From 319795e9b487100595cbadad7370380e7bd953b7 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Tue, 21 Dec 2021 12:21:33 +0100 Subject: [PATCH 001/234] feat: a library of types for communicating with the ICP ledger (#168) This change introduces a new library, ic-ledger-types, which defines types for communicating with the ICP ledger canister from Rust canisters: * `Address` and related types define methods to compute ledger addresses from principals and subaccounts. * `AccountBalanceArgs` and `TransferArgs` define structures that should be used for sending requests to the ledger canister. * MAINNET_LEDGER_CANISTER_ID defines the principal of the ledger canister on the mainnet. --- Cargo.toml | 1 + src/ic-ledger-types/CHANGELOG.md | 9 + src/ic-ledger-types/Cargo.toml | 22 +++ src/ic-ledger-types/LICENSE | 201 ++++++++++++++++++++ src/ic-ledger-types/README.md | 3 + src/ic-ledger-types/src/lib.rs | 303 +++++++++++++++++++++++++++++++ 6 files changed, 539 insertions(+) create mode 100644 src/ic-ledger-types/CHANGELOG.md create mode 100644 src/ic-ledger-types/Cargo.toml create mode 100644 src/ic-ledger-types/LICENSE create mode 100644 src/ic-ledger-types/README.md create mode 100644 src/ic-ledger-types/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index a58c97519..402de5aed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,6 @@ members = [ "src/ic-cdk-macros", "src/ic-cdk-optimizer", "src/ic-certified-map", + "src/ic-ledger-types", ] diff --git a/src/ic-ledger-types/CHANGELOG.md b/src/ic-ledger-types/CHANGELOG.md new file mode 100644 index 000000000..da149632c --- /dev/null +++ b/src/ic-ledger-types/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.0] - 2021-11-11 +### Added +* Initial release of the library. diff --git a/src/ic-ledger-types/Cargo.toml b/src/ic-ledger-types/Cargo.toml new file mode 100644 index 000000000..31aed2351 --- /dev/null +++ b/src/ic-ledger-types/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "ic-ledger-types" +version = "0.1.0" +edition = "2018" +authors = ["DFINITY Stiftung "] +description = "Types for interacting with the ICP ledger canister." +homepage = "https://docs.rs/ic-ledger" +documentation = "https://docs.rs/ic-ledger" +license = "Apache-2.0" +readme = "README.md" +keywords = ["internet-computer", "ledger"] +include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ic-cdk = { path = "../ic-cdk", version = "0.3" } +crc32fast = "1.2.0" +hex = "0.4" +serde = "1" +sha2 = "0.9" + diff --git a/src/ic-ledger-types/LICENSE b/src/ic-ledger-types/LICENSE new file mode 100644 index 000000000..b27ba1fe8 --- /dev/null +++ b/src/ic-ledger-types/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 DFINITY LLC. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/ic-ledger-types/README.md b/src/ic-ledger-types/README.md new file mode 100644 index 000000000..f748b7526 --- /dev/null +++ b/src/ic-ledger-types/README.md @@ -0,0 +1,3 @@ +# ICP Ledger types + +A library of types to communicate with the ICP ledger canister. diff --git a/src/ic-ledger-types/src/lib.rs b/src/ic-ledger-types/src/lib.rs new file mode 100644 index 000000000..24b64e14c --- /dev/null +++ b/src/ic-ledger-types/src/lib.rs @@ -0,0 +1,303 @@ +use ic_cdk::api::call::CallResult; +use ic_cdk::export::candid::{CandidType, Principal}; +use serde::{Deserialize, Serialize}; +use sha2::Digest; +use std::fmt; +use std::ops::{Add, AddAssign, Sub, SubAssign}; + +/// The subaccont that is used by default. +pub const DEFAULT_SUBACCOUNT: Subaccount = Subaccount([0; 32]); + +/// The default fee for ledger transactions. +pub const DEFAULT_FEE: Tokens = Tokens { e8s: 10_000 }; + +/// Id of the ledger canister on the IC. +pub const MAINNET_LEDGER_CANISTER_ID: Principal = + Principal::from_slice(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01]); + +/// Number of nanoseconds from the UNIX epoch in UTC timezone. +#[derive( + CandidType, Serialize, Deserialize, Clone, Copy, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, +)] +pub struct Timestamp { + pub timestamp_nanos: u64, +} + +/// A type for representing amounts of Tokens. +/// +/// # Panics +/// +/// * Arithmetics (addition, subtraction) on the Tokens type panics if the underlying type +/// overflows. +#[derive( + CandidType, Serialize, Deserialize, Clone, Copy, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, +)] +pub struct Tokens { + e8s: u64, +} + +impl Tokens { + /// The maximum number of Tokens we can hold on a single account. + pub const MAX: Self = Tokens { e8s: u64::MAX }; + /// Zero Tokens. + pub const ZERO: Self = Tokens { e8s: 0 }; + /// How many times can Tokenss be divided + pub const SUBDIVIDABLE_BY: u64 = 100_000_000; + + /// Constructs an amount of Tokens from the number of 10^-8 Tokens. + pub fn from_e8s(e8s: u64) -> Self { + Self { e8s } + } + + /// Returns the number of 10^-8 Tokens in this amount. + pub fn e8s(&self) -> u64 { + self.e8s + } +} + +impl Add for Tokens { + type Output = Self; + + fn add(self, other: Self) -> Self { + let e8s = self.e8s.checked_add(other.e8s).unwrap_or_else(|| { + panic!( + "Add Tokens {} + {} failed because the underlying u64 overflowed", + self.e8s, other.e8s + ) + }); + Self { e8s } + } +} + +impl AddAssign for Tokens { + fn add_assign(&mut self, other: Self) { + *self = *self + other; + } +} + +impl Sub for Tokens { + type Output = Self; + fn sub(self, other: Self) -> Self { + let e8s = self.e8s.checked_sub(other.e8s).unwrap_or_else(|| { + panic!( + "Subtracting Tokens {} - {} failed because the underlying u64 underflowed", + self.e8s, other.e8s + ) + }); + Self { e8s } + } +} + +impl SubAssign for Tokens { + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } +} + +impl fmt::Display for Tokens { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}.{:08}", + self.e8s / Tokens::SUBDIVIDABLE_BY, + self.e8s % Tokens::SUBDIVIDABLE_BY + ) + } +} + +/// Subaccount is an arbitrary 32-byte byte array. +/// Ledger uses subaccounts to compute account address, which enables one +/// principal to control multiple ledger accounts. +#[derive( + CandidType, Serialize, Deserialize, Clone, Copy, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, +)] +pub struct Subaccount(pub [u8; 32]); + +/// AccountIdentifier is a 32-byte array. +/// The first 4 bytes is big-endian encoding of a CRC32 checksum of the last 28 bytes. +#[derive( + CandidType, Serialize, Deserialize, Clone, Copy, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, +)] +pub struct AccountIdentifier([u8; 32]); + +impl AccountIdentifier { + pub fn new(owner: &Principal, subaccount: &Subaccount) -> Self { + let mut hasher = sha2::Sha224::new(); + hasher.update(b"\x0Aaccount-id"); + hasher.update(owner.as_slice()); + hasher.update(&subaccount.0[..]); + let hash: [u8; 28] = hasher.finalize().into(); + + let mut hasher = crc32fast::Hasher::new(); + hasher.update(&hash); + let crc32_bytes = hasher.finalize().to_be_bytes(); + + let mut result = [0u8; 32]; + result[0..4].copy_from_slice(&crc32_bytes[..]); + result[4..32].copy_from_slice(hash.as_ref()); + Self(result) + } +} + +impl AsRef<[u8]> for AccountIdentifier { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl fmt::Display for AccountIdentifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", hex::encode(self.as_ref())) + } +} + +/// Arguments for the `account_balance` call. +#[derive(CandidType, Serialize, Deserialize, Clone, Debug)] +pub struct AccountBalanceArgs { + pub account: AccountIdentifier, +} + +/// An arbitrary number associated with a transaction. +/// The caller can set it in a `transfer` call as a correlation identifier. +#[derive( + CandidType, Serialize, Deserialize, Clone, Copy, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, +)] +pub struct Memo(pub u64); + +/// Arguments for the `transfer` call. +#[derive(CandidType, Serialize, Deserialize, Clone, Debug)] +pub struct TransferArgs { + pub memo: Memo, + pub amount: Tokens, + pub fee: Tokens, + pub from_subaccount: Option, + pub to: AccountIdentifier, + pub created_at_time: Option, +} + +/// The sequence number of a block in the Tokens ledger blockchain. +pub type BlockIndex = u64; + +/// Result of the `transfer` call. +pub type TransferResult = Result; + +/// Error of the `transfer` call. +#[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub enum TransferError { + BadFee { expected_fee: Tokens }, + InsufficientFunds { balance: Tokens }, + TxTooOld { allowed_window_nanos: u64 }, + TxCreatedInFuture, + TxDuplicate { duplicate_of: BlockIndex }, +} + +impl fmt::Display for TransferError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::BadFee { expected_fee } => { + write!(f, "transaction fee should be {}", expected_fee) + } + Self::InsufficientFunds { balance } => { + write!( + f, + "the debit account doesn't have enough funds to complete the transaction, current balance: {}", + balance + ) + } + Self::TxTooOld { + allowed_window_nanos, + } => write!( + f, + "transaction is older than {} seconds", + allowed_window_nanos / 1_000_000_000 + ), + Self::TxCreatedInFuture => write!(f, "transaction's created_at_time is in future"), + Self::TxDuplicate { duplicate_of } => write!( + f, + "transaction is a duplicate of another transaction in block {}", + duplicate_of + ), + } + } +} + +/// Calls the "account_balance" method on the specified canister. +/// +/// # Example +/// ```no_run +/// use ic_cdk::api::{caller, call::call}; +/// use ic_ledger_types::{AccountIdentifier, AccountBalanceArgs, Tokens, DEFAULT_SUBACCOUNT, MAINNET_LEDGER_CANISTER_ID, account_balance}; +/// +/// async fn check_callers_balance() -> Tokens { +/// account_balance( +/// MAINNET_LEDGER_CANISTER_ID, +/// AccountBalanceArgs { +/// account: AccountIdentifier::new(&caller(), &DEFAULT_SUBACCOUNT) +/// } +/// ).await.expect("call to ledger failed") +/// } +/// ``` +pub async fn account_balance( + ledger_canister_id: Principal, + args: AccountBalanceArgs, +) -> CallResult { + let (icp,) = ic_cdk::call(ledger_canister_id, "account_balance", (args,)).await?; + Ok(icp) +} + +/// Calls the "transfer" method on the specified canister. +/// # Example +/// ```no_run +/// use ic_cdk::api::{caller, call::call}; +/// use ic_ledger_types::{AccountIdentifier, BlockIndex, Memo, TransferArgs, Tokens, DEFAULT_SUBACCOUNT, DEFAULT_FEE, MAINNET_LEDGER_CANISTER_ID, transfer}; +/// +/// async fn transfer_to_caller() -> BlockIndex { +/// transfer( +/// MAINNET_LEDGER_CANISTER_ID, +/// TransferArgs { +/// memo: Memo(0), +/// amount: Tokens::from_e8s(1_000_000), +/// fee: DEFAULT_FEE, +/// from_subaccount: None, +/// to: AccountIdentifier::new(&caller(), &DEFAULT_SUBACCOUNT), +/// created_at_time: None, +/// } +/// ).await.expect("call to ledger failed").expect("transfer failed") +/// } +/// ``` +pub async fn transfer( + ledger_canister_id: Principal, + args: TransferArgs, +) -> CallResult { + let (result,) = ic_cdk::call(ledger_canister_id, "transfer", (args,)).await?; + Ok(result) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::string::ToString; + + #[test] + fn test_account_id() { + assert_eq!( + "bdc4ee05d42cd0669786899f256c8fd7217fa71177bd1fa7b9534f568680a938".to_string(), + AccountIdentifier::new( + &Principal::from_text( + "iooej-vlrze-c5tme-tn7qt-vqe7z-7bsj5-ebxlc-hlzgs-lueo3-3yast-pae" + ) + .unwrap(), + &DEFAULT_SUBACCOUNT + ) + .to_string() + ); + } + + #[test] + fn test_ledger_canister_id() { + assert_eq!( + MAINNET_LEDGER_CANISTER_ID, + Principal::from_text("ryjl3-tyaaa-aaaaa-aaaba-cai").unwrap() + ); + } +} From f431c8d5fce4e603c30e24c89182fcca2de76a60 Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Wed, 12 Jan 2022 17:57:56 +0000 Subject: [PATCH 002/234] feat: mark suitable functions as const (#183) --- src/ic-ledger-types/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ic-ledger-types/src/lib.rs b/src/ic-ledger-types/src/lib.rs index 24b64e14c..384eaa9ee 100644 --- a/src/ic-ledger-types/src/lib.rs +++ b/src/ic-ledger-types/src/lib.rs @@ -45,12 +45,12 @@ impl Tokens { pub const SUBDIVIDABLE_BY: u64 = 100_000_000; /// Constructs an amount of Tokens from the number of 10^-8 Tokens. - pub fn from_e8s(e8s: u64) -> Self { + pub const fn from_e8s(e8s: u64) -> Self { Self { e8s } } /// Returns the number of 10^-8 Tokens in this amount. - pub fn e8s(&self) -> u64 { + pub const fn e8s(&self) -> u64 { self.e8s } } From bb76b2b8bd8f5ed2355149cb926895e32cb885e8 Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Wed, 12 Jan 2022 17:58:48 +0000 Subject: [PATCH 003/234] feat: expose constants for the governance and cycles minting canister Ids (#184) Co-authored-by: Linwei Shang --- src/ic-ledger-types/src/lib.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/ic-ledger-types/src/lib.rs b/src/ic-ledger-types/src/lib.rs index 384eaa9ee..2b7ac7abc 100644 --- a/src/ic-ledger-types/src/lib.rs +++ b/src/ic-ledger-types/src/lib.rs @@ -15,6 +15,14 @@ pub const DEFAULT_FEE: Tokens = Tokens { e8s: 10_000 }; pub const MAINNET_LEDGER_CANISTER_ID: Principal = Principal::from_slice(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01]); +/// Id of the governance canister on the IC. +pub const MAINNET_GOVERNANCE_CANISTER_ID: Principal = + Principal::from_slice(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01]); + +/// Id of the cycles minting canister on the IC. +pub const MAINNET_CYCLES_MINTING_CANISTER_ID: Principal = + Principal::from_slice(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01]); + /// Number of nanoseconds from the UNIX epoch in UTC timezone. #[derive( CandidType, Serialize, Deserialize, Clone, Copy, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, @@ -300,4 +308,20 @@ mod tests { Principal::from_text("ryjl3-tyaaa-aaaaa-aaaba-cai").unwrap() ); } + + #[test] + fn test_governance_canister_id() { + assert_eq!( + MAINNET_GOVERNANCE_CANISTER_ID, + Principal::from_text("rrkah-fqaaa-aaaaa-aaaaq-cai").unwrap() + ); + } + + #[test] + fn test_cycles_minting_canister_id() { + assert_eq!( + MAINNET_CYCLES_MINTING_CANISTER_ID, + Principal::from_text("rkp4c-7iaaa-aaaaa-aaaca-cai").unwrap() + ); + } } From 4b969f5a093ff66bb75e950f62a57e9f5defa77c Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 13 Jan 2022 11:50:03 -0800 Subject: [PATCH 004/234] chore: use rust 1.55.0 in CI (#185) * Use rust 1.55.0 in CI * Fix clippy * Update expected error messages --- .github/workflows/examples.yml | 2 +- .github/workflows/fmt.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 6 +++--- .../compile_fail/lifecycle_functions_only_once.stderr | 10 +++++----- .../lifecycle_functions_should_have_no_return.stderr | 10 +++++----- src/ic-certified-map/src/rbtree.rs | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index d573fe76d..9cf9abad4 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -16,7 +16,7 @@ jobs: include: - build: linux-stable os: ubuntu-latest - rust: 1.52.1 + rust: 1.55.0 dfx: 0.8.1 steps: diff --git a/.github/workflows/fmt.yml b/.github/workflows/fmt.yml index 98ed25adc..6f3d82770 100644 --- a/.github/workflows/fmt.yml +++ b/.github/workflows/fmt.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust: [ 1.52.1 ] + rust: [ 1.55.0 ] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 63aae40fe..1ab9173d8 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust: [ 1.52.1 ] + rust: [ 1.55.0 ] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ff2d45bd0..a40194db1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,13 +15,13 @@ jobs: include: - build: linux-stable os: ubuntu-latest - rust: 1.52.1 + rust: 1.55.0 - build: macos-stable os: macos-latest - rust: 1.52.1 + rust: 1.55.0 - build: windows-stable os: windows-latest - rust: 1.52.1 + rust: 1.55.0 steps: - uses: actions/checkout@v2 diff --git a/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_only_once.stderr b/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_only_once.stderr index 6350261d8..272f3da51 100644 --- a/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_only_once.stderr +++ b/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_only_once.stderr @@ -4,7 +4,7 @@ error: [init] function already declared. 6 | #[init] | ^^^^^^^ | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) error: [pre_upgrade] function already declared. --> tests/compile_fail/lifecycle_functions_only_once.rs:12:1 @@ -12,7 +12,7 @@ error: [pre_upgrade] function already declared. 12 | #[pre_upgrade] | ^^^^^^^^^^^^^^ | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `pre_upgrade` (in Nightly builds, run with -Z macro-backtrace for more info) error: [post_upgrade] function already declared. --> tests/compile_fail/lifecycle_functions_only_once.rs:18:1 @@ -20,7 +20,7 @@ error: [post_upgrade] function already declared. 18 | #[post_upgrade] | ^^^^^^^^^^^^^^^ | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `post_upgrade` (in Nightly builds, run with -Z macro-backtrace for more info) error: [heartbeat] function already declared. --> tests/compile_fail/lifecycle_functions_only_once.rs:24:1 @@ -28,7 +28,7 @@ error: [heartbeat] function already declared. 24 | #[heartbeat] | ^^^^^^^^^^^^ | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `heartbeat` (in Nightly builds, run with -Z macro-backtrace for more info) error: [inspect_message] function already declared. --> tests/compile_fail/lifecycle_functions_only_once.rs:30:1 @@ -36,4 +36,4 @@ error: [inspect_message] function already declared. 30 | #[inspect_message] | ^^^^^^^^^^^^^^^^^^ | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `inspect_message` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_should_have_no_return.stderr b/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_should_have_no_return.stderr index ec3d6b394..e8c3a8a1d 100644 --- a/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_should_have_no_return.stderr +++ b/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_should_have_no_return.stderr @@ -4,7 +4,7 @@ error: #[init] function cannot have a return value. 3 | #[init] | ^^^^^^^ | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) error: #[pre_upgrade] function cannot have a return value. --> tests/compile_fail/lifecycle_functions_should_have_no_return.rs:6:1 @@ -12,7 +12,7 @@ error: #[pre_upgrade] function cannot have a return value. 6 | #[pre_upgrade] | ^^^^^^^^^^^^^^ | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `pre_upgrade` (in Nightly builds, run with -Z macro-backtrace for more info) error: #[post_upgrade] function cannot have a return value. --> tests/compile_fail/lifecycle_functions_should_have_no_return.rs:9:1 @@ -20,7 +20,7 @@ error: #[post_upgrade] function cannot have a return value. 9 | #[post_upgrade] | ^^^^^^^^^^^^^^^ | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `post_upgrade` (in Nightly builds, run with -Z macro-backtrace for more info) error: #[heartbeat] function cannot have a return value. --> tests/compile_fail/lifecycle_functions_should_have_no_return.rs:12:1 @@ -28,7 +28,7 @@ error: #[heartbeat] function cannot have a return value. 12 | #[heartbeat] | ^^^^^^^^^^^^ | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `heartbeat` (in Nightly builds, run with -Z macro-backtrace for more info) error: #[inspect_message] function cannot have a return value. --> tests/compile_fail/lifecycle_functions_should_have_no_return.rs:15:1 @@ -36,4 +36,4 @@ error: #[inspect_message] function cannot have a return value. 15 | #[inspect_message] | ^^^^^^^^^^^^^^^^^^ | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `inspect_message` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/ic-certified-map/src/rbtree.rs b/src/ic-certified-map/src/rbtree.rs index 8629b4a0b..35549fe7c 100644 --- a/src/ic-certified-map/src/rbtree.rs +++ b/src/ic-certified-map/src/rbtree.rs @@ -482,7 +482,7 @@ impl, V: AsHashTree + 'static> RbTree { }, Some(n) => Iter { visit: Visit::Pre, - parents: vec![&n], + parents: vec![n], }, } } From e55f6a5e60dc37d43851727f1288e9e1293482ed Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 13 Jan 2022 12:15:14 -0800 Subject: [PATCH 005/234] chore: release ic-certified-map v0.3.0 (#186) * Release ic-certified-map v0.3.0 * Fix date --- src/ic-certified-map/CHANGELOG.md | 7 +++++-- src/ic-certified-map/Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ic-certified-map/CHANGELOG.md b/src/ic-certified-map/CHANGELOG.md index bac23f255..48a02aede 100644 --- a/src/ic-certified-map/CHANGELOG.md +++ b/src/ic-certified-map/CHANGELOG.md @@ -4,12 +4,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.3.0] - 2022-01-13 ### Added -- `RbTree::value_range()` method to get a witness for a range of keys with values. - `RbTree::iter()` method. - impls of `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord`, `FromIterator`, and `Debug` for `RbTree`. +## [0.2.0] - 2021-09-16 +### Added +- `RbTree::value_range()` method to get a witness for a range of keys with values. + ### Changed - RbTree::key_range() method returns tighter key bounds which reduces the size of witnesses. - Updated the version of candid from `0.6.19` to `0.7.1` ([#72](https://github.com/dfinity/cdk-rs/pull/72)). diff --git a/src/ic-certified-map/Cargo.toml b/src/ic-certified-map/Cargo.toml index 71a58391c..ba2449265 100644 --- a/src/ic-certified-map/Cargo.toml +++ b/src/ic-certified-map/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-certified-map" -version = "0.2.0" +version = "0.3.0" edition = "2018" authors = ["DFINITY Stiftung "] description = "Merkleized map data structure." From 6c0aa52bc070c4d31a2ca571799f8a11ceb2d6de Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Mon, 24 Jan 2022 12:07:05 +0100 Subject: [PATCH 006/234] refactor: deprecate block_on in favour of the new spawn function (#189) * refactor: deprecate block_on in favour of the new spawn function This PR provides the functionality of `block_on` under a better name, `spawn`. The `block_on` function is marked as deprecated in favour of `spawn`. Closes #7 and #174. --- src/ic-cdk-macros/src/export.rs | 16 ++++++++-------- src/ic-cdk/src/futures.rs | 2 +- src/ic-cdk/src/lib.rs | 14 ++++++++++++-- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index 7e0857a74..4412cd40b 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -193,7 +193,7 @@ fn dfn_macro( #guard - ic_cdk::block_on(async { + ic_cdk::spawn(async { #arg_decode let result = #function_call; #return_encode @@ -306,7 +306,7 @@ mod test { #[export_name = "canister_query query"] fn #fn_name() { ic_cdk::setup(); - ic_cdk::block_on(async { + ic_cdk::spawn(async { let () = ic_cdk::api::call::arg_data(); let result = query(); ic_cdk::api::call::reply(()) @@ -343,7 +343,7 @@ mod test { #[export_name = "canister_query query"] fn #fn_name() { ic_cdk::setup(); - ic_cdk::block_on(async { + ic_cdk::spawn(async { let () = ic_cdk::api::call::arg_data(); let result = query(); ic_cdk::api::call::reply((result,)) @@ -380,7 +380,7 @@ mod test { #[export_name = "canister_query query"] fn #fn_name() { ic_cdk::setup(); - ic_cdk::block_on(async { + ic_cdk::spawn(async { let () = ic_cdk::api::call::arg_data(); let result = query(); ic_cdk::api::call::reply(result) @@ -417,7 +417,7 @@ mod test { #[export_name = "canister_query query"] fn #fn_name() { ic_cdk::setup(); - ic_cdk::block_on(async { + ic_cdk::spawn(async { let (a, ) = ic_cdk::api::call::arg_data(); let result = query(a); ic_cdk::api::call::reply(()) @@ -454,7 +454,7 @@ mod test { #[export_name = "canister_query query"] fn #fn_name() { ic_cdk::setup(); - ic_cdk::block_on(async { + ic_cdk::spawn(async { let (a, b, ) = ic_cdk::api::call::arg_data(); let result = query(a, b); ic_cdk::api::call::reply(()) @@ -491,7 +491,7 @@ mod test { #[export_name = "canister_query query"] fn #fn_name() { ic_cdk::setup(); - ic_cdk::block_on(async { + ic_cdk::spawn(async { let (a, b, ) = ic_cdk::api::call::arg_data(); let result = query(a, b); ic_cdk::api::call::reply((result,)) @@ -528,7 +528,7 @@ mod test { #[export_name = "canister_query custom_query"] fn #fn_name() { ic_cdk::setup(); - ic_cdk::block_on(async { + ic_cdk::spawn(async { let () = ic_cdk::api::call::arg_data(); let result = query(); ic_cdk::api::call::reply(()) diff --git a/src/ic-cdk/src/futures.rs b/src/ic-cdk/src/futures.rs index a231866e0..b145c491c 100644 --- a/src/ic-cdk/src/futures.rs +++ b/src/ic-cdk/src/futures.rs @@ -18,7 +18,7 @@ use std::task::Context; /// API requires us to pass one thin pointer, while a a pointer to a `dyn Trait` /// can only be fat. So we create one additional thin pointer, pointing to the /// fat pointer and pass it instead. -pub fn block_on>(future: F) { +pub fn spawn>(future: F) { let future_ptr = Box::into_raw(Box::new(future)); let future_ptr_ptr: *mut *mut dyn Future = Box::into_raw(Box::new(future_ptr)); let mut pinned_future = unsafe { Pin::new_unchecked(&mut *future_ptr) }; diff --git a/src/ic-cdk/src/lib.rs b/src/ic-cdk/src/lib.rs index 5b034b967..22407aea0 100644 --- a/src/ic-cdk/src/lib.rs +++ b/src/ic-cdk/src/lib.rs @@ -34,9 +34,19 @@ pub fn setup() { printer::hook() } -/// Block on a promise in a WASM-friendly way (no multithreading!). +/// See documentation for [spawn]. +#[deprecated( + since = "0.3.4", + note = "Use the spawn() function instead, it does the same thing but is more appropriately named." +)] pub fn block_on>(future: F) { - futures::block_on(future); + futures::spawn(future); +} + +/// Spawn an asynchronous task that drives the provided future to +/// completion. +pub fn spawn>(future: F) { + futures::spawn(future); } /// Format and then print the formatted message From 40641563c6dde794e0ae9fff396dd179e95998ab Mon Sep 17 00:00:00 2001 From: Dimitris Sarlis Date: Wed, 26 Jan 2022 17:36:20 +0100 Subject: [PATCH 007/234] chore: Remove default features (#190) * Remove default features * Add explicit dependency on candid * Add more explicit candid dependencies * More explicit candid dependencies * Bump up version to v0.4.0 Co-authored-by: Linwei Shang --- README.md | 5 +++-- docs/modules/rust-guide/pages/rust-profile.adoc | 4 ++-- docs/modules/rust-guide/pages/rust-quickstart.adoc | 4 ++-- examples/asset_storage/src/asset_storage_rs/Cargo.toml | 4 ++-- examples/chess/src/chess_rs/Cargo.toml | 5 +++-- examples/counter/src/counter_rs/Cargo.toml | 5 +++-- examples/counter/src/inter2_rs/Cargo.toml | 5 +++-- examples/counter/src/inter_rs/Cargo.toml | 5 +++-- examples/print/src/print_rs/Cargo.toml | 4 ++-- examples/profile/src/profile_inter_rs/Cargo.toml | 5 +++-- examples/profile/src/profile_rs/Cargo.toml | 5 +++-- src/ic-cdk-macros/Cargo.toml | 8 ++------ src/ic-cdk/Cargo.toml | 4 +--- src/ic-ledger-types/Cargo.toml | 3 ++- 14 files changed, 34 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 980f434a8..f9d688d8c 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,9 @@ In Cargo.toml: crate-type = ["cdylib"] [dependencies] -ic-cdk = "0.3" -ic-cdk-macros = "0.3" +candid = "0.7.4" # this is required if you want to use the `#[import]` macro +ic-cdk = "0.4" +ic-cdk-macros = "0.4" ``` Then in your rust source code: diff --git a/docs/modules/rust-guide/pages/rust-profile.adoc b/docs/modules/rust-guide/pages/rust-profile.adoc index fca55d5a7..68615061d 100644 --- a/docs/modules/rust-guide/pages/rust-profile.adoc +++ b/docs/modules/rust-guide/pages/rust-profile.adoc @@ -101,8 +101,8 @@ To replace the default program: [source,toml] ---- [dependencies] -ic-cdk = "0.3" -ic-cdk-macros = "0.3" +ic-cdk = "0.4" +ic-cdk-macros = "0.4" serde = "1.0" ---- + diff --git a/docs/modules/rust-guide/pages/rust-quickstart.adoc b/docs/modules/rust-guide/pages/rust-quickstart.adoc index 4f0321198..dd9d06c83 100644 --- a/docs/modules/rust-guide/pages/rust-quickstart.adoc +++ b/docs/modules/rust-guide/pages/rust-quickstart.adoc @@ -136,8 +136,8 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = "0.3" -ic-cdk-macros = "0.3" +ic-cdk = "0.4" +ic-cdk-macros = "0.4" ---- Notice the `+crate-type = ["cdylib"]+` line which is necessary to compile this rust program into WebAssembly module. diff --git a/examples/asset_storage/src/asset_storage_rs/Cargo.toml b/examples/asset_storage/src/asset_storage_rs/Cargo.toml index 4526dd80f..87292fb51 100644 --- a/examples/asset_storage/src/asset_storage_rs/Cargo.toml +++ b/examples/asset_storage/src/asset_storage_rs/Cargo.toml @@ -11,5 +11,5 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.3" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.3" } +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } diff --git a/examples/chess/src/chess_rs/Cargo.toml b/examples/chess/src/chess_rs/Cargo.toml index 8a52c3398..3a3173b9c 100644 --- a/examples/chess/src/chess_rs/Cargo.toml +++ b/examples/chess/src/chess_rs/Cargo.toml @@ -11,7 +11,8 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.3" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.3" } +candid = "0.7.4" +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } serde = "1.0.111" pleco = "0.5.0" diff --git a/examples/counter/src/counter_rs/Cargo.toml b/examples/counter/src/counter_rs/Cargo.toml index 55eda1d3d..a8c305178 100644 --- a/examples/counter/src/counter_rs/Cargo.toml +++ b/examples/counter/src/counter_rs/Cargo.toml @@ -11,6 +11,7 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.3" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.3" } +candid = "0.7.4" +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } lazy_static = "1.4.0" diff --git a/examples/counter/src/inter2_rs/Cargo.toml b/examples/counter/src/inter2_rs/Cargo.toml index 9222daf2f..5d722b1a6 100644 --- a/examples/counter/src/inter2_rs/Cargo.toml +++ b/examples/counter/src/inter2_rs/Cargo.toml @@ -11,5 +11,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.3" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.3" } +candid = "0.7.4" +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } diff --git a/examples/counter/src/inter_rs/Cargo.toml b/examples/counter/src/inter_rs/Cargo.toml index 12fe2a4d3..1e4940689 100644 --- a/examples/counter/src/inter_rs/Cargo.toml +++ b/examples/counter/src/inter_rs/Cargo.toml @@ -11,5 +11,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.3" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.3" } +candid = "0.7.4" +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } diff --git a/examples/print/src/print_rs/Cargo.toml b/examples/print/src/print_rs/Cargo.toml index 677eacfef..0ed00ec57 100644 --- a/examples/print/src/print_rs/Cargo.toml +++ b/examples/print/src/print_rs/Cargo.toml @@ -11,6 +11,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.3" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.3" } +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } diff --git a/examples/profile/src/profile_inter_rs/Cargo.toml b/examples/profile/src/profile_inter_rs/Cargo.toml index 843faa217..a0036307b 100644 --- a/examples/profile/src/profile_inter_rs/Cargo.toml +++ b/examples/profile/src/profile_inter_rs/Cargo.toml @@ -11,5 +11,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.3" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.3" } +candid = "0.7.4" +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } diff --git a/examples/profile/src/profile_rs/Cargo.toml b/examples/profile/src/profile_rs/Cargo.toml index 504a2f4e2..33d1af5cf 100644 --- a/examples/profile/src/profile_rs/Cargo.toml +++ b/examples/profile/src/profile_rs/Cargo.toml @@ -11,6 +11,7 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.3" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.3" } +candid = "0.7.4" +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } serde = "1.0.111" diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index a20a24e3a..c387fbd1f 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.3.3" +version = "0.4.0" authors = ["DFINITY Stiftung "] edition = "2018" description = "Canister Developer Kit macros." @@ -17,7 +17,7 @@ proc-macro = true [dependencies] candid = "0.7.4" -ic-cdk = { path = "../ic-cdk", version = "0.3" } +ic-cdk = { path = "../ic-cdk", version = "0.4" } syn = { version = "1.0.58", features = ["fold", "full"] } quote = "1.0" proc-macro2 = "1.0" @@ -26,7 +26,3 @@ serde = "1.0.111" [dev-dependencies] trybuild = "1.0" - -[features] -default = ["redirect"] -redirect = ["candid/cdk"] diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 03b8c5f69..8aa2a4df6 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.3.3" +version = "0.4.0" authors = ["DFINITY Stiftung "] edition = "2018" description = "Canister Developer Kit for the Internet Computer." @@ -18,6 +18,4 @@ cfg-if = "1.0.0" serde = "1.0.110" [features] -default = ["redirect"] -redirect = ["candid/cdk"] experimental = [] diff --git a/src/ic-ledger-types/Cargo.toml b/src/ic-ledger-types/Cargo.toml index 31aed2351..188ad199d 100644 --- a/src/ic-ledger-types/Cargo.toml +++ b/src/ic-ledger-types/Cargo.toml @@ -14,7 +14,8 @@ include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ic-cdk = { path = "../ic-cdk", version = "0.3" } +ic-cdk = { path = "../ic-cdk", version = "0.4" } +candid = "0.7.4" crc32fast = "1.2.0" hex = "0.4" serde = "1" From 8ff016f09268a72e2776feb5686718122367400f Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Thu, 27 Jan 2022 21:35:22 +0100 Subject: [PATCH 008/234] fix: update broken links in Cargo.toml (#191) This change updates the `homepage` and `documentation` fields in the `Cargo.toml` file which are currently pointing to a non-existing page. --- src/ic-ledger-types/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ic-ledger-types/Cargo.toml b/src/ic-ledger-types/Cargo.toml index 188ad199d..cafce9e7e 100644 --- a/src/ic-ledger-types/Cargo.toml +++ b/src/ic-ledger-types/Cargo.toml @@ -4,8 +4,8 @@ version = "0.1.0" edition = "2018" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." -homepage = "https://docs.rs/ic-ledger" -documentation = "https://docs.rs/ic-ledger" +homepage = "https://docs.rs/ic-ledger-types" +documentation = "https://docs.rs/ic-ledger-types" license = "Apache-2.0" readme = "README.md" keywords = ["internet-computer", "ledger"] From da460947beb08f051d60e10a3c3c21198b3a1c0d Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Wed, 2 Feb 2022 16:35:47 -0800 Subject: [PATCH 009/234] feat: Add ic-certified-assets crate for serving certified assets from Rust canisters. (#192) * Update to release version of certified-map. Signed-off-by: John Plevyak * Import updates from the dfinity/certified-assets. Signed-off-by: John Plevyak * Use relative dependencies in the same repo * Update comments. Signed-off-by: John Plevyak Co-authored-by: Linwei Shang --- Cargo.toml | 1 + src/ic-certified-assets/Cargo.toml | 19 + src/ic-certified-assets/LICENSE | 201 +++++ src/ic-certified-assets/README.md | 54 ++ src/ic-certified-assets/src/lib.rs | 1010 +++++++++++++++++++++++ src/ic-certified-assets/src/rc_bytes.rs | 53 ++ 6 files changed, 1338 insertions(+) create mode 100644 src/ic-certified-assets/Cargo.toml create mode 100644 src/ic-certified-assets/LICENSE create mode 100644 src/ic-certified-assets/README.md create mode 100644 src/ic-certified-assets/src/lib.rs create mode 100644 src/ic-certified-assets/src/rc_bytes.rs diff --git a/Cargo.toml b/Cargo.toml index 402de5aed..dad10f75e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "src/ic-cdk", "src/ic-cdk-macros", "src/ic-cdk-optimizer", + "src/ic-certified-assets", "src/ic-certified-map", "src/ic-ledger-types", ] diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml new file mode 100644 index 000000000..3af44752b --- /dev/null +++ b/src/ic-certified-assets/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "ic-certified-assets" +version = "0.1.0" +authors = ["DFINITY Stiftung "] +edition = "2018" + +[dependencies] +base64 = "0.13" +candid = "0.7.10" +hex = "0.4.3" +ic-cdk = { path = "../ic-cdk", version = "0.4" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.4" } +ic-types = "0.3.0" +ic-certified-map = { path = "../ic-certified-map", version = "0.3" } +num-traits = "0.2.14" +serde = "1" +serde_bytes = "0.11" +serde_cbor = "0.11" +sha2 = "0.9.1" diff --git a/src/ic-certified-assets/LICENSE b/src/ic-certified-assets/LICENSE new file mode 100644 index 000000000..b27ba1fe8 --- /dev/null +++ b/src/ic-certified-assets/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 DFINITY LLC. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/ic-certified-assets/README.md b/src/ic-certified-assets/README.md new file mode 100644 index 000000000..5ca0cdc5b --- /dev/null +++ b/src/ic-certified-assets/README.md @@ -0,0 +1,54 @@ +# Certified Assets Library + +Rust support for asset certification. + +Certified assets can also be served from any Rust canister by including this library. + +## Adding to a canister + +``` +[dependencies] +ic-certified-assets = "0.1.0" +``` + +The assets are preserved over upgrades by including the corresponding functions in the `init/pre_upgrade/upgrade` +hooks which can be mixed with the other state from the canister: + +``` +#[derive(Clone, Debug, CandidType, Deserialize)] +struct StableState { + my_state: MyState, + assets: crate::assets::StableState, +} + +#[init] +fn init() { + crate::assets::init(); +} + +>>#[pre_upgrade] +fn pre_upgrade() { + let stable_state = STATE.with(|s| StableState { + my_state: s.my_state, + assets: crate::assets::pre_upgrade(), + }); + ic_cdk::storage::stable_save((stable_state,)).expect("failed to save stable state"); +} + +>>#[post_upgrade] +fn post_upgrade() { + let (stable_state,): (StableState,) = + ic_cdk::storage::stable_restore().expect("failed to restore stable state"); + crate::assets::post_upgrade(stable_state.assets); + STATE.with(|s| { + s.my_state = stable_state.my_state; + }; +} +``` + +## Uploading assets + +``` +cd assets +icx-asset --pem ~/.config/dfx/identity/default/identity.pem --replica https://ic0.app sync . +``` diff --git a/src/ic-certified-assets/src/lib.rs b/src/ic-certified-assets/src/lib.rs new file mode 100644 index 000000000..db55151fc --- /dev/null +++ b/src/ic-certified-assets/src/lib.rs @@ -0,0 +1,1010 @@ +mod rc_bytes; + +use crate::rc_bytes::RcBytes; +use ic_cdk::api::{caller, data_certificate, set_certified_data, time, trap}; +use ic_cdk::export::candid::{CandidType, Deserialize, Func, Int, Nat, Principal}; +use ic_cdk_macros::{query, update}; +use ic_certified_map::{AsHashTree, Hash, HashTree, RbTree}; +use num_traits::ToPrimitive; +use serde::Serialize; +use serde_bytes::ByteBuf; +use sha2::Digest; +use std::cell::RefCell; +use std::collections::HashMap; +use std::convert::TryInto; +use std::fmt; + +/// The amount of time a batch is kept alive. Modifying the batch +/// delays the expiry further. +const BATCH_EXPIRY_NANOS: u64 = 300_000_000_000; + +/// The order in which we pick encodings for certification. +const ENCODING_CERTIFICATION_ORDER: &[&str] = &["identity", "gzip", "compress", "deflate", "br"]; + +/// The file to serve if the requested file wasn't found. +const INDEX_FILE: &str = "/index.html"; + +thread_local! { + static STATE: State = State::default(); + static ASSET_HASHES: RefCell = RefCell::new(RbTree::new()); +} + +type AssetHashes = RbTree; + +#[derive(Default)] +struct State { + assets: RefCell>, + + chunks: RefCell>, + next_chunk_id: RefCell, + + batches: RefCell>, + next_batch_id: RefCell, + + authorized: RefCell>, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct StableState { + authorized: Vec, + stable_assets: HashMap, +} + +#[derive(Default, Clone, Debug, CandidType, Deserialize)] +struct AssetEncoding { + modified: Timestamp, + content_chunks: Vec, + total_length: usize, + certified: bool, + sha256: [u8; 32], +} + +#[derive(Default, Clone, Debug, CandidType, Deserialize)] +struct Asset { + content_type: String, + encodings: HashMap, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct EncodedAsset { + content: RcBytes, + content_type: String, + content_encoding: String, + total_length: Nat, + sha256: Option, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct AssetDetails { + key: String, + content_type: String, + encodings: Vec, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct AssetEncodingDetails { + content_encoding: String, + sha256: Option, + length: Nat, + modified: Timestamp, +} + +struct Chunk { + batch_id: BatchId, + content: RcBytes, +} + +struct Batch { + expires_at: Timestamp, +} + +type Timestamp = Int; +type BatchId = Nat; +type ChunkId = Nat; +type Key = String; + +// IDL Types + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct CreateAssetArguments { + key: Key, + content_type: String, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct SetAssetContentArguments { + key: Key, + content_encoding: String, + chunk_ids: Vec, + sha256: Option, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct UnsetAssetContentArguments { + key: Key, + content_encoding: String, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct DeleteAssetArguments { + key: Key, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct ClearArguments {} + +#[derive(Clone, Debug, CandidType, Deserialize)] +enum BatchOperation { + CreateAsset(CreateAssetArguments), + SetAssetContent(SetAssetContentArguments), + UnsetAssetContent(UnsetAssetContentArguments), + DeleteAsset(DeleteAssetArguments), + Clear(ClearArguments), +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct CommitBatchArguments { + batch_id: BatchId, + operations: Vec, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct StoreArg { + key: Key, + content_type: String, + content_encoding: String, + content: ByteBuf, + sha256: Option, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct GetArg { + key: Key, + accept_encodings: Vec, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct GetChunkArg { + key: Key, + content_encoding: String, + index: Nat, + sha256: Option, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct GetChunkResponse { + content: RcBytes, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct CreateBatchResponse { + batch_id: BatchId, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct CreateChunkArg { + batch_id: BatchId, + content: ByteBuf, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct CreateChunkResponse { + chunk_id: ChunkId, +} +// HTTP interface + +type HeaderField = (String, String); + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct HttpRequest { + method: String, + url: String, + headers: Vec<(String, String)>, + body: ByteBuf, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct HttpResponse { + status_code: u16, + headers: Vec, + body: RcBytes, + streaming_strategy: Option, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct StreamingCallbackToken { + key: String, + content_encoding: String, + index: Nat, + // We don't care about the sha, we just want to be backward compatible. + sha256: Option, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +enum StreamingStrategy { + Callback { + callback: Func, + token: StreamingCallbackToken, + }, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +struct StreamingCallbackHttpResponse { + body: RcBytes, + token: Option, +} + +#[update] +fn authorize(other: Principal) { + let caller = caller(); + STATE.with(|s| { + let caller_autorized = s.authorized.borrow().iter().any(|p| *p == caller); + if caller_autorized { + s.authorized.borrow_mut().push(other); + } + }) +} + +#[query] +fn retrieve(key: Key) -> RcBytes { + STATE.with(|s| { + let assets = s.assets.borrow(); + let asset = assets.get(&key).unwrap_or_else(|| trap("asset not found")); + let id_enc = asset + .encodings + .get("identity") + .unwrap_or_else(|| trap("no identity encoding")); + if id_enc.content_chunks.len() > 1 { + trap("Asset too large. Use get() and get_chunk() instead."); + } + id_enc.content_chunks[0].clone() + }) +} + +#[update(guard = "is_authorized")] +fn store(arg: StoreArg) { + STATE.with(move |s| { + let mut assets = s.assets.borrow_mut(); + let asset = assets.entry(arg.key.clone()).or_default(); + asset.content_type = arg.content_type; + + let hash = hash_bytes(&arg.content); + if let Some(provided_hash) = arg.sha256 { + if hash != provided_hash.as_ref() { + trap("sha256 mismatch"); + } + } + + let encoding = asset.encodings.entry(arg.content_encoding).or_default(); + encoding.total_length = arg.content.len(); + encoding.content_chunks = vec![RcBytes::from(arg.content)]; + encoding.modified = Int::from(time() as u64); + encoding.sha256 = hash; + + on_asset_change(&arg.key, asset); + }); +} + +#[update(guard = "is_authorized")] +fn create_batch() -> CreateBatchResponse { + STATE.with(|s| { + let batch_id = s.next_batch_id.borrow().clone(); + *s.next_batch_id.borrow_mut() += 1; + + let now = time() as u64; + + let mut batches = s.batches.borrow_mut(); + batches.insert( + batch_id.clone(), + Batch { + expires_at: Int::from(now + BATCH_EXPIRY_NANOS), + }, + ); + s.chunks.borrow_mut().retain(|_, c| { + batches + .get(&c.batch_id) + .map(|b| b.expires_at > now) + .unwrap_or(false) + }); + batches.retain(|_, b| b.expires_at > now); + + CreateBatchResponse { batch_id } + }) +} + +#[update(guard = "is_authorized")] +fn create_chunk(arg: CreateChunkArg) -> CreateChunkResponse { + STATE.with(|s| { + let mut batches = s.batches.borrow_mut(); + let now = time() as u64; + let mut batch = batches + .get_mut(&arg.batch_id) + .unwrap_or_else(|| trap("batch not found")); + batch.expires_at = Int::from(now + BATCH_EXPIRY_NANOS); + + let chunk_id = s.next_chunk_id.borrow().clone(); + *s.next_chunk_id.borrow_mut() += 1; + + s.chunks.borrow_mut().insert( + chunk_id.clone(), + Chunk { + batch_id: arg.batch_id, + content: RcBytes::from(arg.content), + }, + ); + + CreateChunkResponse { chunk_id } + }) +} + +#[update(guard = "is_authorized")] +fn create_asset(arg: CreateAssetArguments) { + do_create_asset(arg); +} + +#[update(guard = "is_authorized")] +fn set_asset_content(arg: SetAssetContentArguments) { + do_set_asset_content(arg); +} + +#[update(guard = "is_authorized")] +fn unset_asset_content(arg: UnsetAssetContentArguments) { + do_unset_asset_content(arg); +} + +#[update(guard = "is_authorized")] +fn delete_content(arg: DeleteAssetArguments) { + do_delete_asset(arg); +} + +#[update(guard = "is_authorized")] +fn clear() { + do_clear(); +} + +#[update(guard = "is_authorized")] +fn commit_batch(arg: CommitBatchArguments) { + let batch_id = arg.batch_id; + for op in arg.operations { + match op { + BatchOperation::CreateAsset(arg) => do_create_asset(arg), + BatchOperation::SetAssetContent(arg) => do_set_asset_content(arg), + BatchOperation::UnsetAssetContent(arg) => do_unset_asset_content(arg), + BatchOperation::DeleteAsset(arg) => do_delete_asset(arg), + BatchOperation::Clear(_) => do_clear(), + } + } + STATE.with(|s| { + s.batches.borrow_mut().remove(&batch_id); + }) +} + +#[query] +fn get(arg: GetArg) -> EncodedAsset { + STATE.with(|s| { + let assets = s.assets.borrow(); + let asset = assets.get(&arg.key).unwrap_or_else(|| { + trap("asset not found"); + }); + + for enc in arg.accept_encodings.iter() { + if let Some(asset_enc) = asset.encodings.get(enc) { + return EncodedAsset { + content: asset_enc.content_chunks[0].clone(), + content_type: asset.content_type.clone(), + content_encoding: enc.clone(), + total_length: Nat::from(asset_enc.total_length as u64), + sha256: Some(ByteBuf::from(asset_enc.sha256)), + }; + } + } + trap("no such encoding"); + }) +} + +#[query] +fn get_chunk(arg: GetChunkArg) -> GetChunkResponse { + STATE.with(|s| { + let assets = s.assets.borrow(); + let asset = assets + .get(&arg.key) + .unwrap_or_else(|| trap("asset not found")); + + let enc = asset + .encodings + .get(&arg.content_encoding) + .unwrap_or_else(|| trap("no such encoding")); + + if let Some(expected_hash) = arg.sha256 { + if expected_hash != enc.sha256 { + trap("sha256 mismatch") + } + } + if arg.index >= enc.content_chunks.len() { + trap("chunk index out of bounds"); + } + let index: usize = arg.index.0.to_usize().unwrap(); + + GetChunkResponse { + content: enc.content_chunks[index].clone(), + } + }) +} + +#[query] +fn list() -> Vec { + STATE.with(|s| { + s.assets + .borrow() + .iter() + .map(|(key, asset)| { + let mut encodings: Vec<_> = asset + .encodings + .iter() + .map(|(enc_name, enc)| AssetEncodingDetails { + content_encoding: enc_name.clone(), + sha256: Some(ByteBuf::from(enc.sha256)), + length: Nat::from(enc.total_length), + modified: enc.modified.clone(), + }) + .collect(); + encodings.sort_by(|l, r| l.content_encoding.cmp(&r.content_encoding)); + + AssetDetails { + key: key.clone(), + content_type: asset.content_type.clone(), + encodings, + } + }) + .collect::>() + }) +} + +fn create_token( + _asset: &Asset, + enc_name: &str, + enc: &AssetEncoding, + key: &str, + chunk_index: usize, +) -> Option { + if chunk_index + 1 >= enc.content_chunks.len() { + None + } else { + Some(StreamingCallbackToken { + key: key.to_string(), + content_encoding: enc_name.to_string(), + index: Nat::from(chunk_index + 1), + sha256: Some(ByteBuf::from(enc.sha256)), + }) + } +} + +fn create_strategy( + asset: &Asset, + enc_name: &str, + enc: &AssetEncoding, + key: &str, + chunk_index: usize, +) -> Option { + create_token(asset, enc_name, enc, key, chunk_index).map(|token| StreamingStrategy::Callback { + callback: ic_cdk::export::candid::Func { + method: "http_request_streaming_callback".to_string(), + principal: ic_cdk::id(), + }, + token, + }) +} + +fn build_200( + asset: &Asset, + enc_name: &str, + enc: &AssetEncoding, + key: &str, + chunk_index: usize, + certificate_header: Option, +) -> HttpResponse { + let mut headers = vec![("Content-Type".to_string(), asset.content_type.to_string())]; + if enc_name != "identity" { + headers.push(("Content-Encoding".to_string(), enc_name.to_string())); + } + if let Some(head) = certificate_header { + headers.push(head); + } + + let streaming_strategy = create_strategy(asset, enc_name, enc, key, chunk_index); + + HttpResponse { + status_code: 200, + headers, + body: enc.content_chunks[chunk_index].clone(), + streaming_strategy, + } +} + +fn build_404(certificate_header: HeaderField) -> HttpResponse { + HttpResponse { + status_code: 404, + headers: vec![certificate_header], + body: RcBytes::from(ByteBuf::from("not found")), + streaming_strategy: None, + } +} + +fn build_http_response(path: &str, encodings: Vec, index: usize) -> HttpResponse { + STATE.with(|s| { + let assets = s.assets.borrow(); + + let index_redirect_certificate = ASSET_HASHES.with(|t| { + let tree = t.borrow(); + if tree.get(path.as_bytes()).is_none() && tree.get(INDEX_FILE.as_bytes()).is_some() { + let absence_proof = tree.witness(path.as_bytes()); + let index_proof = tree.witness(INDEX_FILE.as_bytes()); + let combined_proof = merge_hash_trees(absence_proof, index_proof); + Some(witness_to_header(combined_proof)) + } else { + None + } + }); + + if let Some(certificate_header) = index_redirect_certificate { + if let Some(asset) = assets.get(INDEX_FILE) { + for enc_name in encodings.iter() { + if let Some(enc) = asset.encodings.get(enc_name) { + if enc.certified { + return build_200( + asset, + enc_name, + enc, + INDEX_FILE, + index, + Some(certificate_header), + ); + } + } + } + } + } + + let certificate_header = + ASSET_HASHES.with(|t| witness_to_header(t.borrow().witness(path.as_bytes()))); + + if let Some(asset) = assets.get(path) { + for enc_name in encodings.iter() { + if let Some(enc) = asset.encodings.get(enc_name) { + if enc.certified { + return build_200( + asset, + enc_name, + enc, + path, + index, + Some(certificate_header), + ); + } else { + // Find if identity is certified, if it's not. + if let Some(id_enc) = asset.encodings.get("identity") { + if id_enc.certified { + return build_200( + asset, + enc_name, + enc, + path, + index, + Some(certificate_header), + ); + } + } + } + } + } + } + + build_404(certificate_header) + }) +} + +/// An iterator-like structure that decode a URL. +struct UrlDecode<'a> { + bytes: std::slice::Iter<'a, u8>, +} + +fn convert_percent(iter: &mut std::slice::Iter) -> Option { + let mut cloned_iter = iter.clone(); + let result = match cloned_iter.next()? { + b'%' => b'%', + h => { + let h = char::from(*h).to_digit(16)?; + let l = char::from(*cloned_iter.next()?).to_digit(16)?; + h as u8 * 0x10 + l as u8 + } + }; + // Update this if we make it this far, otherwise "reset" the iterator. + *iter = cloned_iter; + Some(result) +} + +#[derive(Debug, PartialEq)] +pub enum UrlDecodeError { + InvalidPercentEncoding, +} + +impl fmt::Display for UrlDecodeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::InvalidPercentEncoding => write!(f, "invalid percent encoding"), + } + } +} + +impl<'a> Iterator for UrlDecode<'a> { + type Item = Result; + + fn next(&mut self) -> Option { + let b = self.bytes.next()?; + match b { + b'%' => Some( + convert_percent(&mut self.bytes) + .map(char::from) + .ok_or(UrlDecodeError::InvalidPercentEncoding), + ), + b'+' => Some(Ok(' ')), + x => Some(Ok(char::from(*x))), + } + } + + fn size_hint(&self) -> (usize, Option) { + let bytes = self.bytes.len(); + (bytes / 3, Some(bytes)) + } +} + +fn url_decode(url: &str) -> Result { + UrlDecode { + bytes: url.as_bytes().iter(), + } + .collect() +} + +#[test] +fn check_url_decode() { + assert_eq!( + url_decode("/%"), + Err(UrlDecodeError::InvalidPercentEncoding) + ); + assert_eq!(url_decode("/%%"), Ok("/%".to_string())); + assert_eq!(url_decode("/%20a"), Ok("/ a".to_string())); + assert_eq!( + url_decode("/%%+a%20+%@"), + Err(UrlDecodeError::InvalidPercentEncoding) + ); + assert_eq!( + url_decode("/has%percent.txt"), + Err(UrlDecodeError::InvalidPercentEncoding) + ); + assert_eq!(url_decode("/%e6"), Ok("/æ".to_string())); +} + +#[query] +fn http_request(req: HttpRequest) -> HttpResponse { + let mut encodings = vec![]; + for (name, value) in req.headers.iter() { + if name.eq_ignore_ascii_case("Accept-Encoding") { + for v in value.split(',') { + encodings.push(v.trim().to_string()); + } + } + } + encodings.push("identity".to_string()); + + let path = match req.url.find('?') { + Some(i) => &req.url[..i], + None => &req.url[..], + }; + match url_decode(path) { + Ok(path) => build_http_response(&path, encodings, 0), + Err(err) => HttpResponse { + status_code: 400, + headers: vec![], + body: RcBytes::from(ByteBuf::from(format!( + "failed to decode path '{}': {}", + path, err + ))), + streaming_strategy: None, + }, + } +} + +#[query] +fn http_request_streaming_callback( + StreamingCallbackToken { + key, + content_encoding, + index, + sha256, + }: StreamingCallbackToken, +) -> StreamingCallbackHttpResponse { + STATE.with(|s| { + let assets = s.assets.borrow(); + let asset = assets + .get(&key) + .expect("Invalid token on streaming: key not found."); + let enc = asset + .encodings + .get(&content_encoding) + .expect("Invalid token on streaming: encoding not found."); + + if let Some(expected_hash) = sha256 { + if expected_hash != enc.sha256 { + trap("sha256 mismatch"); + } + } + + // MAX is good enough. This means a chunk would be above 64-bits, which is impossible... + let chunk_index = index.0.to_usize().unwrap_or(usize::MAX); + + StreamingCallbackHttpResponse { + body: enc.content_chunks[chunk_index].clone(), + token: create_token(asset, &content_encoding, enc, &key, chunk_index), + } + }) +} + +fn do_create_asset(arg: CreateAssetArguments) { + STATE.with(|s| { + let mut assets = s.assets.borrow_mut(); + if let Some(asset) = assets.get(&arg.key) { + if asset.content_type != arg.content_type { + trap("create_asset: content type mismatch"); + } + } else { + assets.insert( + arg.key, + Asset { + content_type: arg.content_type, + encodings: HashMap::new(), + }, + ); + } + }) +} + +fn do_set_asset_content(arg: SetAssetContentArguments) { + STATE.with(|s| { + if arg.chunk_ids.is_empty() { + trap("encoding must have at least one chunk"); + } + + let mut assets = s.assets.borrow_mut(); + let asset = assets + .get_mut(&arg.key) + .unwrap_or_else(|| trap("asset not found")); + let now = Int::from(time() as u64); + + let mut chunks = s.chunks.borrow_mut(); + + let mut content_chunks = vec![]; + for chunk_id in arg.chunk_ids.iter() { + let chunk = chunks.remove(chunk_id).expect("chunk not found"); + content_chunks.push(chunk.content); + } + + let sha256: [u8; 32] = match arg.sha256 { + Some(bytes) => bytes + .into_vec() + .try_into() + .unwrap_or_else(|_| trap("invalid SHA-256")), + None => { + let mut hasher = sha2::Sha256::new(); + for chunk in content_chunks.iter() { + hasher.update(chunk); + } + hasher.finalize().into() + } + }; + + let total_length: usize = content_chunks.iter().map(|c| c.len()).sum(); + let enc = AssetEncoding { + modified: now, + content_chunks, + certified: false, + total_length, + sha256, + }; + asset.encodings.insert(arg.content_encoding, enc); + + on_asset_change(&arg.key, asset); + }) +} + +fn do_unset_asset_content(arg: UnsetAssetContentArguments) { + STATE.with(|s| { + let mut assets = s.assets.borrow_mut(); + let asset = assets + .get_mut(&arg.key) + .unwrap_or_else(|| trap("asset not found")); + + if asset.encodings.remove(&arg.content_encoding).is_some() { + on_asset_change(&arg.key, asset); + } + }) +} + +fn do_delete_asset(arg: DeleteAssetArguments) { + STATE.with(|s| { + let mut assets = s.assets.borrow_mut(); + assets.remove(&arg.key); + }); + delete_asset_hash(&arg.key); +} + +fn do_clear() { + STATE.with(|s| { + s.assets.borrow_mut().clear(); + s.batches.borrow_mut().clear(); + s.chunks.borrow_mut().clear(); + *s.next_batch_id.borrow_mut() = Nat::from(1); + *s.next_chunk_id.borrow_mut() = Nat::from(1); + }) +} + +pub fn is_authorized() -> Result<(), String> { + STATE.with(|s| { + s.authorized + .borrow() + .contains(&caller()) + .then(|| ()) + .ok_or_else(|| "Caller is not authorized".to_string()) + }) +} + +fn on_asset_change(key: &str, asset: &mut Asset) { + // If the most preferred encoding is present and certified, + // there is nothing to do. + for enc_name in ENCODING_CERTIFICATION_ORDER.iter() { + if let Some(enc) = asset.encodings.get(*enc_name) { + if enc.certified { + return; + } else { + break; + } + } + } + + if asset.encodings.is_empty() { + delete_asset_hash(key); + return; + } + + // An encoding with a higher priority was added, let's certify it + // instead. + + for enc in asset.encodings.values_mut() { + enc.certified = false; + } + + for enc_name in ENCODING_CERTIFICATION_ORDER.iter() { + if let Some(enc) = asset.encodings.get_mut(*enc_name) { + certify_asset(key.to_string(), &enc.sha256); + enc.certified = true; + return; + } + } + + // No known encodings found. Just pick the first one. The exact + // order is hard to predict because we use a hash map. Should + // almost never happen anyway. + if let Some(enc) = asset.encodings.values_mut().next() { + certify_asset(key.to_string(), &enc.sha256); + enc.certified = true; + } +} + +fn certify_asset(key: Key, content_hash: &Hash) { + ASSET_HASHES.with(|t| { + let mut tree = t.borrow_mut(); + tree.insert(key, *content_hash); + set_root_hash(&*tree); + }); +} + +fn delete_asset_hash(key: &str) { + ASSET_HASHES.with(|t| { + let mut tree = t.borrow_mut(); + tree.delete(key.as_bytes()); + set_root_hash(&*tree); + }); +} + +fn set_root_hash(tree: &AssetHashes) { + use ic_certified_map::labeled_hash; + let full_tree_hash = labeled_hash(b"http_assets", &tree.root_hash()); + set_certified_data(&full_tree_hash); +} + +fn witness_to_header(witness: HashTree) -> HeaderField { + use ic_certified_map::labeled; + + let hash_tree = labeled(b"http_assets", witness); + let mut serializer = serde_cbor::ser::Serializer::new(vec![]); + serializer.self_describe().unwrap(); + hash_tree.serialize(&mut serializer).unwrap(); + + let certificate = data_certificate().unwrap_or_else(|| trap("no data certificate available")); + + ( + "IC-Certificate".to_string(), + String::from("certificate=:") + + &base64::encode(&certificate) + + ":, tree=:" + + &base64::encode(&serializer.into_inner()) + + ":", + ) +} + +fn merge_hash_trees<'a>(lhs: HashTree<'a>, rhs: HashTree<'a>) -> HashTree<'a> { + use HashTree::{Empty, Fork, Labeled, Leaf, Pruned}; + + match (lhs, rhs) { + (Pruned(l), Pruned(r)) => { + if l != r { + trap("merge_hash_trees: inconsistent hashes"); + } + Pruned(l) + } + (Pruned(_), r) => r, + (l, Pruned(_)) => l, + (Fork(l), Fork(r)) => Fork(Box::new(( + merge_hash_trees(l.0, r.0), + merge_hash_trees(l.1, r.1), + ))), + (Labeled(l_label, l), Labeled(r_label, r)) => { + if l_label != r_label { + trap("merge_hash_trees: inconsistent hash tree labels"); + } + Labeled(l_label, Box::new(merge_hash_trees(*l, *r))) + } + (Empty, Empty) => Empty, + (Leaf(l), Leaf(r)) => { + if l != r { + trap("merge_hash_trees: inconsistent leaves"); + } + Leaf(l) + } + (_l, _r) => { + trap("merge_hash_trees: inconsistent tree structure"); + } + } +} + +fn hash_bytes(bytes: &[u8]) -> Hash { + let mut hash = sha2::Sha256::new(); + hash.update(bytes); + hash.finalize().into() +} + +pub fn init() { + do_clear(); + STATE.with(|s| s.authorized.borrow_mut().push(caller())); +} + +pub fn pre_upgrade() -> StableState { + STATE.with(|s| StableState { + authorized: s.authorized.take(), + stable_assets: s.assets.take(), + }) +} + +pub fn post_upgrade(stable_state: StableState) { + do_clear(); + STATE.with(|s| { + s.authorized.replace(stable_state.authorized); + s.assets.replace(stable_state.stable_assets); + + for (asset_name, asset) in s.assets.borrow_mut().iter_mut() { + for enc in asset.encodings.values_mut() { + enc.certified = false; + } + on_asset_change(asset_name, asset); + } + }); +} diff --git a/src/ic-certified-assets/src/rc_bytes.rs b/src/ic-certified-assets/src/rc_bytes.rs new file mode 100644 index 000000000..bc376e85f --- /dev/null +++ b/src/ic-certified-assets/src/rc_bytes.rs @@ -0,0 +1,53 @@ +use ic_cdk::export::candid::{ + types::{internal::Type, Serializer}, + CandidType, Deserialize, +}; +use serde::de::Deserializer; +use serde_bytes::ByteBuf; +use std::convert::AsRef; +use std::ops::Deref; +use std::rc::Rc; + +#[derive(Clone, Debug)] +pub(crate) struct RcBytes(Rc); + +impl CandidType for RcBytes { + fn _ty() -> Type { + Type::Vec(Box::new(Type::Nat8)) + } + + fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> + where + S: Serializer, + { + serializer.serialize_blob(&*self.0) + } +} + +impl<'de> Deserialize<'de> for RcBytes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + ByteBuf::deserialize(deserializer).map(Self::from) + } +} + +impl From for RcBytes { + fn from(b: ByteBuf) -> Self { + Self(Rc::new(b)) + } +} + +impl AsRef<[u8]> for RcBytes { + fn as_ref(&self) -> &[u8] { + &*self.0 + } +} + +impl Deref for RcBytes { + type Target = [u8]; + fn deref(&self) -> &[u8] { + &*self.0 + } +} From f287539501333eed0152e50b66596517722406c7 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 2 Feb 2022 19:48:55 -0500 Subject: [PATCH 010/234] Prepare Cargo.toml for publish (#193) --- src/ic-certified-assets/Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml index 3af44752b..e79370b4a 100644 --- a/src/ic-certified-assets/Cargo.toml +++ b/src/ic-certified-assets/Cargo.toml @@ -1,8 +1,11 @@ [package] name = "ic-certified-assets" version = "0.1.0" -authors = ["DFINITY Stiftung "] edition = "2018" +authors = ["DFINITY Stiftung "] +description = "Rust support for asset certification." +license = "Apache-2.0" +keywords = ["internet-computer", "dfinity"] [dependencies] base64 = "0.13" From c627f3b9e26b77d580aec31d4a74b82b6faf4bad Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Thu, 3 Feb 2022 08:29:38 -0800 Subject: [PATCH 011/234] Update ic-certified-assets README. (#194) Signed-off-by: John Plevyak --- src/ic-certified-assets/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ic-certified-assets/README.md b/src/ic-certified-assets/README.md index 5ca0cdc5b..14f3c4844 100644 --- a/src/ic-certified-assets/README.md +++ b/src/ic-certified-assets/README.md @@ -37,11 +37,11 @@ fn pre_upgrade() { >>#[post_upgrade] fn post_upgrade() { - let (stable_state,): (StableState,) = - ic_cdk::storage::stable_restore().expect("failed to restore stable state"); - crate::assets::post_upgrade(stable_state.assets); + let (StableState { assets, my_state },): (StableState,) = + ic_cdk::storage::stable_restore().expect("failed to restore stable state"); + crate::assets::post_upgrade(assets); STATE.with(|s| { - s.my_state = stable_state.my_state; + s.my_state = my_state; }; } ``` From 76da97ddd36e35206b31066632ebbc440d6eec39 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 4 Feb 2022 14:35:23 -0500 Subject: [PATCH 012/234] Bump up ic-ledger-types version (#195) --- src/ic-ledger-types/CHANGELOG.md | 4 ++++ src/ic-ledger-types/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ic-ledger-types/CHANGELOG.md b/src/ic-ledger-types/CHANGELOG.md index da149632c..13c3e114d 100644 --- a/src/ic-ledger-types/CHANGELOG.md +++ b/src/ic-ledger-types/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.1] - 2022-02-04 +### Changed +* Upgrade `ic-cdk` to v0.4.0. + ## [0.1.0] - 2021-11-11 ### Added * Initial release of the library. diff --git a/src/ic-ledger-types/Cargo.toml b/src/ic-ledger-types/Cargo.toml index cafce9e7e..ee86fe7be 100644 --- a/src/ic-ledger-types/Cargo.toml +++ b/src/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.1.0" +version = "0.1.1" edition = "2018" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." From b7c952edccbceb23f4394447309f879a309a9eb2 Mon Sep 17 00:00:00 2001 From: Nicolas Mattia Date: Mon, 7 Feb 2022 17:54:12 +0100 Subject: [PATCH 013/234] fix: Actually print version with --version (#196) This makes sure that `ic-cdk-optimizer` prints the version: ``` ~/cdk-rs$ ./target/debug/ic-cdk-optimizer --version ic-cdk-optimizer 0.3.2 ~/cdk-rs$ ./target/debug/ic-cdk-optimizer --help ic-cdk-optimizer 0.3.2 USAGE: ic-cdk-optimizer --output [input] ARGS: Input file to optimize. By default will use STDIN FLAGS: -h, --help Prints help information -V, --version Prints version information OPTIONS: -o, --output Output file. Required ``` Co-authored-by: Linwei Shang --- src/ic-cdk-optimizer/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ic-cdk-optimizer/src/main.rs b/src/ic-cdk-optimizer/src/main.rs index 9c9cd77d1..94df7b340 100644 --- a/src/ic-cdk-optimizer/src/main.rs +++ b/src/ic-cdk-optimizer/src/main.rs @@ -6,7 +6,7 @@ use std::path::PathBuf; mod passes; #[derive(Clap, Debug)] -#[clap()] +#[clap(version)] struct CommandLineOpts { /// Input file to optimize. By default will use STDIN. input: Option, From f3923ac61e20e2069249717f0a3f11e9ab22cf11 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 7 Feb 2022 12:54:27 -0500 Subject: [PATCH 014/234] Release optimizer v0.3.4 (#198) --- src/ic-cdk-optimizer/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ic-cdk-optimizer/Cargo.toml b/src/ic-cdk-optimizer/Cargo.toml index 7ca340660..f21b51bca 100644 --- a/src/ic-cdk-optimizer/Cargo.toml +++ b/src/ic-cdk-optimizer/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "ic-cdk-optimizer" -version = "0.3.3" +version = "0.3.4" authors = ["DFINITY Stiftung "] edition = "2018" description = "WASM Optimizer for the IC CDK (experimental)." - homepage = "https://docs.rs/ic-cdk-optimizer" - documentation = "https://docs.rs/ic-cdk-optimizer" +homepage = "https://docs.rs/ic-cdk-optimizer" +documentation = "https://docs.rs/ic-cdk-optimizer" license = "Apache-2.0" readme = "README.md" categories = ["api-bindings", "data-structures", "no-std", "command-line-utilities"] From 5360899d1d8df043107615deb1ba53414a3f2f2e Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 8 Feb 2022 15:34:14 -0500 Subject: [PATCH 015/234] Add rust-toolchain.toml and point to 1.55.0 (#200) --- rust-toolchain.toml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 rust-toolchain.toml diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 000000000..b4c36257f --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.55.0" +components = ["rustfmt", "clippy"] From 1991c58321d06e77aa547aa522b6eb1cc9f2925f Mon Sep 17 00:00:00 2001 From: adamspofford-dfinity <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Mon, 14 Feb 2022 08:53:57 -0800 Subject: [PATCH 016/234] fix: Remove uniqueness check on export macros (#203) * Remove uniqueness check on export macros * Remove test --- src/ic-cdk-macros/src/export.rs | 46 ------------------- .../lifecycle_functions_only_once.rs | 33 ------------- .../lifecycle_functions_only_once.stderr | 39 ---------------- 3 files changed, 118 deletions(-) delete mode 100644 src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_only_once.rs delete mode 100644 src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_only_once.stderr diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index 4412cd40b..b1c739bed 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -3,7 +3,6 @@ use quote::quote; use serde::Deserialize; use serde_tokenstream::from_tokenstream; use std::fmt::Formatter; -use std::sync::atomic::{AtomicBool, Ordering}; use syn::Error; use syn::{spanned::Spanned, FnArg, ItemFn, Pat, PatIdent, PatType, ReturnType, Signature, Type}; @@ -215,71 +214,26 @@ pub(crate) fn ic_update(attr: TokenStream, item: TokenStream) -> Result Result { - if IS_INIT.swap(true, Ordering::SeqCst) { - return Err(Error::new( - Span::call_site(), - "[init] function already declared.", - )); - } - dfn_macro(MethodType::Init, attr, item) } -static HAS_PRE_UPGRADE: AtomicBool = AtomicBool::new(false); - pub(crate) fn ic_pre_upgrade(attr: TokenStream, item: TokenStream) -> Result { - if HAS_PRE_UPGRADE.swap(true, Ordering::SeqCst) { - return Err(Error::new( - Span::call_site(), - "[pre_upgrade] function already declared.", - )); - } - dfn_macro(MethodType::PreUpgrade, attr, item) } -static HAS_POST_UPGRADE: AtomicBool = AtomicBool::new(false); - pub(crate) fn ic_post_upgrade(attr: TokenStream, item: TokenStream) -> Result { - if HAS_POST_UPGRADE.swap(true, Ordering::SeqCst) { - return Err(Error::new( - Span::call_site(), - "[post_upgrade] function already declared.", - )); - } - dfn_macro(MethodType::PostUpgrade, attr, item) } -static HAS_HEARTBEAT: AtomicBool = AtomicBool::new(false); - pub(crate) fn ic_heartbeat(attr: TokenStream, item: TokenStream) -> Result { - if HAS_HEARTBEAT.swap(true, Ordering::SeqCst) { - return Err(Error::new( - Span::call_site(), - "[heartbeat] function already declared.", - )); - } - dfn_macro(MethodType::Heartbeat, attr, item) } -static HAS_INSPECT_MESSAGE: AtomicBool = AtomicBool::new(false); - pub(crate) fn ic_inspect_message( attr: TokenStream, item: TokenStream, ) -> Result { - if HAS_INSPECT_MESSAGE.swap(true, Ordering::SeqCst) { - return Err(Error::new( - Span::call_site(), - "[inspect_message] function already declared.", - )); - } - dfn_macro(MethodType::InspectMessage, attr, item) } diff --git a/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_only_once.rs b/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_only_once.rs deleted file mode 100644 index c99b7cf75..000000000 --- a/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_only_once.rs +++ /dev/null @@ -1,33 +0,0 @@ -use ic_cdk_macros::*; - -#[init] -fn init_1() {} - -#[init] -fn init_2() {} - -#[pre_upgrade] -fn pre_upgrade_1() {} - -#[pre_upgrade] -fn pre_upgrade_2() {} - -#[post_upgrade] -fn post_upgrade_1() {} - -#[post_upgrade] -fn post_upgrade_2() {} - -#[heartbeat] -fn heartbeat_1() {} - -#[heartbeat] -fn heartbeat_2() {} - -#[inspect_message] -fn inspect_message_1() {} - -#[inspect_message] -fn inspect_message_2() {} - -fn main() {} diff --git a/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_only_once.stderr b/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_only_once.stderr deleted file mode 100644 index 272f3da51..000000000 --- a/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_only_once.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error: [init] function already declared. - --> tests/compile_fail/lifecycle_functions_only_once.rs:6:1 - | -6 | #[init] - | ^^^^^^^ - | - = note: this error originates in the attribute macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: [pre_upgrade] function already declared. - --> tests/compile_fail/lifecycle_functions_only_once.rs:12:1 - | -12 | #[pre_upgrade] - | ^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `pre_upgrade` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: [post_upgrade] function already declared. - --> tests/compile_fail/lifecycle_functions_only_once.rs:18:1 - | -18 | #[post_upgrade] - | ^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `post_upgrade` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: [heartbeat] function already declared. - --> tests/compile_fail/lifecycle_functions_only_once.rs:24:1 - | -24 | #[heartbeat] - | ^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `heartbeat` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: [inspect_message] function already declared. - --> tests/compile_fail/lifecycle_functions_only_once.rs:30:1 - | -30 | #[inspect_message] - | ^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `inspect_message` (in Nightly builds, run with -Z macro-backtrace for more info) From a253119adb08929b6304d007ee0a6a37960656ed Mon Sep 17 00:00:00 2001 From: adamspofford-dfinity <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Wed, 16 Feb 2022 09:43:17 -0800 Subject: [PATCH 017/234] Remove out-of-bounds vulnerability (#208) --- src/ic-cdk/src/api/stable.rs | 55 ++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/ic-cdk/src/api/stable.rs b/src/ic-cdk/src/api/stable.rs index c4f1c27d9..9ae91c91c 100644 --- a/src/ic-cdk/src/api/stable.rs +++ b/src/ic-cdk/src/api/stable.rs @@ -2,7 +2,7 @@ //! //! You can check the [Internet Computer Specification](https://smartcontracts.org/docs/interface-spec/index.html#system-api-stable-memory) //! for a in-depth explanation of stable memory. -use std::io; +use std::{error, fmt, io}; /// Gets current size of the stable memory. pub fn stable_size() -> u32 { @@ -15,7 +15,24 @@ pub fn stable64_size() -> u64 { } /// A possible error value when dealing with stable memory. -pub struct StableMemoryError(); +#[derive(Debug)] +pub enum StableMemoryError { + /// No more stable memory could be allocated. + OutOfMemory, + /// Attempted to read more stable memory than had been allocated. + OutOfBounds, +} + +impl fmt::Display for StableMemoryError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::OutOfMemory => f.write_str("Out of memory"), + Self::OutOfBounds => f.write_str("Read exceeds allocated memory"), + } + } +} + +impl error::Error for StableMemoryError {} /// Attempts to grow the stable memory by `new_pages` (added pages). /// @@ -26,7 +43,7 @@ pub struct StableMemoryError(); pub fn stable_grow(new_pages: u32) -> Result { unsafe { match super::ic0::stable_grow(new_pages as i32) { - -1 => Err(StableMemoryError()), + -1 => Err(StableMemoryError::OutOfMemory), x => Ok(x as u32), } } @@ -36,7 +53,7 @@ pub fn stable_grow(new_pages: u32) -> Result { pub fn stable64_grow(new_pages: u64) -> Result { unsafe { match super::ic0::stable64_grow(new_pages as i64) { - -1 => Err(StableMemoryError()), + -1 => Err(StableMemoryError::OutOfMemory), x => Ok(x as u64), } } @@ -134,7 +151,7 @@ impl StableWriter { impl io::Write for StableWriter { fn write(&mut self, buf: &[u8]) -> Result { self.write(buf) - .map_err(|_| io::Error::new(io::ErrorKind::Other, "Out Of Memory")) + .map_err(|e| io::Error::new(io::ErrorKind::OutOfMemory, e)) } fn flush(&mut self) -> Result<(), io::Error> { @@ -147,28 +164,42 @@ impl io::Write for StableWriter { /// /// Keeps an offset and reads off stable memory consecutively. pub struct StableReader { - /// The offset of the next write. + /// The offset of the next read. offset: usize, + /// The capacity, in pages. + capacity: u32, } impl Default for StableReader { fn default() -> Self { - Self { offset: 0 } + Self { + offset: 0, + capacity: stable_size(), + } } } impl StableReader { /// Reads data from the stable memory location specified by an offset. pub fn read(&mut self, buf: &mut [u8]) -> Result { - stable_read(self.offset as u32, buf); - self.offset += buf.len(); - Ok(buf.len()) + let cap = (self.capacity as usize) << 16; + let read_buf = if buf.len() + self.offset > cap { + if self.offset < cap { + &mut buf[..cap - self.offset] + } else { + return Err(StableMemoryError::OutOfBounds); + } + } else { + buf + }; + stable_read(self.offset as u32, read_buf); + self.offset += read_buf.len(); + Ok(read_buf.len()) } } impl io::Read for StableReader { fn read(&mut self, buf: &mut [u8]) -> Result { - self.read(buf) - .map_err(|_| io::Error::new(io::ErrorKind::Other, "Unexpected error.")) + self.read(buf).or(Ok(0)) // Read defines EOF to be success } } From 30b6d845946a58da93746253e2f12f730eaeab74 Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Thu, 17 Feb 2022 00:06:53 +0000 Subject: [PATCH 018/234] Add Clone and Copy to RejectionCode (#202) --- src/ic-cdk/src/api/call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index a50bdcc15..bfeca610a 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -127,7 +127,7 @@ use rc::{InnerCell, WasmCell}; /// These can be obtained either using `reject_code()` or `reject_result()`. #[allow(missing_docs)] #[repr(i32)] -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub enum RejectionCode { NoError = 0, From b24a8b278cbca04314fa5fcad8df579590356198 Mon Sep 17 00:00:00 2001 From: adamspofford-dfinity <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Thu, 17 Feb 2022 12:58:55 -0800 Subject: [PATCH 019/234] chore: Update clap to 3.1 (#209) * Update clap to 3.1 * Remove conflicting arguments None of this appears to serve any purpose --- src/ic-cdk-optimizer/Cargo.toml | 3 +-- src/ic-cdk-optimizer/src/main.rs | 19 ++++--------------- src/ic-cdk-optimizer/src/passes.rs | 14 +++++--------- src/ic-cdk-optimizer/src/passes/binaryen.rs | 14 ++------------ 4 files changed, 12 insertions(+), 38 deletions(-) diff --git a/src/ic-cdk-optimizer/Cargo.toml b/src/ic-cdk-optimizer/Cargo.toml index f21b51bca..af6cfd0d9 100644 --- a/src/ic-cdk-optimizer/Cargo.toml +++ b/src/ic-cdk-optimizer/Cargo.toml @@ -16,7 +16,6 @@ include = ["src", "Cargo.toml", "LICENSE", "README.md"] [dependencies] binaryen = "0.12.0" -clap = "=3.0.0-beta.2" -clap_derive = "=3.0.0-beta.2" +clap = { version = "3.1.0", features = ["derive"] } humansize = "1.1.0" wabt = "0.10.0" diff --git a/src/ic-cdk-optimizer/src/main.rs b/src/ic-cdk-optimizer/src/main.rs index 94df7b340..88dd59465 100644 --- a/src/ic-cdk-optimizer/src/main.rs +++ b/src/ic-cdk-optimizer/src/main.rs @@ -1,11 +1,11 @@ -use clap::{Clap, FromArgMatches, IntoApp}; +use clap::Parser; use humansize::{file_size_opts, FileSize}; use std::io::Read; use std::path::PathBuf; mod passes; -#[derive(Clap, Debug)] +#[derive(Parser, Debug)] #[clap(version)] struct CommandLineOpts { /// Input file to optimize. By default will use STDIN. @@ -18,18 +18,7 @@ struct CommandLineOpts { fn main() { let passes = passes::create(); - let mut app = ::into_app(); - - for pass in &passes { - let args = pass.args(); - for arg in args.get_arguments() { - app = app.arg(arg); - } - } - - let matches = app.get_matches(); - let opts = ::from_arg_matches(&matches); - + let opts = CommandLineOpts::parse(); let content = if let Some(i) = opts.input { std::fs::read(&i).expect("Could not read the file.") } else { @@ -51,7 +40,7 @@ fn main() { for pass in passes { eprintln!("{}...", pass.description()); - let new_wasm = pass.opt(&wasm_back, &matches).expect("Pass failed:"); + let new_wasm = pass.opt(&wasm_back).expect("Pass failed:"); if new_wasm.len() < wasm_back.len() { wasm_back = new_wasm; eprintln!( diff --git a/src/ic-cdk-optimizer/src/passes.rs b/src/ic-cdk-optimizer/src/passes.rs index 6685bd90b..fecc243d4 100644 --- a/src/ic-cdk-optimizer/src/passes.rs +++ b/src/ic-cdk-optimizer/src/passes.rs @@ -1,4 +1,3 @@ -use clap::ArgMatches; use wabt::{wasm2wat, wat2wasm}; mod binaryen; @@ -6,15 +5,12 @@ mod binaryen; pub type PassResult = Result, Box>; pub trait OptimizationPass { - fn args(&self) -> clap::App { - clap::App::new(&self.short_name()) - } fn short_name(&self) -> String; fn description(&self) -> String; - fn opt(&self, wasm: &[u8], args: &ArgMatches) -> PassResult; + fn opt(&self, wasm: &[u8]) -> PassResult; } -struct RemoveDebugSymbolsPass {} +struct RemoveDebugSymbolsPass; impl OptimizationPass for RemoveDebugSymbolsPass { fn short_name(&self) -> String { @@ -25,7 +21,7 @@ impl OptimizationPass for RemoveDebugSymbolsPass { String::from("Stripping Unused Data Segments") } - fn opt(&self, wasm: &[u8], _: &ArgMatches) -> PassResult { + fn opt(&self, wasm: &[u8]) -> PassResult { let wat = wasm2wat(&wasm)?; Ok(wat2wasm(&wat)?) } @@ -33,7 +29,7 @@ impl OptimizationPass for RemoveDebugSymbolsPass { pub fn create() -> Vec> { vec![ - Box::new(RemoveDebugSymbolsPass {}), - Box::new(binaryen::BinaryenPass {}), + Box::new(RemoveDebugSymbolsPass), + Box::new(binaryen::BinaryenPass), ] } diff --git a/src/ic-cdk-optimizer/src/passes/binaryen.rs b/src/ic-cdk-optimizer/src/passes/binaryen.rs index 73a205e29..5676b5700 100644 --- a/src/ic-cdk-optimizer/src/passes/binaryen.rs +++ b/src/ic-cdk-optimizer/src/passes/binaryen.rs @@ -1,19 +1,9 @@ use crate::passes::{OptimizationPass, PassResult}; use binaryen::{CodegenConfig, Module}; -use clap::{ArgMatches, Clap, IntoApp}; -pub struct BinaryenPass {} - -impl BinaryenPass {} - -#[derive(Clap, Debug)] -pub struct BinaryenPassArgs {} +pub struct BinaryenPass; impl OptimizationPass for BinaryenPass { - fn args(&self) -> clap::App { - BinaryenPassArgs::into_app() - } - fn short_name(&self) -> String { String::from("binaryen") } @@ -22,7 +12,7 @@ impl OptimizationPass for BinaryenPass { String::from("Execute a binaryen optimization pass on your WASM.") } - fn opt(&self, wasm: &[u8], _matches: &ArgMatches) -> PassResult { + fn opt(&self, wasm: &[u8]) -> PassResult { let mut module = Module::read(wasm).map_err(|_| String::from("Could not load module..."))?; From 28eb8f75540d132818d01ece0f15a48aa43d3726 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Feb 2022 08:43:03 -0800 Subject: [PATCH 020/234] chore(deps): bump url-parse from 1.5.3 to 1.5.7 in /examples/chess (#211) Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.3 to 1.5.7. - [Release notes](https://github.com/unshiftio/url-parse/releases) - [Commits](https://github.com/unshiftio/url-parse/compare/1.5.3...1.5.7) --- updated-dependencies: - dependency-name: url-parse dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/chess/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/chess/package-lock.json b/examples/chess/package-lock.json index ad51f2eed..b7981e1e6 100644 --- a/examples/chess/package-lock.json +++ b/examples/chess/package-lock.json @@ -7508,9 +7508,9 @@ } }, "node_modules/url-parse": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz", + "integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==", "dev": true, "dependencies": { "querystringify": "^2.1.1", @@ -14351,9 +14351,9 @@ } }, "url-parse": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz", + "integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==", "dev": true, "requires": { "querystringify": "^2.1.1", From b8d0749569aae728f69acc194ca3301c906f28ca Mon Sep 17 00:00:00 2001 From: adamspofford-dfinity <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Tue, 22 Feb 2022 12:16:17 -0800 Subject: [PATCH 021/234] feat: Allow configuring export macros to not reply (#210) --- .../examples/profile-tutorial/profile.rs | 18 ++++--- .../asset_storage/src/asset_storage_rs/lib.rs | 12 +++-- examples/counter/src/counter_rs/lib.rs | 11 ++-- examples/profile/src/profile_rs/lib.rs | 21 ++++---- src/ic-cdk-macros/src/export.rs | 4 +- src/ic-cdk-macros/src/lib.rs | 36 +++++++++++++ src/ic-cdk/src/api/call.rs | 54 ++++++++++++++++++- 7 files changed, 131 insertions(+), 25 deletions(-) diff --git a/docs/modules/rust-guide/examples/profile-tutorial/profile.rs b/docs/modules/rust-guide/examples/profile-tutorial/profile.rs index e6f8a0a5d..28c51a8db 100644 --- a/docs/modules/rust-guide/examples/profile-tutorial/profile.rs +++ b/docs/modules/rust-guide/examples/profile-tutorial/profile.rs @@ -1,5 +1,11 @@ -use ic_cdk::export::{candid::{CandidType, Deserialize}, Principal}; use ic_cdk::storage; +use ic_cdk::{ + call::{self, ManualReply}, + export::{ + candid::{CandidType, Deserialize}, + Principal, + }, +}; use ic_cdk_macros::*; use std::collections::BTreeMap; @@ -45,22 +51,22 @@ fn update(profile: Profile) { profile_store.insert(principal_id, profile); } -#[query] -fn search(text: String) -> Option<&'static Profile> { +#[query(manual_reply = true)] +fn search(text: String) -> ManualReply> { let text = text.to_lowercase(); let profile_store = storage::get::(); for (_, p) in profile_store.iter() { if p.name.to_lowercase().contains(&text) || p.description.to_lowercase().contains(&text) { - return Some(p); + return ManualReply::one(Some(p)); } for x in p.keywords.iter() { if x.to_lowercase() == text { - return Some(p); + return ManualReply::one(Some(p)); } } } - None + ManualReply::one(None::) } diff --git a/examples/asset_storage/src/asset_storage_rs/lib.rs b/examples/asset_storage/src/asset_storage_rs/lib.rs index 6b698fd21..f2f4d1fd4 100644 --- a/examples/asset_storage/src/asset_storage_rs/lib.rs +++ b/examples/asset_storage/src/asset_storage_rs/lib.rs @@ -1,4 +1,8 @@ -use ic_cdk::{storage, export::Principal}; +use ic_cdk::{ + api::call::{self, ManualReply}, + export::Principal, + storage, +}; use ic_cdk_macros::*; use std::collections::{BTreeMap, BTreeSet}; @@ -27,12 +31,12 @@ fn store(path: String, contents: Vec) { store.insert(path, contents); } -#[query] -fn retrieve(path: String) -> &'static Vec { +#[query(manual_reply = true)] +fn retrieve(path: String) -> ManualReply> { let store = storage::get::(); match store.get(&path) { - Some(content) => content, + Some(content) => ManualReply::one(content), None => panic!("Path {} not found.", path), } } diff --git a/examples/counter/src/counter_rs/lib.rs b/examples/counter/src/counter_rs/lib.rs index a1dc1cfef..477271bab 100644 --- a/examples/counter/src/counter_rs/lib.rs +++ b/examples/counter/src/counter_rs/lib.rs @@ -1,5 +1,8 @@ +use ic_cdk::{ + api::call::{self, ManualReply}, + export::{candid, Principal}, +}; use ic_cdk_macros::*; -use ic_cdk::export::{candid, Principal}; static mut COUNTER: Option = None; static mut OWNER: Option = None; @@ -20,9 +23,9 @@ fn inc() -> () { } } -#[query] -fn read() -> candid::Nat { - unsafe { COUNTER.as_mut().unwrap().clone() } +#[query(manual_reply = true)] +fn read() -> ManualReply { + unsafe { ManualReply::one(COUNTER.as_mut().unwrap()) } } #[update] diff --git a/examples/profile/src/profile_rs/lib.rs b/examples/profile/src/profile_rs/lib.rs index ad587c127..dddca70b6 100644 --- a/examples/profile/src/profile_rs/lib.rs +++ b/examples/profile/src/profile_rs/lib.rs @@ -1,8 +1,11 @@ -use ic_cdk::export::{ - candid::{CandidType, Deserialize}, - Principal, -}; use ic_cdk::storage; +use ic_cdk::{ + api::call::{self, ManualReply}, + export::{ + candid::{CandidType, Deserialize}, + Principal, + }, +}; use ic_cdk_macros::*; use std::collections::BTreeMap; @@ -48,22 +51,22 @@ fn update(profile: Profile) { profile_store.insert(principal_id, profile); } -#[query] -fn search(text: String) -> Option<&'static Profile> { +#[query(manual_reply = true)] +fn search(text: String) -> ManualReply> { let text = text.to_lowercase(); let profile_store = storage::get::(); for (_, p) in profile_store.iter() { if p.name.to_lowercase().contains(&text) || p.description.to_lowercase().contains(&text) { - return Some(p); + return ManualReply::one(Some(p)); } for x in p.keywords.iter() { if x.to_lowercase() == text { - return Some(p); + return ManualReply::one(Some(p)); } } } - None + ManualReply::one(None::) } diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index b1c739bed..086a3ad3c 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -10,6 +10,8 @@ use syn::{spanned::Spanned, FnArg, ItemFn, Pat, PatIdent, PatType, ReturnType, S struct ExportAttributes { pub name: Option, pub guard: Option, + #[serde(default)] + pub manual_reply: bool, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -152,7 +154,7 @@ fn dfn_macro( let arg_count = arg_tuple.len(); - let return_encode = if method.is_lifecycle() { + let return_encode = if method.is_lifecycle() || attrs.manual_reply { quote! {} } else { match return_length { diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index 8c3cdc975..f63cdc8d8 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -89,6 +89,24 @@ where /// # unimplemented!() /// } /// ``` +/// +/// If you would rather call the [`call::reply`] function than return a value, +/// you will need to set `manual_reply` to `true` so that the canister does not +/// trap. +/// +/// ```rust +/// # fn calculate_result() {} +/// # type MyResult = (); +/// # use ic_cdk_macros::query; +/// use ic_cdk::api::call::{self, ManualReply}; +/// #[query(manual_reply = true)] +/// fn query_function() -> ManualReply { +/// let result = calculate_result(); +/// ManualReply::one(result) +/// } +/// ``` +/// +/// [`reply`]: ic_cdk::api::call::reply #[proc_macro_attribute] pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_query, "ic_query", attr, item) @@ -120,6 +138,24 @@ pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { /// # unimplemented!() /// } /// ``` +/// +/// If you would rather call the [`call::reply`] function than return a value, +/// you will need to set `manual_reply` to `true` so that the canister does not +/// trap. +/// +/// ```rust +/// # fn calculate_result() {} +/// # type MyResult = (); +/// # use ic_cdk_macros::update; +/// use ic_cdk::api::call::{self, ManualReply}; +/// #[update(manual_reply = true)] +/// fn update_function() -> ManualReply { +/// let result = calculate_result(); +/// ManualReply::one(result) +/// } +/// ``` +/// +/// [`reply`]: ic_cdk::api::call::reply #[proc_macro_attribute] pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_update, "ic_update", attr, item) diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index bfeca610a..34cbf4246 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -2,8 +2,10 @@ use crate::api::{ic0, trap}; use crate::export::Principal; use candid::utils::{ArgumentDecoder, ArgumentEncoder}; -use candid::{decode_args, encode_args, write_args}; +use candid::{decode_args, encode_args, write_args, CandidType}; +use serde::ser::Error; use std::future::Future; +use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll, Waker}; @@ -395,3 +397,53 @@ pub fn method_name() -> String { } String::from_utf8_lossy(&bytes).to_string() } + +/// Pretends to have the Candid type `T`, but unconditionally errors +/// when serialized. +/// +/// Usable, but not required, as metadata when using `#[query(reply = false)]`, +/// so an accurate Candid file can still be generated. +#[derive(Debug, Copy, Clone, Default)] +pub struct ManualReply(PhantomData); + +impl ManualReply { + /// Constructs a new `ManualReply`. + #[allow(clippy::self_named_constructors)] + pub const fn empty() -> Self { + Self(PhantomData) + } + /// Replies with the given value and returns a new `ManualReply`, + /// for a useful reply-then-return shortcut. + pub fn all(value: U) -> Self + where + U: ArgumentEncoder, + { + reply(value); + Self::empty() + } + /// Replies with a one-element tuple around the given value and returns + /// a new `ManualReply`, for a useful reply-then-return shortcut. + pub fn one(value: U) -> Self + where + U: CandidType, + { + reply((value,)); + Self::empty() + } +} + +impl CandidType for ManualReply +where + T: CandidType + ?Sized, +{ + fn _ty() -> candid::types::Type { + T::_ty() + } + /// Unconditionally errors. + fn idl_serialize(&self, _: S) -> Result<(), S::Error> + where + S: candid::types::Serializer, + { + Err(S::Error::custom("`Empty` cannot be serialized")) + } +} From 01ad9029e25ad055ae97c8a0fafb8b402745aeb2 Mon Sep 17 00:00:00 2001 From: adamspofford-dfinity <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Tue, 22 Feb 2022 14:56:35 -0800 Subject: [PATCH 022/234] feat: Remove non-stable storage API (#215) * Remove unstable storage * Update examples --- .../examples/profile-tutorial/profile.rs | 74 +++++++++------- .../asset_storage/src/asset_storage_rs/lib.rs | 39 ++++---- examples/build.sh | 0 examples/chess/src/chess_rs/lib.rs | 79 ++++++++--------- examples/counter/src/counter_rs/lib.rs | 26 +++--- examples/counter/src/inter2_rs/lib.rs | 2 +- examples/counter/src/inter_rs/lib.rs | 2 +- examples/profile/src/profile_rs/lib.rs | 88 +++++++++++-------- src/ic-cdk/src/storage.rs | 50 +---------- 9 files changed, 164 insertions(+), 196 deletions(-) mode change 100644 => 100755 examples/build.sh diff --git a/docs/modules/rust-guide/examples/profile-tutorial/profile.rs b/docs/modules/rust-guide/examples/profile-tutorial/profile.rs index 28c51a8db..bed2c2e73 100644 --- a/docs/modules/rust-guide/examples/profile-tutorial/profile.rs +++ b/docs/modules/rust-guide/examples/profile-tutorial/profile.rs @@ -1,4 +1,3 @@ -use ic_cdk::storage; use ic_cdk::{ call::{self, ManualReply}, export::{ @@ -7,6 +6,7 @@ use ic_cdk::{ }, }; use ic_cdk_macros::*; +use std::cell::RefCell; use std::collections::BTreeMap; type IdStore = BTreeMap; @@ -19,54 +19,66 @@ struct Profile { pub keywords: Vec, } +thread_local! { + static PROFILE_STORE: RefCell = RefCell::default(); + static ID_STORE: RefCell = RefCell::default(); +} + #[query(name = "getSelf")] fn get_self() -> Profile { - let id = ic_cdk::caller(); - let profile_store = storage::get::(); - - profile_store - .get(&id) - .cloned() - .unwrap_or_else(|| Profile::default()) + let id = ic_cdk::api::caller(); + PROFILE_STORE.with(|profile_store| { + profile_store + .borrow() + .get(&id) + .cloned() + .unwrap_or_else(|| Profile::default()) + }) } #[query] fn get(name: String) -> Profile { - let id_store = storage::get::(); - let profile_store = storage::get::(); - - id_store - .get(&name) - .and_then(|id| profile_store.get(id).cloned()) - .unwrap_or_else(|| Profile::default()) + ID_STORE.with(|id_store| { + PROFILE_STORE.with(|profile_store| { + id_store + .borrow() + .get(&name) + .and_then(|id| profile_store.borrow().get(id).cloned()) + .unwrap_or_else(|| Profile::default()) + }) + }) } #[update] fn update(profile: Profile) { - let principal_id = ic_cdk::caller(); - let id_store = storage::get_mut::(); - let profile_store = storage::get_mut::(); - - id_store.insert(profile.name.clone(), principal_id.clone()); - profile_store.insert(principal_id, profile); + let principal_id = ic_cdk::api::caller(); + ID_STORE.with(|id_store| { + id_store + .borrow_mut() + .insert(profile.name.clone(), principal_id); + }); + PROFILE_STORE.with(|profile_store| { + profile_store.borrow_mut().insert(principal_id, profile); + }); } #[query(manual_reply = true)] fn search(text: String) -> ManualReply> { let text = text.to_lowercase(); - let profile_store = storage::get::(); - - for (_, p) in profile_store.iter() { - if p.name.to_lowercase().contains(&text) || p.description.to_lowercase().contains(&text) { - return ManualReply::one(Some(p)); - } - - for x in p.keywords.iter() { - if x.to_lowercase() == text { + PROFILE_STORE.with(|profile_store| { + for (_, p) in profile_store.borrow().iter() { + if p.name.to_lowercase().contains(&text) || p.description.to_lowercase().contains(&text) + { return ManualReply::one(Some(p)); } + + for x in p.keywords.iter() { + if x.to_lowercase() == text { + return ManualReply::one(Some(p)); + } + } } - } + }); ManualReply::one(None::) } diff --git a/examples/asset_storage/src/asset_storage_rs/lib.rs b/examples/asset_storage/src/asset_storage_rs/lib.rs index f2f4d1fd4..6df723e63 100644 --- a/examples/asset_storage/src/asset_storage_rs/lib.rs +++ b/examples/asset_storage/src/asset_storage_rs/lib.rs @@ -1,24 +1,27 @@ use ic_cdk::{ - api::call::{self, ManualReply}, + api::call::ManualReply, export::Principal, storage, }; use ic_cdk_macros::*; +use std::cell::RefCell; use std::collections::{BTreeMap, BTreeSet}; type Users = BTreeSet; type Store = BTreeMap>; +thread_local! { + static USERS: RefCell = RefCell::default(); + static STORE: RefCell = RefCell::default(); +} + #[init] fn init() { - let users = storage::get_mut::(); - users.insert(ic_cdk::api::caller()); + USERS.with(|users| users.borrow_mut().insert(ic_cdk::api::caller())); } fn is_user() -> Result<(), String> { - let users = storage::get::(); - - if users.contains(&ic_cdk::api::caller()) { + if USERS.with(|users| users.borrow().contains(&ic_cdk::api::caller())) { Ok(()) } else { Err("Store can only be set by the owner of the asset canister.".to_string()) @@ -27,39 +30,29 @@ fn is_user() -> Result<(), String> { #[update(guard = "is_user")] fn store(path: String, contents: Vec) { - let store = storage::get_mut::(); - store.insert(path, contents); + STORE.with(|store| store.borrow_mut().insert(path, contents)); } #[query(manual_reply = true)] fn retrieve(path: String) -> ManualReply> { - let store = storage::get::(); - - match store.get(&path) { + STORE.with(|store| match store.borrow().get(&path) { Some(content) => ManualReply::one(content), None => panic!("Path {} not found.", path), - } + }) } #[update(guard = "is_user")] fn add_user(principal: Principal) { - let users = storage::get_mut::(); - users.insert(principal); + USERS.with(|users| users.borrow_mut().insert(principal)); } #[pre_upgrade] fn pre_upgrade() { - let mut vec = Vec::new(); - for p in storage::get_mut::().iter() { - vec.push(p); - } - storage::stable_save((vec,)).unwrap(); + USERS.with(|users| storage::stable_save((users,)).unwrap()); } #[post_upgrade] fn post_upgrade() { - let (old_users,): (Vec,) = storage::stable_restore().unwrap(); - for u in old_users { - storage::get_mut::().insert(u); - } + let (old_users,): (BTreeSet,) = storage::stable_restore().unwrap(); + USERS.with(|users| *users.borrow_mut() = old_users); } diff --git a/examples/build.sh b/examples/build.sh old mode 100644 new mode 100755 diff --git a/examples/chess/src/chess_rs/lib.rs b/examples/chess/src/chess_rs/lib.rs index 046d58bf3..e2ef86d45 100644 --- a/examples/chess/src/chess_rs/lib.rs +++ b/examples/chess/src/chess_rs/lib.rs @@ -1,8 +1,8 @@ use ic_cdk::export::candid::CandidType; -use ic_cdk::storage; use ic_cdk_macros::*; use pleco::tools::Searcher; use serde::Serialize; +use std::cell::RefCell; use std::collections::BTreeMap; type GameStore = BTreeMap; @@ -16,15 +16,20 @@ pub struct GameInternal { pub board: pleco::Board, } +thread_local! { + static STORE: RefCell = RefCell::default(); +} + #[update] fn new(name: String, white: bool) -> () { - let game_store = storage::get_mut::(); - game_store.insert( - name.clone(), - GameInternal { - board: pleco::Board::start_pos(), - }, - ); + STORE.with(|game_store| { + game_store.borrow_mut().insert( + name.clone(), + GameInternal { + board: pleco::Board::start_pos(), + }, + ); + }); // If the user is playing black; if !white { @@ -34,48 +39,42 @@ fn new(name: String, white: bool) -> () { #[update(name = "move")] fn uci_move(name: String, m: String) -> bool { - let game_store = storage::get_mut::(); - - if !game_store.contains_key(&name) { - panic!("Game {} does not exist.", name); - } - - let game = game_store - .get_mut(&name) - .expect(&format!("No game named {}", name)); - - // If the move is valid, also apply the next move using AI. - if game.board.apply_uci_move(&m) { + let should_move = STORE.with(|game_store| { + let mut game_store = game_store.borrow_mut(); + let game = game_store + .get_mut(&name) + .unwrap_or_else(|| panic!("Game {} does not exist.", name)); + + // If the move is valid, also apply the next move using AI. + game.board.apply_uci_move(&m) + }); + if should_move { ai_move(name); - true - } else { - false } + should_move } #[update(name = "aiMove")] fn ai_move(name: String) -> () { - let game_store = storage::get_mut::(); - - if !game_store.contains_key(&name) { - panic!("Game {} does not exist.", name); - } + STORE.with(|game_store| { + let mut game_store = game_store.borrow_mut(); + let game = game_store + .get_mut(&name) + .unwrap_or_else(|| panic!("Game {} does not exist.", name)); - let game = game_store - .get_mut(&name) - .expect(&format!("No game named {}", name)); + let b = game.board.shallow_clone(); + let m = pleco::bots::MiniMaxSearcher::best_move(b, 3); - let b = game.board.shallow_clone(); - let m = pleco::bots::MiniMaxSearcher::best_move(b, 3); - - game.board.apply_move(m); + game.board.apply_move(m); + }); } #[query(name = "getFen")] fn get_fen(name: String) -> Option { - let game_store = storage::get_mut::(); - - game_store - .get(&name) - .and_then(|game| Some(game.board.fen())) + STORE.with(|game_store| { + game_store + .borrow() + .get(&name) + .and_then(|game| Some(game.board.fen())) + }) } diff --git a/examples/counter/src/counter_rs/lib.rs b/examples/counter/src/counter_rs/lib.rs index 477271bab..57c0c31d3 100644 --- a/examples/counter/src/counter_rs/lib.rs +++ b/examples/counter/src/counter_rs/lib.rs @@ -1,36 +1,32 @@ use ic_cdk::{ - api::call::{self, ManualReply}, + api::call::ManualReply, export::{candid, Principal}, }; use ic_cdk_macros::*; +use std::cell::{Cell, RefCell}; -static mut COUNTER: Option = None; -static mut OWNER: Option = None; +thread_local! { + static COUNTER: RefCell = RefCell::new(candid::Nat::from(0)); + static OWNER: Cell = Cell::new(Principal::from_slice(&[])); +} #[init] fn init() { - unsafe { - OWNER = Some(ic_cdk::api::caller()); - COUNTER = Some(candid::Nat::from(0)); - } + OWNER.with(|owner| owner.set(ic_cdk::api::caller())); } #[update] fn inc() -> () { - unsafe { - ic_cdk::println!("{:?}", OWNER); - COUNTER.as_mut().unwrap().0 += 1u64; - } + ic_cdk::println!("{:?}", OWNER.with(|owner| owner.get())); + COUNTER.with(|counter| *counter.borrow_mut() += 1u64); } #[query(manual_reply = true)] fn read() -> ManualReply { - unsafe { ManualReply::one(COUNTER.as_mut().unwrap()) } + COUNTER.with(|counter| ManualReply::one(counter)) } #[update] fn write(input: candid::Nat) -> () { - unsafe { - COUNTER.as_mut().unwrap().0 = input.0; - } + COUNTER.with(|counter| *counter.borrow_mut() = input); } diff --git a/examples/counter/src/inter2_rs/lib.rs b/examples/counter/src/inter2_rs/lib.rs index af21a22c3..8daae069b 100644 --- a/examples/counter/src/inter2_rs/lib.rs +++ b/examples/counter/src/inter2_rs/lib.rs @@ -1,5 +1,5 @@ -use ic_cdk_macros::*; use ic_cdk::export::candid; +use ic_cdk_macros::*; #[import(canister = "inter_mo")] struct CounterCanister; diff --git a/examples/counter/src/inter_rs/lib.rs b/examples/counter/src/inter_rs/lib.rs index b1104bf35..fd407bf33 100644 --- a/examples/counter/src/inter_rs/lib.rs +++ b/examples/counter/src/inter_rs/lib.rs @@ -1,5 +1,5 @@ -use ic_cdk_macros::*; use ic_cdk::export::candid; +use ic_cdk_macros::*; #[import(canister = "counter_mo")] struct CounterCanister; diff --git a/examples/profile/src/profile_rs/lib.rs b/examples/profile/src/profile_rs/lib.rs index dddca70b6..d48ae68a0 100644 --- a/examples/profile/src/profile_rs/lib.rs +++ b/examples/profile/src/profile_rs/lib.rs @@ -1,12 +1,12 @@ -use ic_cdk::storage; use ic_cdk::{ - api::call::{self, ManualReply}, + api::call::ManualReply, export::{ candid::{CandidType, Deserialize}, Principal, }, }; use ic_cdk_macros::*; +use std::cell::RefCell; use std::collections::BTreeMap; type IdStore = BTreeMap; @@ -19,54 +19,70 @@ struct Profile { pub keywords: Vec, } -#[query(name = "getSelf")] -fn get_self() -> Profile { - let id = ic_cdk::api::caller(); - let profile_store = storage::get::(); - - profile_store - .get(&id) - .cloned() - .unwrap_or_else(|| Profile::default()) +thread_local! { + static PROFILE_STORE: RefCell = RefCell::default(); + static ID_STORE: RefCell = RefCell::default(); } -#[query] -fn get(name: String) -> Profile { - let id_store = storage::get::(); - let profile_store = storage::get::(); +#[query(name = "getSelf", manual_reply = true)] +fn get_self() -> ManualReply { + let id = ic_cdk::api::caller(); + PROFILE_STORE.with(|profile_store| { + if let Some(profile) = profile_store.borrow().get(&id) { + ManualReply::one(profile) + } else { + ManualReply::one(Profile::default()) + } + }) +} - id_store - .get(&name) - .and_then(|id| profile_store.get(id).cloned()) - .unwrap_or_else(|| Profile::default()) +#[query(manual_reply = true)] +fn get(name: String) -> ManualReply { + ID_STORE.with(|id_store| { + PROFILE_STORE.with(|profile_store| { + let profile_store = profile_store.borrow(); + if let Some(profile) = id_store + .borrow() + .get(&name) + .and_then(|id| profile_store.get(id)) + { + ManualReply::one(profile) + } else { + ManualReply::one(Profile::default()) + } + }) + }) } #[update] fn update(profile: Profile) { let principal_id = ic_cdk::api::caller(); - let id_store = storage::get_mut::(); - let profile_store = storage::get_mut::(); - - id_store.insert(profile.name.clone(), principal_id.clone()); - profile_store.insert(principal_id, profile); + ID_STORE.with(|id_store| { + id_store + .borrow_mut() + .insert(profile.name.clone(), principal_id); + }); + PROFILE_STORE.with(|profile_store| { + profile_store.borrow_mut().insert(principal_id, profile); + }); } #[query(manual_reply = true)] fn search(text: String) -> ManualReply> { let text = text.to_lowercase(); - let profile_store = storage::get::(); - - for (_, p) in profile_store.iter() { - if p.name.to_lowercase().contains(&text) || p.description.to_lowercase().contains(&text) { - return ManualReply::one(Some(p)); - } - - for x in p.keywords.iter() { - if x.to_lowercase() == text { + PROFILE_STORE.with(|profile_store| { + for (_, p) in profile_store.borrow().iter() { + if p.name.to_lowercase().contains(&text) || p.description.to_lowercase().contains(&text) + { return ManualReply::one(Some(p)); } - } - } - ManualReply::one(None::) + for x in p.keywords.iter() { + if x.to_lowercase() == text { + return ManualReply::one(Some(p)); + } + } + } + ManualReply::one(None::) + }) } diff --git a/src/ic-cdk/src/storage.rs b/src/ic-cdk/src/storage.rs index 69dcc3521..ada5f4d4b 100644 --- a/src/ic-cdk/src/storage.rs +++ b/src/ic-cdk/src/storage.rs @@ -1,53 +1,5 @@ -//! Tools for managing storage of data types in canister. -//! -//! Each data type `T` will have one storage for it. +//! Tools for managing stable storage of data in a canister. use crate::api::stable; -use std::any::{Any, TypeId}; -use std::collections::BTreeMap; - -type StorageTree = BTreeMap>; - -static mut STORAGE: Option = None; - -fn storage() -> &'static mut StorageTree { - unsafe { - if let Some(s) = &mut STORAGE { - s - } else { - STORAGE = Some(BTreeMap::new()); - storage() - } - } -} - -/// Deletes the storage. -pub fn delete() -> bool { - let type_id = std::any::TypeId::of::(); - - storage().remove(&type_id).is_some() -} - -/// Returns a mutable reference of the storage. -/// -/// This will create the storage if it doesn't exist. -pub fn get_mut() -> &'static mut T { - let type_id = std::any::TypeId::of::(); - - let store = storage(); - - store - .entry(type_id) - .or_insert_with(|| Box::new(T::default())) - .downcast_mut() - .expect("Unexpected value of invalid type.") -} - -/// Returns a share reference of the storage. -/// -/// This will create the storage if it doesn't exist. -pub fn get() -> &'static T { - get_mut::() -} /// Saves the storage into the stable memory. /// From 5a0206ba76666c293d1fec8a5383de0fa7422c6a Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Thu, 24 Feb 2022 17:11:26 +0100 Subject: [PATCH 023/234] fix: do not call done() in stable_restore() (#216) This change removes the call to decoder.done() in stable_restore(). Rationale: * done() almost always returns an error because the input is likely to contain trailing zero bytes. * Calling done() has no effect on the return value. * The error that done() constructs contains the dump of the whole state, which causes the decoder to allocate huge amounts of memory. All of these allocations are unnecessary because stable_restore() throws away the error right away. Fixes #212. --- src/ic-cdk/src/storage.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ic-cdk/src/storage.rs b/src/ic-cdk/src/storage.rs index ada5f4d4b..fe8d81451 100644 --- a/src/ic-cdk/src/storage.rs +++ b/src/ic-cdk/src/storage.rs @@ -23,8 +23,5 @@ where let mut de = candid::de::IDLDeserialize::new(bytes.as_slice()).map_err(|e| format!("{:?}", e))?; let res = candid::utils::ArgumentDecoder::decode(&mut de).map_err(|e| format!("{:?}", e))?; - // The idea here is to ignore an error that comes from Candid, because we have trailing - // bytes. - let _ = de.done(); Ok(res) } From 9fa30051c80bb5326315870d9f51b2bd779a36da Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Fri, 25 Feb 2022 17:02:05 +0000 Subject: [PATCH 024/234] Take slice rather than owned Vec as input arg (#217) --- src/ic-cdk/src/api/call.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 34cbf4246..affb3c51d 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -220,7 +220,7 @@ fn callback(state_ptr: *const InnerCell>>) { pub fn call_raw( id: Principal, method: &str, - args_raw: Vec, + args_raw: &[u8], payment: u64, ) -> impl Future>> { let callee = id.as_slice(); @@ -266,7 +266,7 @@ pub async fn call ArgumentDecoder<'a>>( args: T, ) -> CallResult { let args_raw = encode_args(args).expect("Failed to encode arguments."); - let bytes = call_raw(id, method, args_raw, 0).await?; + let bytes = call_raw(id, method, &args_raw, 0).await?; decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) } @@ -278,7 +278,7 @@ pub async fn call_with_payment ArgumentDecoder<'a cycles: u64, ) -> CallResult { let args_raw = encode_args(args).expect("Failed to encode arguments."); - let bytes = call_raw(id, method, args_raw, cycles).await?; + let bytes = call_raw(id, method, &args_raw, cycles).await?; decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) } From dfb6889db8efdcd3a82195fc9df495c261241878 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 8 Mar 2022 16:19:48 -0500 Subject: [PATCH 025/234] chore: add CHANGELOG files (#220) * Add ic-cdk changelog * Add ic-certified-assets changelog * Add ic-cdk-optimizer changelog --- src/ic-cdk-optimizer/CHANGELOG.md | 13 ++++++++++++ src/ic-cdk/CHANGELOG.md | 31 ++++++++++++++++++++++++++++ src/ic-certified-assets/CHANGELOG.md | 11 ++++++++++ 3 files changed, 55 insertions(+) create mode 100644 src/ic-cdk-optimizer/CHANGELOG.md create mode 100644 src/ic-cdk/CHANGELOG.md create mode 100644 src/ic-certified-assets/CHANGELOG.md diff --git a/src/ic-cdk-optimizer/CHANGELOG.md b/src/ic-cdk-optimizer/CHANGELOG.md new file mode 100644 index 000000000..8a05fa981 --- /dev/null +++ b/src/ic-cdk-optimizer/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] +### Changed +- Update clap to 3.1 (#209) + +## [0.3.4] - 2022-02-07 +### Fixed +- Actually print version with --version (#196) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md new file mode 100644 index 000000000..2022bec2b --- /dev/null +++ b/src/ic-cdk/CHANGELOG.md @@ -0,0 +1,31 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] +### Changed +- Take slice rather than owned Vec as input arg (#217) +- Remove non-stable storage API (#215) +- Allow configuring export macros to not reply (#210) +- Add Clone and Copy to RejectionCode (#202) + +### Fixed +- Do not call done() in stable_restore() (#216) +- Remove out-of-bounds vulnerability (#208) + +## [0.4.0] - 2022-01-26 +### Changed +- `candid` is required to be included in `[dependencies]` to use the `#[import]` macro (#190) +- Deprecate block_on in favour of the new spawn function (#189) +- Trap in setup panic hook (#172) + +## [0.3.3] - 2021-11-17 +### Added +- Update system API for 128 bit cycles (#167) + +## [0.3.2] - 2021-09-16 +### Added +- Add support for 64 bit stable memory (#137) +- Add support for 'heartbeat' and 'inspect_message' (#129) diff --git a/src/ic-certified-assets/CHANGELOG.md b/src/ic-certified-assets/CHANGELOG.md new file mode 100644 index 000000000..8de61aba1 --- /dev/null +++ b/src/ic-certified-assets/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.0] - 2022-02-02 +### Added +- First release From 63a81d19e3b96c9d7132966143cac5f23165defa Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Fri, 11 Mar 2022 12:53:37 -0800 Subject: [PATCH 026/234] Update manifest metadata (#222) * Update manifest metadata --- src/ic-cdk-macros/Cargo.toml | 3 ++- src/ic-cdk-optimizer/Cargo.toml | 3 ++- src/ic-cdk/Cargo.toml | 3 ++- src/ic-certified-assets/Cargo.toml | 2 ++ src/ic-certified-map/Cargo.toml | 3 ++- src/ic-ledger-types/Cargo.toml | 2 ++ 6 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index c387fbd1f..daa900238 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -8,9 +8,10 @@ homepage = "https://docs.rs/ic-cdk-macros" documentation = "https://docs.rs/ic-cdk-macros" license = "Apache-2.0" readme = "README.md" -categories = ["api-bindings", "data-structures", "no-std"] +categories = ["api-bindings", "data-structures", "no-std", "development-tools::ffi"] keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] +repository = "https://github.com/dfinity/cdk-rs" [lib] proc-macro = true diff --git a/src/ic-cdk-optimizer/Cargo.toml b/src/ic-cdk-optimizer/Cargo.toml index af6cfd0d9..6fbbe6c11 100644 --- a/src/ic-cdk-optimizer/Cargo.toml +++ b/src/ic-cdk-optimizer/Cargo.toml @@ -8,9 +8,10 @@ homepage = "https://docs.rs/ic-cdk-optimizer" documentation = "https://docs.rs/ic-cdk-optimizer" license = "Apache-2.0" readme = "README.md" -categories = ["api-bindings", "data-structures", "no-std", "command-line-utilities"] +categories = ["api-bindings", "data-structures", "no-std", "command-line-utilities", "wasm"] keywords = ["internet-computer", "dfinity", "canister", "cli", "optimizer"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] +repository = "https://github.com/dfinity/cdk-rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 8aa2a4df6..674c544df 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -8,9 +8,10 @@ homepage = "https://docs.rs/ic-cdk" documentation = "https://docs.rs/ic-cdk" license = "Apache-2.0" readme = "README.md" -categories = ["api-bindings", "data-structures", "no-std"] +categories = ["api-bindings", "data-structures", "no-std", "development-tools::ffi"] keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] +repository = "https://github.com/dfinity/cdk-rs" [dependencies] candid = "0.7.4" diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml index e79370b4a..b95074849 100644 --- a/src/ic-certified-assets/Cargo.toml +++ b/src/ic-certified-assets/Cargo.toml @@ -6,6 +6,8 @@ authors = ["DFINITY Stiftung "] description = "Rust support for asset certification." license = "Apache-2.0" keywords = ["internet-computer", "dfinity"] +categories = ["wasm", "filesystem", "data-structures"] +repository = "https://github.com/dfinity/cdk-rs" [dependencies] base64 = "0.13" diff --git a/src/ic-certified-map/Cargo.toml b/src/ic-certified-map/Cargo.toml index ba2449265..15ac8658b 100644 --- a/src/ic-certified-map/Cargo.toml +++ b/src/ic-certified-map/Cargo.toml @@ -8,9 +8,10 @@ homepage = "https://docs.rs/ic-certified-map" documentation = "https://docs.rs/ic-certified-map" license = "Apache-2.0" readme = "README.md" -categories = ["data-structures"] +categories = ["data-structures", "cryptography", "cryptography::cryptocurrencies"] keywords = ["internet-computer", "types", "dfinity", "map"] include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"] +repository = "https://github.com/dfinity/cdk-rs" [dependencies] serde = "1" diff --git a/src/ic-ledger-types/Cargo.toml b/src/ic-ledger-types/Cargo.toml index ee86fe7be..59e1167c3 100644 --- a/src/ic-ledger-types/Cargo.toml +++ b/src/ic-ledger-types/Cargo.toml @@ -9,7 +9,9 @@ documentation = "https://docs.rs/ic-ledger-types" license = "Apache-2.0" readme = "README.md" keywords = ["internet-computer", "ledger"] +categories = ["cryptography::cryptocurrencies", "data-structures"] include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"] +repository = "https://github.com/dfinity/cdk-rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 0759a2846ac5066887aeefc78d98fce019c30375 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Tue, 15 Mar 2022 13:08:57 -0700 Subject: [PATCH 027/234] feat: Redirect the uncertified mainnet endpoint to the certified one (#223) * Redirect the uncertified mainnet endpoint to the certified one * fmt * Move to function and add tests * fmt+lint * Handle query parameter * Move unit tests to dedicated module * Handle conditions separately --- src/ic-certified-assets/src/lib.rs | 39 ++++++++++-------- src/ic-certified-assets/src/tests.rs | 61 ++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 src/ic-certified-assets/src/tests.rs diff --git a/src/ic-certified-assets/src/lib.rs b/src/ic-certified-assets/src/lib.rs index db55151fc..86136160b 100644 --- a/src/ic-certified-assets/src/lib.rs +++ b/src/ic-certified-assets/src/lib.rs @@ -1,4 +1,6 @@ mod rc_bytes; +#[cfg(test)] +mod tests; use crate::rc_bytes::RcBytes; use ic_cdk::api::{caller, data_certificate, set_certified_data, time, trap}; @@ -665,23 +667,16 @@ fn url_decode(url: &str) -> Result { .collect() } -#[test] -fn check_url_decode() { - assert_eq!( - url_decode("/%"), - Err(UrlDecodeError::InvalidPercentEncoding) - ); - assert_eq!(url_decode("/%%"), Ok("/%".to_string())); - assert_eq!(url_decode("/%20a"), Ok("/ a".to_string())); - assert_eq!( - url_decode("/%%+a%20+%@"), - Err(UrlDecodeError::InvalidPercentEncoding) - ); - assert_eq!( - url_decode("/has%percent.txt"), - Err(UrlDecodeError::InvalidPercentEncoding) - ); - assert_eq!(url_decode("/%e6"), Ok("/æ".to_string())); +fn redirect_to_url(host: &str, url: &str) -> Option { + if let Some(host) = host.split(':').next() { + let host = host.trim(); + if host == "raw.ic0.app" { + return Some(format!("https://ic0.app{}", url)); + } else if let Some(base) = host.strip_suffix(".raw.ic0.app") { + return Some(format!("https://{}.ic0.app{}", base, url)); + } + } + None } #[query] @@ -693,6 +688,16 @@ fn http_request(req: HttpRequest) -> HttpResponse { encodings.push(v.trim().to_string()); } } + if name.eq_ignore_ascii_case("Host") { + if let Some(replacement_url) = redirect_to_url(value, &req.url) { + return HttpResponse { + status_code: 308, + headers: vec![("Location".to_string(), replacement_url)], + body: RcBytes::from(ByteBuf::default()), + streaming_strategy: None, + }; + } + } } encodings.push("identity".to_string()); diff --git a/src/ic-certified-assets/src/tests.rs b/src/ic-certified-assets/src/tests.rs new file mode 100644 index 000000000..c775de9fd --- /dev/null +++ b/src/ic-certified-assets/src/tests.rs @@ -0,0 +1,61 @@ +use crate::*; + +use std::panic::catch_unwind; + +#[test] +fn check_url_decode() { + assert_eq!( + url_decode("/%"), + Err(UrlDecodeError::InvalidPercentEncoding) + ); + assert_eq!(url_decode("/%%"), Ok("/%".to_string())); + assert_eq!(url_decode("/%20a"), Ok("/ a".to_string())); + assert_eq!( + url_decode("/%%+a%20+%@"), + Err(UrlDecodeError::InvalidPercentEncoding) + ); + assert_eq!( + url_decode("/has%percent.txt"), + Err(UrlDecodeError::InvalidPercentEncoding) + ); + assert_eq!(url_decode("/%e6"), Ok("/æ".to_string())); +} + +#[test] +fn redirects_cleanly() { + fn fake(host: &str) -> HttpRequest { + HttpRequest { + body: ByteBuf::new(), + headers: vec![("Host".to_string(), host.to_string())], + method: "GET".to_string(), + url: "/asset.blob".to_string(), + } + } + fn assert_308(resp: &HttpResponse, expected: &str) { + assert_eq!(resp.status_code, 308); + assert!(resp + .headers + .iter() + .any(|(key, value)| key == "Location" && value == expected)); + } + assert_308( + &http_request(fake("aaaaa-aa.raw.ic0.app")), + "https://aaaaa-aa.ic0.app/asset.blob", + ); + assert_308( + &http_request(fake("my.http.files.raw.ic0.app")), + "https://my.http.files.ic0.app/asset.blob", + ); + assert_308( + &http_request(fake("raw.ic0.app.raw.ic0.app")), + "https://raw.ic0.app.ic0.app/asset.blob", + ); + assert_308( + &http_request(fake("raw.ic0.app")), // for ?canisterId= + "https://ic0.app/asset.blob", + ); + let no_redirect = catch_unwind(|| http_request(fake("raw.ic0.app.ic0.app")).status_code); + assert!(!matches!(no_redirect, Ok(308))); + let no_redirect2 = catch_unwind(|| http_request(fake("straw.ic0.app")).status_code); + assert!(!matches!(no_redirect2, Ok(308))); +} From 3bbbd309dc7ff2e54b55907336db39c284b981ba Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 15 Mar 2022 18:05:08 -0400 Subject: [PATCH 028/234] docs: guard attribute of all export macros (#225) * doc: guard attribute of all export macros * Fix link to reply * Lowercase error --- src/ic-cdk-macros/src/lib.rs | 116 ++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 2 deletions(-) diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index f63cdc8d8..8fba9a2c9 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -90,6 +90,22 @@ where /// } /// ``` /// +/// You can specify a guard function to be executed before the query function. +/// When the guard function returns an error, the query function will not proceed. +/// +/// ```rust +/// # use ic_cdk_macros::*; +/// fn guard_function() -> Result<(), String> { +/// // ... +/// # unimplemented!() +/// } +/// #[query(guard = "guard_function")] +/// fn query_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// /// If you would rather call the [`call::reply`] function than return a value, /// you will need to set `manual_reply` to `true` so that the canister does not /// trap. @@ -106,7 +122,7 @@ where /// } /// ``` /// -/// [`reply`]: ic_cdk::api::call::reply +/// [`call::reply`]: ic_cdk::api::call::reply #[proc_macro_attribute] pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_query, "ic_query", attr, item) @@ -139,6 +155,22 @@ pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { /// } /// ``` /// +/// You can specify a guard function to be executed before the update function. +/// When the guard function returns an error, the update function will not proceed. +/// +/// ```rust +/// # use ic_cdk_macros::*; +/// fn guard_function() -> Result<(), String> { +/// // ... +/// # unimplemented!() +/// } +/// #[update(guard = "guard_function")] +/// fn update_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// /// If you would rather call the [`call::reply`] function than return a value, /// you will need to set `manual_reply` to `true` so that the canister does not /// trap. @@ -155,7 +187,7 @@ pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { /// } /// ``` /// -/// [`reply`]: ic_cdk::api::call::reply +/// [`call::reply`]: ic_cdk::api::call::reply #[proc_macro_attribute] pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_update, "ic_update", attr, item) @@ -180,6 +212,22 @@ pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream { /// # unimplemented!() /// } /// ``` +/// +/// You can specify a guard function to be executed before the init function. +/// When the guard function returns an error, the init function will not proceed. +/// +/// ```rust +/// # use ic_cdk_macros::*; +/// fn guard_function() -> Result<(), String> { +/// // ... +/// # unimplemented!() +/// } +/// #[init(guard = "guard_function")] +/// fn init_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` #[proc_macro_attribute] pub fn init(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_init, "ic_init", attr, item) @@ -204,6 +252,22 @@ pub fn init(attr: TokenStream, item: TokenStream) -> TokenStream { /// # unimplemented!() /// } /// ``` +/// +/// You can specify a guard function to be executed before the pre_upgrade function. +/// When the guard function returns an error, the pre_upgrade function will not proceed. +/// +/// ```rust +/// # use ic_cdk_macros::*; +/// fn guard_function() -> Result<(), String> { +/// // ... +/// # unimplemented!() +/// } +/// #[pre_upgrade(guard = "guard_function")] +/// fn pre_upgrade_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` #[proc_macro_attribute] pub fn pre_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_pre_upgrade, "ic_pre_upgrade", attr, item) @@ -228,6 +292,22 @@ pub fn pre_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { /// # unimplemented!() /// } /// ``` +/// +/// You can specify a guard function to be executed before the post_upgrade function. +/// When the guard function returns an error, the post_upgrade function will not proceed. +/// +/// ```rust +/// # use ic_cdk_macros::*; +/// fn guard_function() -> Result<(), String> { +/// // ... +/// # unimplemented!() +/// } +/// #[post_upgrade(guard = "guard_function")] +/// fn post_upgrade_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` #[proc_macro_attribute] pub fn post_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_post_upgrade, "ic_post_upgrade", attr, item) @@ -252,6 +332,22 @@ pub fn post_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { /// # unimplemented!() /// } /// ``` +/// +/// You can specify a guard function to be executed before the heartbeat function. +/// When the guard function returns an error, the heartbeat function will not proceed. +/// +/// ```rust +/// # use ic_cdk_macros::*; +/// fn guard_function() -> Result<(), String> { +/// // ... +/// # unimplemented!() +/// } +/// #[heartbeat(guard = "guard_function")] +/// fn heartbeat_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` #[proc_macro_attribute] pub fn heartbeat(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_heartbeat, "ic_heartbeat", attr, item) @@ -276,6 +372,22 @@ pub fn heartbeat(attr: TokenStream, item: TokenStream) -> TokenStream { /// # unimplemented!() /// } /// ``` +/// +/// You can specify a guard function to be executed before the inspect_message function. +/// When the guard function returns an error, the inspect_message function will not proceed. +/// +/// ```rust +/// # use ic_cdk_macros::*; +/// fn guard_function() -> Result<(), String> { +/// // ... +/// # unimplemented!() +/// } +/// #[inspect_message(guard = "guard_function")] +/// fn inspect_message_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` #[proc_macro_attribute] pub fn inspect_message(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_inspect_message, "ic_inspect_message", attr, item) From a44316600ec1fd918567facd8aa4a650ef765228 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Thu, 17 Mar 2022 15:13:52 -0700 Subject: [PATCH 029/234] feat: Implement remaining 128-bit functions (#228) * Add remaining 128-bit functions * Make canister_balance128 behave the same way * Update changelog --- src/ic-cdk/CHANGELOG.md | 3 ++ src/ic-cdk/src/api.rs | 9 ++-- src/ic-cdk/src/api/call.rs | 87 +++++++++++++++++++++++++++++++++++--- 3 files changed, 89 insertions(+), 10 deletions(-) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 2022bec2b..84d14ca8c 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Update canister calling API for 128-bit cycles (#228) + ### Changed - Take slice rather than owned Vec as input arg (#217) - Remove non-stable storage API (#215) diff --git a/src/ic-cdk/src/api.rs b/src/ic-cdk/src/api.rs index b6fbe095e..14199c317 100644 --- a/src/ic-cdk/src/api.rs +++ b/src/ic-cdk/src/api.rs @@ -1,6 +1,6 @@ //! System API and low level functions for it. use crate::export::Principal; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryFrom; pub mod call; pub mod stable; @@ -55,10 +55,9 @@ pub fn canister_balance() -> u64 { /// Get the amount of funds available in the canister. pub fn canister_balance128() -> u128 { - let size = 16; - let mut buf = vec![0u8; size]; - unsafe { ic0::canister_cycle_balance128(buf.as_mut_ptr() as i32) } - u128::from_le_bytes(buf.try_into().unwrap()) + let mut recv = 0u128; + unsafe { ic0::canister_cycle_balance128(&mut recv as *mut u128 as i32) } + recv } /// Sets the certified data of this canister. diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index affb3c51d..ee16f0821 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -222,6 +222,39 @@ pub fn call_raw( method: &str, args_raw: &[u8], payment: u64, +) -> impl Future>> { + call_raw_internal(id, method, args_raw, move || { + if payment > 0 { + unsafe { + ic0::call_cycles_add(payment as i64); + } + } + }) +} + +/// Similar to `call128`, but without serialization. +pub fn call_raw128( + id: Principal, + method: &str, + args_raw: &[u8], + payment: u128, +) -> impl Future>> { + call_raw_internal(id, method, args_raw, move || { + if payment > 0 { + unsafe { + let high = (payment >> 64) as u64; + let low = (payment & u64::MAX as u128) as u64; + ic0::call_cycles_add128(high as i64, low as i64); + } + } + }) +} + +fn call_raw_internal( + id: Principal, + method: &str, + args_raw: &[u8], + payment_func: impl FnOnce(), ) -> impl Future>> { let callee = id.as_slice(); let state = WasmCell::new(CallFutureState { @@ -242,9 +275,7 @@ pub fn call_raw( ); ic0::call_data_append(args_raw.as_ptr() as i32, args_raw.len() as i32); - if payment > 0 { - ic0::call_cycles_add(payment as i64); - } + payment_func(); ic0::call_perform() }; @@ -270,7 +301,7 @@ pub async fn call ArgumentDecoder<'a>>( decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) } -/// Performs an asynchronous call to another canister and pay cycles at the same time +/// Performs an asynchronous call to another canister and pay cycles at the same time. pub async fn call_with_payment ArgumentDecoder<'a>>( id: Principal, method: &str, @@ -282,6 +313,18 @@ pub async fn call_with_payment ArgumentDecoder<'a decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) } +/// Performs an asynchronous call to another canister and pay cycles at the same time. +pub async fn call_with_payment128 ArgumentDecoder<'a>>( + id: Principal, + method: &str, + args: T, + cycles: u128, +) -> CallResult { + let args_raw = encode_args(args).expect("Failed to encode arguments."); + let bytes = call_raw128(id, method, &args_raw, cycles).await?; + decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) +} + /// Returns a result that maps over the call /// /// It will be Ok(T) if the call succeeded (with T being the arg_data), @@ -348,6 +391,16 @@ pub fn msg_cycles_available() -> u64 { unsafe { ic0::msg_cycles_available() as u64 } } +/// Returns the amount of cycles that were transferred by the caller +/// of the current call, and is still available in this message. +pub fn msg_cycles_available128() -> u128 { + let mut recv = 0u128; + unsafe { + ic0::msg_cycles_available128(&mut recv as *mut u128 as i32); + } + recv +} + /// Returns the amount of cycles that came back with the response as a refund. /// /// The refund has already been added to the canister balance automatically. @@ -355,14 +408,38 @@ pub fn msg_cycles_refunded() -> u64 { unsafe { ic0::msg_cycles_refunded() as u64 } } +/// Returns the amount of cycles that came back with the response as a refund. +/// +/// The refund has already been added to the canister balance automatically. +pub fn msg_cycles_refunded128() -> u128 { + let mut recv = 0u128; + unsafe { + ic0::msg_cycles_refunded128(&mut recv as *mut u128 as i32); + } + recv +} + /// Moves cycles from the call to the canister balance. /// -/// The actual amounts moved will be returned +/// The actual amount moved will be returned. pub fn msg_cycles_accept(max_amount: u64) -> u64 { // TODO: should we assert the u64 input is within the range of i64? unsafe { ic0::msg_cycles_accept(max_amount as i64) as u64 } } +/// Moves cycles from the call to the canister balance. +/// +/// The actual amount moved will be returned. +pub fn msg_cycles_accept128(max_amount: u128) -> u128 { + let high = (max_amount >> 64) as u64; + let low = (max_amount & u64::MAX as u128) as u64; + let mut recv = 0u128; + unsafe { + ic0::msg_cycles_accept128(high as i64, low as i64, &mut recv as *mut u128 as i32); + } + recv +} + /// Returns the argument data as bytes. pub(crate) unsafe fn arg_data_raw() -> Vec { let len: usize = ic0::msg_arg_data_size() as usize; From ac3c9657971cb786b1c8b38945eddd153a924018 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Mon, 21 Mar 2022 09:40:27 -0700 Subject: [PATCH 030/234] feat: Add stdin param and auto-select output file (#230) * Add stdin param and auto-select output file --- src/ic-cdk-optimizer/CHANGELOG.md | 4 ++++ src/ic-cdk-optimizer/src/main.rs | 27 +++++++++++++++++---------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/ic-cdk-optimizer/CHANGELOG.md b/src/ic-cdk-optimizer/CHANGELOG.md index 8a05fa981..15c6a3f77 100644 --- a/src/ic-cdk-optimizer/CHANGELOG.md +++ b/src/ic-cdk-optimizer/CHANGELOG.md @@ -5,8 +5,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Specifying `-` as the input or output argument refers to stdin or stdout respectively (#230) + ### Changed - Update clap to 3.1 (#209) +- The output argument defaults to the input argument if unspecified (#230) ## [0.3.4] - 2022-02-07 ### Fixed diff --git a/src/ic-cdk-optimizer/src/main.rs b/src/ic-cdk-optimizer/src/main.rs index 88dd59465..7d11301e8 100644 --- a/src/ic-cdk-optimizer/src/main.rs +++ b/src/ic-cdk-optimizer/src/main.rs @@ -1,26 +1,27 @@ use clap::Parser; use humansize::{file_size_opts, FileSize}; -use std::io::Read; -use std::path::PathBuf; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; mod passes; #[derive(Parser, Debug)] #[clap(version)] struct CommandLineOpts { - /// Input file to optimize. By default will use STDIN. - input: Option, + /// Input file to optimize. By default, or if "-", will use STDIN. + #[clap(default_value("-"))] + input: PathBuf, - /// Output file. Required. + /// Output file. If unset, the original file will be overwritten. If "-", or if unset and the original was passed via STDIN, the result will go to STDOUT. #[clap(short, long)] - output: PathBuf, + output: Option, } fn main() { let passes = passes::create(); let opts = CommandLineOpts::parse(); - let content = if let Some(i) = opts.input { - std::fs::read(&i).expect("Could not read the file.") + let content = if opts.input != Path::new("-") { + std::fs::read(&opts.input).expect("Could not read the file.") } else { let mut buff = Vec::new(); std::io::stdin() @@ -59,6 +60,12 @@ fn main() { wasm_back.len().file_size(file_size_opts::BINARY).unwrap(), (1.0 - ((wasm_back.len() as f64) / (original_wasm_size as f64))) * 100.0 ); - - std::fs::write(opts.output, wasm_back).expect("Could not write output file."); + let outfile = opts.output.unwrap_or(opts.input); + if outfile == Path::new("-") { + std::io::stdout() + .write_all(&wasm_back) + .expect("Could not write output."); + } else { + std::fs::write(outfile, wasm_back).expect("Could not write output file."); + } } From fbfe6eb494faf2fa73669eb4fa17752fa3e6251b Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 22 Mar 2022 13:29:35 -0400 Subject: [PATCH 031/234] chore: Add PR template (#231) * chore: Add PR template * fmt --- .github/PULL_REQUEST_TEMPLATE.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..bfd5ec903 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +# Description + +Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. + +Fixes # (issue) + +# How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration. + +# Checklist: + +- [ ] The title of this PR complies with [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). +- [ ] I have edited the CHANGELOG accordingly. +- [ ] I have made corresponding changes to the documentation. From 4147564ebb435f5e479e2201fbd7614209d154c3 Mon Sep 17 00:00:00 2001 From: Nicolas Mattia Date: Thu, 24 Mar 2022 16:52:06 +0100 Subject: [PATCH 032/234] docs: Add example of using init args (#234) This adds an example and quick explanation of how arguments are dealt with in the `init` macro. --- src/ic-cdk-macros/src/lib.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index 8fba9a2c9..0996e85ef 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -228,6 +228,27 @@ pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream { /// # unimplemented!() /// } /// ``` +/// +/// The init function may accept an argument, if that argument is a `CandidType`: +/// +/// ```rust +/// # use ic_cdk_macros::*; +/// +/// #[derive(Clone, Debug, CandidType, Deserialize)] +/// struct InitArg { +/// foo: u8, +/// } +/// +/// #[init] +/// fn init_function(arg: InitArg) { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// +/// In this case, the argument will be read from `ic0.msg_arg_data_size/copy` and passed to the +/// init function upon successful deserialization. +/// Refer to the [`canister_init` Specification](https://smartcontracts.org/docs/interface-spec/index.html#system-api-init) for more information. #[proc_macro_attribute] pub fn init(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_init, "ic_init", attr, item) From 095be3b43e99404a78c6a300e76cc6838b373298 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Mon, 28 Mar 2022 14:03:31 -0700 Subject: [PATCH 033/234] feat: Add cleanup code in case of await trap (#232) * Add cleanup code in case of await trap * fmt Co-authored-by: Linwei Shang --- src/ic-cdk/src/api/call.rs | 24 ++++++++++++++++++++++++ src/ic-cdk/src/futures.rs | 20 ++++++++++++++------ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index ee16f0821..26fdf30c8 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -7,6 +7,7 @@ use serde::ser::Error; use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; +use std::sync::atomic::Ordering; use std::task::{Context, Poll, Waker}; #[cfg(target_arch = "wasm32-unknown-unknown")] @@ -216,6 +217,28 @@ fn callback(state_ptr: *const InnerCell>>) { } } +/// This function is called when [callback] was just called with the same parameter, and trapped. +/// We can't guarantee internal consistency at this point, but we can at least e.g. drop mutex guards. +/// Waker is a very opaque API, so the best we can do is set a global flag and proceed normally. +fn cleanup(state_ptr: *const InnerCell>>) { + let state = unsafe { WasmCell::from_raw(state_ptr) }; + // We set the call result, even though it won't be read on the default executor, because we can't guarantee it was called on our executor. + // None of these calls trap - the rollback from the previous trap ensures that the Mutex is not in a poisoned state. + { + state.borrow_mut().result = Some(match reject_code() { + RejectionCode::NoError => unsafe { Ok(arg_data_raw()) }, + n => Err((n, reject_message())), + }); + } + let w = state.borrow_mut().waker.take(); + if let Some(waker) = w { + // Flag that we do not want to actually wake the task - we want to drop it *without* executing it. + crate::futures::CLEANUP.store(true, Ordering::Relaxed); + waker.wake(); + crate::futures::CLEANUP.store(false, Ordering::Relaxed); + } +} + /// Similar to `call`, but without serialization. pub fn call_raw( id: Principal, @@ -276,6 +299,7 @@ fn call_raw_internal( ic0::call_data_append(args_raw.as_ptr() as i32, args_raw.len() as i32); payment_func(); + ic0::call_on_cleanup(cleanup as usize as i32, state_ptr as i32); ic0::call_perform() }; diff --git a/src/ic-cdk/src/futures.rs b/src/ic-cdk/src/futures.rs index b145c491c..8da3896a1 100644 --- a/src/ic-cdk/src/futures.rs +++ b/src/ic-cdk/src/futures.rs @@ -1,5 +1,6 @@ use std::future::Future; use std::pin::Pin; +use std::sync::atomic::AtomicBool; use std::task::Context; /// Must be called on every top-level future corresponding to a method call of a @@ -36,6 +37,8 @@ pub fn spawn>(future: F) { } } +pub(crate) static CLEANUP: AtomicBool = AtomicBool::new(false); + // This module contains the implementation of a waker we're using for waking // top-level futures (the ones returned by canister methods). The waker polls // the future once and re-pins it on the heap, if it's pending. If the future is @@ -44,7 +47,10 @@ pub fn spawn>(future: F) { // waker was used as intended. mod waker { use super::*; - use std::task::{RawWaker, RawWakerVTable, Waker}; + use std::{ + sync::atomic::Ordering, + task::{RawWaker, RawWakerVTable, Waker}, + }; type FuturePtr = *mut dyn Future; static MY_VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); @@ -61,16 +67,18 @@ mod waker { // Then, the waker will restore the future from the pointer we passed into the // waker inside the `kickstart` method and poll the future again. If the future // is pending, we leave it on the heap. If it's ready, we deallocate the - // pointer. + // pointer. If CLEANUP is set, then we're recovering from a callback trap, and + // want to drop the future without executing any more of it. unsafe fn wake(ptr: *const ()) { let boxed_future_ptr_ptr = Box::from_raw(ptr as *mut FuturePtr); let future_ptr: FuturePtr = *boxed_future_ptr_ptr; let boxed_future = Box::from_raw(future_ptr); let mut pinned_future = Pin::new_unchecked(&mut *future_ptr); - if pinned_future - .as_mut() - .poll(&mut Context::from_waker(&waker::waker(ptr))) - .is_pending() + if !super::CLEANUP.load(Ordering::Relaxed) + && pinned_future + .as_mut() + .poll(&mut Context::from_waker(&waker::waker(ptr))) + .is_pending() { Box::into_raw(boxed_future_ptr_ptr); Box::into_raw(boxed_future); From c0522afb8a0c6e061c2e7a0da86ef9c00d29d156 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Tue, 29 Mar 2022 09:35:57 -0700 Subject: [PATCH 034/234] fix: Run inter-canister calls without awaiting (#233) * Change async fns to async blocks * Update changelog Co-authored-by: Linwei Shang --- src/ic-cdk/CHANGELOG.md | 1 + src/ic-cdk/src/api/call.rs | 33 +++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 84d14ca8c..329a5fec8 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Do not call done() in stable_restore() (#216) - Remove out-of-bounds vulnerability (#208) +- Run inter-canister calls without awaiting (#233) ## [0.4.0] - 2022-01-26 ### Changed diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 26fdf30c8..4b8e275cf 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -315,38 +315,47 @@ fn call_raw_internal( } /// Performs an asynchronous call to another canister via ic0. -pub async fn call ArgumentDecoder<'a>>( +pub fn call ArgumentDecoder<'a>>( id: Principal, method: &str, args: T, -) -> CallResult { +) -> impl Future> { let args_raw = encode_args(args).expect("Failed to encode arguments."); - let bytes = call_raw(id, method, &args_raw, 0).await?; - decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) + let fut = call_raw(id, method, &args_raw, 0); + async { + let bytes = fut.await?; + decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) + } } /// Performs an asynchronous call to another canister and pay cycles at the same time. -pub async fn call_with_payment ArgumentDecoder<'a>>( +pub fn call_with_payment ArgumentDecoder<'a>>( id: Principal, method: &str, args: T, cycles: u64, -) -> CallResult { +) -> impl Future> { let args_raw = encode_args(args).expect("Failed to encode arguments."); - let bytes = call_raw(id, method, &args_raw, cycles).await?; - decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) + let fut = call_raw(id, method, &args_raw, cycles); + async { + let bytes = fut.await?; + decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) + } } /// Performs an asynchronous call to another canister and pay cycles at the same time. -pub async fn call_with_payment128 ArgumentDecoder<'a>>( +pub fn call_with_payment128 ArgumentDecoder<'a>>( id: Principal, method: &str, args: T, cycles: u128, -) -> CallResult { +) -> impl Future> { let args_raw = encode_args(args).expect("Failed to encode arguments."); - let bytes = call_raw128(id, method, &args_raw, cycles).await?; - decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) + let fut = call_raw128(id, method, &args_raw, cycles); + async { + let bytes = fut.await?; + decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) + } } /// Returns a result that maps over the call From fa0b1362919a25af9e99363b3c1cf723a90f131f Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 29 Mar 2022 13:25:28 -0400 Subject: [PATCH 035/234] chore: release cdk 0.5.0 (#236) * chore: bump up cdk to 0.5.0 * changelog * readme --- README.md | 4 ++-- docs/modules/rust-guide/pages/rust-profile.adoc | 4 ++-- docs/modules/rust-guide/pages/rust-quickstart.adoc | 4 ++-- examples/asset_storage/src/asset_storage_rs/Cargo.toml | 4 ++-- examples/chess/src/chess_rs/Cargo.toml | 4 ++-- examples/counter/src/counter_rs/Cargo.toml | 4 ++-- examples/counter/src/inter2_rs/Cargo.toml | 4 ++-- examples/counter/src/inter_rs/Cargo.toml | 4 ++-- examples/print/src/print_rs/Cargo.toml | 4 ++-- examples/profile/src/profile_inter_rs/Cargo.toml | 4 ++-- examples/profile/src/profile_rs/Cargo.toml | 4 ++-- src/ic-cdk-macros/Cargo.toml | 4 ++-- src/ic-cdk/CHANGELOG.md | 2 +- src/ic-cdk/Cargo.toml | 2 +- src/ic-certified-assets/Cargo.toml | 4 ++-- src/ic-ledger-types/Cargo.toml | 2 +- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index f9d688d8c..8a53310f4 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,8 @@ crate-type = ["cdylib"] [dependencies] candid = "0.7.4" # this is required if you want to use the `#[import]` macro -ic-cdk = "0.4" -ic-cdk-macros = "0.4" +ic-cdk = "0.5" +ic-cdk-macros = "0.5" ``` Then in your rust source code: diff --git a/docs/modules/rust-guide/pages/rust-profile.adoc b/docs/modules/rust-guide/pages/rust-profile.adoc index 68615061d..7f2519fe2 100644 --- a/docs/modules/rust-guide/pages/rust-profile.adoc +++ b/docs/modules/rust-guide/pages/rust-profile.adoc @@ -101,8 +101,8 @@ To replace the default program: [source,toml] ---- [dependencies] -ic-cdk = "0.4" -ic-cdk-macros = "0.4" +ic-cdk = "0.5" +ic-cdk-macros = "0.5" serde = "1.0" ---- + diff --git a/docs/modules/rust-guide/pages/rust-quickstart.adoc b/docs/modules/rust-guide/pages/rust-quickstart.adoc index dd9d06c83..aa71f3ac3 100644 --- a/docs/modules/rust-guide/pages/rust-quickstart.adoc +++ b/docs/modules/rust-guide/pages/rust-quickstart.adoc @@ -136,8 +136,8 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = "0.4" -ic-cdk-macros = "0.4" +ic-cdk = "0.5" +ic-cdk-macros = "0.5" ---- Notice the `+crate-type = ["cdylib"]+` line which is necessary to compile this rust program into WebAssembly module. diff --git a/examples/asset_storage/src/asset_storage_rs/Cargo.toml b/examples/asset_storage/src/asset_storage_rs/Cargo.toml index 87292fb51..715975203 100644 --- a/examples/asset_storage/src/asset_storage_rs/Cargo.toml +++ b/examples/asset_storage/src/asset_storage_rs/Cargo.toml @@ -11,5 +11,5 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } diff --git a/examples/chess/src/chess_rs/Cargo.toml b/examples/chess/src/chess_rs/Cargo.toml index 3a3173b9c..de551e63c 100644 --- a/examples/chess/src/chess_rs/Cargo.toml +++ b/examples/chess/src/chess_rs/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["cdylib"] [dependencies] candid = "0.7.4" -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } serde = "1.0.111" pleco = "0.5.0" diff --git a/examples/counter/src/counter_rs/Cargo.toml b/examples/counter/src/counter_rs/Cargo.toml index a8c305178..4b839dd03 100644 --- a/examples/counter/src/counter_rs/Cargo.toml +++ b/examples/counter/src/counter_rs/Cargo.toml @@ -12,6 +12,6 @@ crate-type = ["cdylib"] [dependencies] candid = "0.7.4" -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } lazy_static = "1.4.0" diff --git a/examples/counter/src/inter2_rs/Cargo.toml b/examples/counter/src/inter2_rs/Cargo.toml index 5d722b1a6..36173aaa9 100644 --- a/examples/counter/src/inter2_rs/Cargo.toml +++ b/examples/counter/src/inter2_rs/Cargo.toml @@ -12,5 +12,5 @@ crate-type = ["cdylib"] [dependencies] candid = "0.7.4" -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } diff --git a/examples/counter/src/inter_rs/Cargo.toml b/examples/counter/src/inter_rs/Cargo.toml index 1e4940689..10277b1f7 100644 --- a/examples/counter/src/inter_rs/Cargo.toml +++ b/examples/counter/src/inter_rs/Cargo.toml @@ -12,5 +12,5 @@ crate-type = ["cdylib"] [dependencies] candid = "0.7.4" -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } diff --git a/examples/print/src/print_rs/Cargo.toml b/examples/print/src/print_rs/Cargo.toml index 0ed00ec57..cf6d0587f 100644 --- a/examples/print/src/print_rs/Cargo.toml +++ b/examples/print/src/print_rs/Cargo.toml @@ -11,6 +11,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } diff --git a/examples/profile/src/profile_inter_rs/Cargo.toml b/examples/profile/src/profile_inter_rs/Cargo.toml index a0036307b..0142d06da 100644 --- a/examples/profile/src/profile_inter_rs/Cargo.toml +++ b/examples/profile/src/profile_inter_rs/Cargo.toml @@ -12,5 +12,5 @@ crate-type = ["cdylib"] [dependencies] candid = "0.7.4" -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } diff --git a/examples/profile/src/profile_rs/Cargo.toml b/examples/profile/src/profile_rs/Cargo.toml index 33d1af5cf..f867a3fd7 100644 --- a/examples/profile/src/profile_rs/Cargo.toml +++ b/examples/profile/src/profile_rs/Cargo.toml @@ -12,6 +12,6 @@ crate-type = ["cdylib"] [dependencies] candid = "0.7.4" -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.4" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.4" } +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } serde = "1.0.111" diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index daa900238..2c674a92c 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.4.0" +version = "0.5.0" authors = ["DFINITY Stiftung "] edition = "2018" description = "Canister Developer Kit macros." @@ -18,7 +18,7 @@ proc-macro = true [dependencies] candid = "0.7.4" -ic-cdk = { path = "../ic-cdk", version = "0.4" } +ic-cdk = { path = "../ic-cdk", version = "0.5" } syn = { version = "1.0.58", features = ["fold", "full"] } quote = "1.0" proc-macro2 = "1.0" diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 329a5fec8..5420bdeca 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.5.0] - 2022-03-29 ### Added - Update canister calling API for 128-bit cycles (#228) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 674c544df..94652807b 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.4.0" +version = "0.5.0" authors = ["DFINITY Stiftung "] edition = "2018" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml index b95074849..e2bade31f 100644 --- a/src/ic-certified-assets/Cargo.toml +++ b/src/ic-certified-assets/Cargo.toml @@ -13,8 +13,8 @@ repository = "https://github.com/dfinity/cdk-rs" base64 = "0.13" candid = "0.7.10" hex = "0.4.3" -ic-cdk = { path = "../ic-cdk", version = "0.4" } -ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.4" } +ic-cdk = { path = "../ic-cdk", version = "0.5" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.5" } ic-types = "0.3.0" ic-certified-map = { path = "../ic-certified-map", version = "0.3" } num-traits = "0.2.14" diff --git a/src/ic-ledger-types/Cargo.toml b/src/ic-ledger-types/Cargo.toml index 59e1167c3..7fc71b932 100644 --- a/src/ic-ledger-types/Cargo.toml +++ b/src/ic-ledger-types/Cargo.toml @@ -16,7 +16,7 @@ repository = "https://github.com/dfinity/cdk-rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ic-cdk = { path = "../ic-cdk", version = "0.4" } +ic-cdk = { path = "../ic-cdk", version = "0.5" } candid = "0.7.4" crc32fast = "1.2.0" hex = "0.4" From 88530166bd885fa23e4b3d1b92de48cfada537f8 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Wed, 30 Mar 2022 14:18:17 -0700 Subject: [PATCH 036/234] chore: Update Rust to 1.58.1 (#237) * Update to 1.58.1 * Set MSRV * Set all editions to 2021 * Fix Clippy error (was UB) * Fix new clippy warnings * Update trybuild * Update macro doctest --- .github/workflows/examples.yml | 2 +- .github/workflows/fmt.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 6 +++--- rust-toolchain.toml | 2 +- src/ic-cdk-macros/Cargo.toml | 3 ++- src/ic-cdk-macros/src/export.rs | 5 +---- src/ic-cdk-macros/src/import.rs | 2 +- src/ic-cdk-macros/src/lib.rs | 1 + src/ic-cdk-macros/tests/compile_fail/only_function.stderr | 2 +- src/ic-cdk-optimizer/Cargo.toml | 3 ++- src/ic-cdk/Cargo.toml | 3 ++- src/ic-cdk/src/api/stable.rs | 4 +--- src/ic-certified-assets/Cargo.toml | 3 ++- src/ic-certified-map/Cargo.toml | 3 ++- src/ic-ledger-types/Cargo.toml | 3 ++- 16 files changed, 24 insertions(+), 22 deletions(-) diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 9cf9abad4..6a0db539b 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -16,7 +16,7 @@ jobs: include: - build: linux-stable os: ubuntu-latest - rust: 1.55.0 + rust: 1.58.1 dfx: 0.8.1 steps: diff --git a/.github/workflows/fmt.yml b/.github/workflows/fmt.yml index 6f3d82770..25d737e69 100644 --- a/.github/workflows/fmt.yml +++ b/.github/workflows/fmt.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust: [ 1.55.0 ] + rust: [ 1.58.1 ] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1ab9173d8..000b41319 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust: [ 1.55.0 ] + rust: [ 1.58.1 ] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a40194db1..9270965cb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,13 +15,13 @@ jobs: include: - build: linux-stable os: ubuntu-latest - rust: 1.55.0 + rust: 1.58.1 - build: macos-stable os: macos-latest - rust: 1.55.0 + rust: 1.58.1 - build: windows-stable os: windows-latest - rust: 1.55.0 + rust: 1.58.1 steps: - uses: actions/checkout@v2 diff --git a/rust-toolchain.toml b/rust-toolchain.toml index b4c36257f..76b44e44c 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.55.0" +channel = "1.58.1" components = ["rustfmt", "clippy"] diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 2c674a92c..e4ae20d91 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -2,7 +2,7 @@ name = "ic-cdk-macros" version = "0.5.0" authors = ["DFINITY Stiftung "] -edition = "2018" +edition = "2021" description = "Canister Developer Kit macros." homepage = "https://docs.rs/ic-cdk-macros" documentation = "https://docs.rs/ic-cdk-macros" @@ -12,6 +12,7 @@ categories = ["api-bindings", "data-structures", "no-std", "development-tools::f keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" +rust-version = "1.58.1" [lib] proc-macro = true diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index 086a3ad3c..95d7dd6ef 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -131,10 +131,7 @@ fn dfn_macro( get_args(method, signature)?.iter().cloned().unzip(); let name = &signature.ident; - let outer_function_ident = Ident::new( - &format!("{}_{}_", name.to_string(), crate::id()), - Span::call_site(), - ); + let outer_function_ident = Ident::new(&format!("{}_{}_", name, crate::id()), Span::call_site()); let export_name = if method.is_lifecycle() { format!("canister_{}", method) diff --git a/src/ic-cdk-macros/src/import.rs b/src/ic-cdk-macros/src/import.rs index dd53bfa7f..c606ed918 100644 --- a/src/ic-cdk-macros/src/import.rs +++ b/src/ic-cdk-macros/src/import.rs @@ -127,7 +127,7 @@ impl candid::codegen::rust::RustBindings for RustLanguageBinding { arguments = arguments_list, body = body, return_type = if returns.is_empty() { - format!("") + String::new() } else { format!("-> ({},)", returns.to_vec().join(",")) } diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index 0996e85ef..d38097117 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -233,6 +233,7 @@ pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream { /// /// ```rust /// # use ic_cdk_macros::*; +/// # use candid::*; /// /// #[derive(Clone, Debug, CandidType, Deserialize)] /// struct InitArg { diff --git a/src/ic-cdk-macros/tests/compile_fail/only_function.stderr b/src/ic-cdk-macros/tests/compile_fail/only_function.stderr index 7b9c45d2c..8c94f8431 100644 --- a/src/ic-cdk-macros/tests/compile_fail/only_function.stderr +++ b/src/ic-cdk-macros/tests/compile_fail/only_function.stderr @@ -1,5 +1,5 @@ error: #[query] must be above a function. -expected `fn` + expected `fn` --> tests/compile_fail/only_function.rs:4:1 | 4 | struct S; diff --git a/src/ic-cdk-optimizer/Cargo.toml b/src/ic-cdk-optimizer/Cargo.toml index 6fbbe6c11..335ccc868 100644 --- a/src/ic-cdk-optimizer/Cargo.toml +++ b/src/ic-cdk-optimizer/Cargo.toml @@ -2,7 +2,7 @@ name = "ic-cdk-optimizer" version = "0.3.4" authors = ["DFINITY Stiftung "] -edition = "2018" +edition = "2021" description = "WASM Optimizer for the IC CDK (experimental)." homepage = "https://docs.rs/ic-cdk-optimizer" documentation = "https://docs.rs/ic-cdk-optimizer" @@ -12,6 +12,7 @@ categories = ["api-bindings", "data-structures", "no-std", "command-line-utiliti keywords = ["internet-computer", "dfinity", "canister", "cli", "optimizer"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" +rust-version = "1.58.1" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 94652807b..4fbcb8980 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -2,7 +2,7 @@ name = "ic-cdk" version = "0.5.0" authors = ["DFINITY Stiftung "] -edition = "2018" +edition = "2021" description = "Canister Developer Kit for the Internet Computer." homepage = "https://docs.rs/ic-cdk" documentation = "https://docs.rs/ic-cdk" @@ -12,6 +12,7 @@ categories = ["api-bindings", "data-structures", "no-std", "development-tools::f keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" +rust-version = "1.58.1" [dependencies] candid = "0.7.4" diff --git a/src/ic-cdk/src/api/stable.rs b/src/ic-cdk/src/api/stable.rs index 9ae91c91c..57b6a3bf8 100644 --- a/src/ic-cdk/src/api/stable.rs +++ b/src/ic-cdk/src/api/stable.rs @@ -94,11 +94,9 @@ pub fn stable_bytes() -> Vec { let size = (stable_size() as usize) << 16; let mut vec = Vec::with_capacity(size); unsafe { + super::ic0::stable_read(vec.as_ptr() as i32, 0, size as i32); vec.set_len(size); } - - stable_read(0, vec.as_mut_slice()); - vec } diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml index e2bade31f..f9d0ed67d 100644 --- a/src/ic-certified-assets/Cargo.toml +++ b/src/ic-certified-assets/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "ic-certified-assets" version = "0.1.0" -edition = "2018" +edition = "2021" authors = ["DFINITY Stiftung "] description = "Rust support for asset certification." license = "Apache-2.0" keywords = ["internet-computer", "dfinity"] categories = ["wasm", "filesystem", "data-structures"] repository = "https://github.com/dfinity/cdk-rs" +rust-version = "1.58.1" [dependencies] base64 = "0.13" diff --git a/src/ic-certified-map/Cargo.toml b/src/ic-certified-map/Cargo.toml index 15ac8658b..22c8ad48f 100644 --- a/src/ic-certified-map/Cargo.toml +++ b/src/ic-certified-map/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ic-certified-map" version = "0.3.0" -edition = "2018" +edition = "2021" authors = ["DFINITY Stiftung "] description = "Merkleized map data structure." homepage = "https://docs.rs/ic-certified-map" @@ -12,6 +12,7 @@ categories = ["data-structures", "cryptography", "cryptography::cryptocurrencies keywords = ["internet-computer", "types", "dfinity", "map"] include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" +rust-version = "1.58.1" [dependencies] serde = "1" diff --git a/src/ic-ledger-types/Cargo.toml b/src/ic-ledger-types/Cargo.toml index 7fc71b932..717ef11d7 100644 --- a/src/ic-ledger-types/Cargo.toml +++ b/src/ic-ledger-types/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ic-ledger-types" version = "0.1.1" -edition = "2018" +edition = "2021" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." homepage = "https://docs.rs/ic-ledger-types" @@ -12,6 +12,7 @@ keywords = ["internet-computer", "ledger"] categories = ["cryptography::cryptocurrencies", "data-structures"] include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" +rust-version = "1.58.1" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 085b1c6c37b8f904e763ee413d799c0d53368b4f Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Wed, 6 Apr 2022 10:27:45 +0100 Subject: [PATCH 037/234] docs: Add warning to `stable_write` explaining scenario in which it panics (#239) --- src/ic-cdk/src/api/stable.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ic-cdk/src/api/stable.rs b/src/ic-cdk/src/api/stable.rs index 57b6a3bf8..6ec50cf76 100644 --- a/src/ic-cdk/src/api/stable.rs +++ b/src/ic-cdk/src/api/stable.rs @@ -60,6 +60,9 @@ pub fn stable64_grow(new_pages: u64) -> Result { } /// Writes data to the stable memory location specified by an offset. +/// +/// Warning - this will panic if `offset + buf.len()` exceeds the current size of stable memory. +/// Use `stable_grow` to request more stable memory if needed. pub fn stable_write(offset: u32, buf: &[u8]) { unsafe { super::ic0::stable_write(offset as i32, buf.as_ptr() as i32, buf.len() as i32); From 05536a9dcfe844e5ecaa949da545e5fcf7e4ad9f Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 6 Apr 2022 16:23:13 -0400 Subject: [PATCH 038/234] chore: Update dfx to 0.9.3 in CI (#242) * chore: Update dfx to 0.9.3 in CI * remove --no-wallet --- .github/workflows/examples.yml | 2 +- examples/asset_storage/tests/basic.bats | 36 ++++++++++++------------- examples/chess/tests/basic.bats | 10 +++---- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 6a0db539b..7ab0aa40b 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -17,7 +17,7 @@ jobs: - build: linux-stable os: ubuntu-latest rust: 1.58.1 - dfx: 0.8.1 + dfx: 0.9.3 steps: - uses: actions/checkout@v2 diff --git a/examples/asset_storage/tests/basic.bats b/examples/asset_storage/tests/basic.bats index 3255d9c69..c00a6e9f1 100644 --- a/examples/asset_storage/tests/basic.bats +++ b/examples/asset_storage/tests/basic.bats @@ -19,10 +19,10 @@ teardown() { } @test "Can store and restore assets" { - dfx deploy --no-wallet - dfx canister --no-wallet call asset_storage store '("asset_name", vec { 1; 2; 3; })' - dfx canister --no-wallet call asset_storage retrieve '("asset_name")' - run dfx canister --no-wallet call asset_storage retrieve '("unknown")' + dfx deploy + dfx canister call asset_storage store '("asset_name", vec { 1; 2; 3; })' + dfx canister call asset_storage retrieve '("asset_name")' + run dfx canister call asset_storage retrieve '("unknown")' # As of dfx 0.8.1, above command results in following error message: # > The Replica returned an error: code 5, message: "IC0502: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped: unreachable" [ "$status" != 0 ] @@ -30,45 +30,45 @@ teardown() { @test "Will fails on invalid identities" { dfx identity use alice - dfx deploy --no-wallet - dfx canister --no-wallet call asset_storage store '("asset_name", vec { 1; 2; 3; })' - dfx canister --no-wallet call asset_storage retrieve '("asset_name")' + dfx deploy + dfx canister call asset_storage store '("asset_name", vec { 1; 2; 3; })' + dfx canister call asset_storage retrieve '("asset_name")' - dfx canister --no-wallet call asset_storage add_user "(principal \"$(dfx --identity charlie identity get-principal)\")" + dfx canister call asset_storage add_user "(principal \"$(dfx --identity charlie identity get-principal)\")" dfx identity use bob - dfx canister --no-wallet call asset_storage retrieve '("asset_name")' + dfx canister call asset_storage retrieve '("asset_name")' # Test that an unknown asset fails. - run dfx canister --no-wallet call asset_storage retrieve '("unknown")' + run dfx canister call asset_storage retrieve '("unknown")' [ "$status" != 0 ] # Test that cannot upload assets as bob. - run dfx canister --no-wallet call asset_storage store '("asset_name", vec { 1; })' + run dfx canister call asset_storage store '("asset_name", vec { 1; })' [ "$status" != 0 ] # Test we can upload assets as charlie. dfx identity use charlie - run dfx canister --no-wallet call asset_storage store '("asset_name_2", vec { 1; 2; 3; })' + run dfx canister call asset_storage store '("asset_name_2", vec { 1; 2; 3; })' [ "$status" == 0 ] } @test "Can upgrade and keep ACLs" { dfx identity use alice - dfx deploy --no-wallet + dfx deploy - dfx canister --no-wallet call asset_storage store '("asset_name", vec { 1; 2; 3; })' + dfx canister call asset_storage store '("asset_name", vec { 1; 2; 3; })' dfx identity use bob - run dfx canister --no-wallet call asset_storage retrieve '("unknown")' + run dfx canister call asset_storage retrieve '("unknown")' [ "$status" != 0 ] dfx identity use alice - dfx canister --no-wallet call asset_storage add_user "(principal \"$(dfx --identity charlie identity get-principal)\")" + dfx canister call asset_storage add_user "(principal \"$(dfx --identity charlie identity get-principal)\")" dfx build - dfx canister --no-wallet install --all --mode=upgrade + dfx canister install --all --mode=upgrade dfx identity use charlie - run dfx canister --no-wallet call asset_storage store '("asset_name_2", vec { 1; 2; 3; })' + run dfx canister call asset_storage store '("asset_name_2", vec { 1; 2; 3; })' [ "$status" == 0 ] } diff --git a/examples/chess/tests/basic.bats b/examples/chess/tests/basic.bats index e1ea0e70c..f1ee962cf 100644 --- a/examples/chess/tests/basic.bats +++ b/examples/chess/tests/basic.bats @@ -17,13 +17,13 @@ teardown() { } @test "Can play chess against AI" { - dfx deploy --no-wallet - run dfx canister --no-wallet call chess_rs new '("test", true)' + dfx deploy + run dfx canister call chess_rs new '("test", true)' [ "$output" == "()" ] - run dfx canister --no-wallet call chess_rs move '("test", "e2e4")' + run dfx canister call chess_rs move '("test", "e2e4")' [ "$output" == "(true)" ] - run dfx canister --no-wallet call chess_rs move '("test", "d2d3")' + run dfx canister call chess_rs move '("test", "d2d3")' [ "$output" == "(true)" ] - run dfx canister --no-wallet call chess_rs getFen '("test")' + run dfx canister call chess_rs getFen '("test")' [ "$output" == '(opt "rnb1kbnr/pp1ppppp/1qp5/8/4P3/3P4/PPP2PPP/RNBQKBNR w KQkq - 1 3")' ] } From 8a2843f82460c19a730c08666ef2c5f474a931b2 Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Wed, 6 Apr 2022 23:31:52 +0100 Subject: [PATCH 039/234] feat: Add `grow_then_write_stable_bytes` helper method (#240) * feat: Add `grow_then_write_stable_bytes` helper method * Add comment to make page size easily human readable Co-authored-by: Linwei Shang --- src/ic-cdk/src/api/stable.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/ic-cdk/src/api/stable.rs b/src/ic-cdk/src/api/stable.rs index 6ec50cf76..1e5ffc5e2 100644 --- a/src/ic-cdk/src/api/stable.rs +++ b/src/ic-cdk/src/api/stable.rs @@ -4,7 +4,9 @@ //! for a in-depth explanation of stable memory. use std::{error, fmt, io}; -/// Gets current size of the stable memory. +const WASM_PAGE_SIZE_IN_BYTES: u64 = 64 * 1024; // 64KB + +/// Gets current size of the stable memory (in WASM pages). pub fn stable_size() -> u32 { unsafe { super::ic0::stable_size() as u32 } } @@ -103,6 +105,22 @@ pub fn stable_bytes() -> Vec { vec } +/// Ensures the stable memory size is large enough to perform the write, then writes data to the +/// stable memory location specified by an offset. +pub fn grow_then_write_stable_bytes(offset: u64, bytes: &[u8]) -> Result<(), StableMemoryError> { + let bytes_required = offset + bytes.len() as u64; + let pages_required = (bytes_required + WASM_PAGE_SIZE_IN_BYTES - 1) / WASM_PAGE_SIZE_IN_BYTES; + let current_pages = stable64_size(); + let additional_pages_required = pages_required.saturating_sub(current_pages); + + if additional_pages_required > 0 { + stable64_grow(additional_pages_required)?; + } + + stable64_write(offset, bytes); + Ok(()) +} + /// A writer to the stable memory. /// /// Will attempt to grow the memory as it writes, @@ -139,11 +157,7 @@ impl StableWriter { /// The only condition where this will /// error out is if it cannot grow the memory. pub fn write(&mut self, buf: &[u8]) -> Result { - if self.offset + buf.len() > ((self.capacity as usize) << 16) { - self.grow((buf.len() >> 16) as u32 + 1)?; - } - - stable_write(self.offset as u32, buf); + grow_then_write_stable_bytes(self.offset as u64, buf)?; self.offset += buf.len(); Ok(buf.len()) } From 50739f0842c9b159e0b7a5da491c3e8130917b0f Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Thu, 7 Apr 2022 17:08:18 +0100 Subject: [PATCH 040/234] Revert "feat: Add `grow_then_write_stable_bytes` helper method (#240)" (#244) This reverts commit 8a2843f82460c19a730c08666ef2c5f474a931b2. --- src/ic-cdk/src/api/stable.rs | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/src/ic-cdk/src/api/stable.rs b/src/ic-cdk/src/api/stable.rs index 1e5ffc5e2..6ec50cf76 100644 --- a/src/ic-cdk/src/api/stable.rs +++ b/src/ic-cdk/src/api/stable.rs @@ -4,9 +4,7 @@ //! for a in-depth explanation of stable memory. use std::{error, fmt, io}; -const WASM_PAGE_SIZE_IN_BYTES: u64 = 64 * 1024; // 64KB - -/// Gets current size of the stable memory (in WASM pages). +/// Gets current size of the stable memory. pub fn stable_size() -> u32 { unsafe { super::ic0::stable_size() as u32 } } @@ -105,22 +103,6 @@ pub fn stable_bytes() -> Vec { vec } -/// Ensures the stable memory size is large enough to perform the write, then writes data to the -/// stable memory location specified by an offset. -pub fn grow_then_write_stable_bytes(offset: u64, bytes: &[u8]) -> Result<(), StableMemoryError> { - let bytes_required = offset + bytes.len() as u64; - let pages_required = (bytes_required + WASM_PAGE_SIZE_IN_BYTES - 1) / WASM_PAGE_SIZE_IN_BYTES; - let current_pages = stable64_size(); - let additional_pages_required = pages_required.saturating_sub(current_pages); - - if additional_pages_required > 0 { - stable64_grow(additional_pages_required)?; - } - - stable64_write(offset, bytes); - Ok(()) -} - /// A writer to the stable memory. /// /// Will attempt to grow the memory as it writes, @@ -157,7 +139,11 @@ impl StableWriter { /// The only condition where this will /// error out is if it cannot grow the memory. pub fn write(&mut self, buf: &[u8]) -> Result { - grow_then_write_stable_bytes(self.offset as u64, buf)?; + if self.offset + buf.len() > ((self.capacity as usize) << 16) { + self.grow((buf.len() >> 16) as u32 + 1)?; + } + + stable_write(self.offset as u32, buf); self.offset += buf.len(); Ok(buf.len()) } From 20c4f8d686e715b6f1137b2388a7bf46311f2e98 Mon Sep 17 00:00:00 2001 From: Paul Liu Date: Thu, 7 Apr 2022 14:20:39 -0700 Subject: [PATCH 041/234] feat: Add a TryFrom instance for AccountIdentifier that checks CRC-32 (#241) * Add a TryFrom instance for AccountIdentifier that checks CRC32 * Update CHANGELOG Co-authored-by: Linwei Shang --- src/ic-ledger-types/CHANGELOG.md | 3 +++ src/ic-ledger-types/src/lib.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/ic-ledger-types/CHANGELOG.md b/src/ic-ledger-types/CHANGELOG.md index 13c3e114d..ac5b5afc5 100644 --- a/src/ic-ledger-types/CHANGELOG.md +++ b/src/ic-ledger-types/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### Changed +* Support conversion from `[u8; 32]` to `AccountIdentifier` via `TryFrom` with CRC-32 check. + ## [0.1.1] - 2022-02-04 ### Changed * Upgrade `ic-cdk` to v0.4.0. diff --git a/src/ic-ledger-types/src/lib.rs b/src/ic-ledger-types/src/lib.rs index 2b7ac7abc..d21bd2c48 100644 --- a/src/ic-ledger-types/src/lib.rs +++ b/src/ic-ledger-types/src/lib.rs @@ -2,6 +2,7 @@ use ic_cdk::api::call::CallResult; use ic_cdk::export::candid::{CandidType, Principal}; use serde::{Deserialize, Serialize}; use sha2::Digest; +use std::convert::TryFrom; use std::fmt; use std::ops::{Add, AddAssign, Sub, SubAssign}; @@ -147,6 +148,22 @@ impl AccountIdentifier { } } +impl TryFrom<[u8; 32]> for AccountIdentifier { + type Error = String; + + fn try_from(bytes: [u8; 32]) -> Result { + let hash = &bytes[4..]; + let mut hasher = crc32fast::Hasher::new(); + hasher.update(hash); + let crc32_bytes = hasher.finalize().to_be_bytes(); + if bytes[0..4] == crc32_bytes[0..4] { + Ok(Self(bytes)) + } else { + Err("CRC-32 checksum failed to verify".to_string()) + } + } +} + impl AsRef<[u8]> for AccountIdentifier { fn as_ref(&self) -> &[u8] { &self.0 @@ -301,6 +318,18 @@ mod tests { ); } + #[test] + fn test_account_id_try_from() { + let mut bytes: [u8; 32] = [0; 32]; + bytes.copy_from_slice( + &hex::decode("bdc4ee05d42cd0669786899f256c8fd7217fa71177bd1fa7b9534f568680a938") + .unwrap(), + ); + assert!(AccountIdentifier::try_from(bytes).is_ok()); + bytes[0] = 0; + assert!(AccountIdentifier::try_from(bytes).is_err()); + } + #[test] fn test_ledger_canister_id() { assert_eq!( From 43044af95a678e98bc70bdbb81b0ab49e35db728 Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Wed, 13 Apr 2022 00:42:24 +0100 Subject: [PATCH 042/234] feat: Add `BufferedStableWriter` which aims to minimise system calls (#245) --- src/ic-cdk/CHANGELOG.md | 4 + src/ic-cdk/Cargo.toml | 3 + src/ic-cdk/src/api/stable.rs | 160 +++++++++++++++++++------- src/ic-cdk/src/api/stable/canister.rs | 57 +++++++++ src/ic-cdk/src/api/stable/tests.rs | 154 +++++++++++++++++++++++++ 5 files changed, 339 insertions(+), 39 deletions(-) create mode 100644 src/ic-cdk/src/api/stable/canister.rs create mode 100644 src/ic-cdk/src/api/stable/tests.rs diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 5420bdeca..727fe2023 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [unreleased] +### Added +- Add `BufferedStableWriter` for efficient writing to stable memory (#245) + ## [0.5.0] - 2022-03-29 ### Added - Update canister calling API for 128-bit cycles (#228) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 4fbcb8980..ef3775b90 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -19,5 +19,8 @@ candid = "0.7.4" cfg-if = "1.0.0" serde = "1.0.110" +[dev-dependencies] +rstest = "0.12.0" + [features] experimental = [] diff --git a/src/ic-cdk/src/api/stable.rs b/src/ic-cdk/src/api/stable.rs index 6ec50cf76..baf58e52b 100644 --- a/src/ic-cdk/src/api/stable.rs +++ b/src/ic-cdk/src/api/stable.rs @@ -2,16 +2,60 @@ //! //! You can check the [Internet Computer Specification](https://smartcontracts.org/docs/interface-spec/index.html#system-api-stable-memory) //! for a in-depth explanation of stable memory. +mod canister; +#[cfg(test)] +mod tests; + +use canister::CanisterStableMemory; use std::{error, fmt, io}; -/// Gets current size of the stable memory. +const WASM_PAGE_SIZE_IN_BYTES: usize = 64 * 1024; // 64KB + +static CANISTER_STABLE_MEMORY: CanisterStableMemory = CanisterStableMemory {}; + +/// A trait defining the stable memory API which each canister running on the IC can make use of +pub trait StableMemory { + /// Gets current size of the stable memory (in WASM pages). + fn stable_size(&self) -> u32; + + /// Similar to `stable_size` but with support for 64-bit addressed memory. + fn stable64_size(&self) -> u64; + + /// Attempts to grow the stable memory by `new_pages` (added pages). + /// + /// Returns an error if it wasn't possible. Otherwise, returns the previous + /// size that was reserved. + /// + /// *Note*: Pages are 64KiB in WASM. + fn stable_grow(&self, new_pages: u32) -> Result; + + /// Similar to `stable_grow` but with support for 64-bit addressed memory. + fn stable64_grow(&self, new_pages: u64) -> Result; + + /// Writes data to the stable memory location specified by an offset. + /// + /// Warning - this will panic if `offset + buf.len()` exceeds the current size of stable memory. + /// Use `stable_grow` to request more stable memory if needed. + fn stable_write(&self, offset: u32, buf: &[u8]); + + /// Similar to `stable_write` but with support for 64-bit addressed memory. + fn stable64_write(&self, offset: u64, buf: &[u8]); + + /// Reads data from the stable memory location specified by an offset. + fn stable_read(&self, offset: u32, buf: &mut [u8]); + + /// Similar to `stable_read` but with support for 64-bit addressed memory. + fn stable64_read(&self, offset: u64, buf: &mut [u8]); +} + +/// Gets current size of the stable memory (in WASM pages). pub fn stable_size() -> u32 { - unsafe { super::ic0::stable_size() as u32 } + CANISTER_STABLE_MEMORY.stable_size() } /// Similar to `stable_size` but with support for 64-bit addressed memory. pub fn stable64_size() -> u64 { - unsafe { super::ic0::stable64_size() as u64 } + CANISTER_STABLE_MEMORY.stable64_size() } /// A possible error value when dealing with stable memory. @@ -41,22 +85,12 @@ impl error::Error for StableMemoryError {} /// /// *Note*: Pages are 64KiB in WASM. pub fn stable_grow(new_pages: u32) -> Result { - unsafe { - match super::ic0::stable_grow(new_pages as i32) { - -1 => Err(StableMemoryError::OutOfMemory), - x => Ok(x as u32), - } - } + CANISTER_STABLE_MEMORY.stable_grow(new_pages) } /// Similar to `stable_grow` but with support for 64-bit addressed memory. pub fn stable64_grow(new_pages: u64) -> Result { - unsafe { - match super::ic0::stable64_grow(new_pages as i64) { - -1 => Err(StableMemoryError::OutOfMemory), - x => Ok(x as u64), - } - } + CANISTER_STABLE_MEMORY.stable64_grow(new_pages) } /// Writes data to the stable memory location specified by an offset. @@ -64,30 +98,22 @@ pub fn stable64_grow(new_pages: u64) -> Result { /// Warning - this will panic if `offset + buf.len()` exceeds the current size of stable memory. /// Use `stable_grow` to request more stable memory if needed. pub fn stable_write(offset: u32, buf: &[u8]) { - unsafe { - super::ic0::stable_write(offset as i32, buf.as_ptr() as i32, buf.len() as i32); - } + CANISTER_STABLE_MEMORY.stable_write(offset, buf) } /// Similar to `stable_write` but with support for 64-bit addressed memory. pub fn stable64_write(offset: u64, buf: &[u8]) { - unsafe { - super::ic0::stable64_write(offset as i64, buf.as_ptr() as i64, buf.len() as i64); - } + CANISTER_STABLE_MEMORY.stable64_write(offset, buf) } /// Reads data from the stable memory location specified by an offset. pub fn stable_read(offset: u32, buf: &mut [u8]) { - unsafe { - super::ic0::stable_read(buf.as_ptr() as i32, offset as i32, buf.len() as i32); - } + CANISTER_STABLE_MEMORY.stable_read(offset, buf) } /// Similar to `stable_read` but with support for 64-bit addressed memory. pub fn stable64_read(offset: u64, buf: &mut [u8]) { - unsafe { - super::ic0::stable64_read(buf.as_ptr() as i64, offset as i64, buf.len() as i64); - } + CANISTER_STABLE_MEMORY.stable64_read(offset, buf) } /// Returns a copy of the stable memory. @@ -105,32 +131,44 @@ pub fn stable_bytes() -> Vec { /// A writer to the stable memory. /// +/// Warning: This will overwrite any existing data in stable memory as it writes, so ensure you set +/// the `offset` value accordingly if you wish to preserve existing data. +/// /// Will attempt to grow the memory as it writes, /// and keep offsets and total capacity. -pub struct StableWriter { +pub struct StableWriter { /// The offset of the next write. offset: usize, /// The capacity, in pages. capacity: u32, + + /// The stable memory to write data to. + memory: M, } impl Default for StableWriter { fn default() -> Self { - let capacity = stable_size(); + Self::with_memory(CanisterStableMemory::default(), 0) + } +} + +impl StableWriter { + /// Creates a new `StableWriter` which writes to the selected memory + pub fn with_memory(memory: M, offset: usize) -> Self { + let capacity = memory.stable_size(); Self { - offset: 0, + offset, capacity, + memory, } } -} -impl StableWriter { /// Attempts to grow the memory by adding new pages. - pub fn grow(&mut self, added_pages: u32) -> Result<(), StableMemoryError> { - let old_page_count = stable_grow(added_pages)?; - self.capacity = old_page_count + added_pages; + pub fn grow(&mut self, new_pages: u32) -> Result<(), StableMemoryError> { + let old_page_count = self.memory.stable_grow(new_pages)?; + self.capacity = old_page_count + new_pages; Ok(()) } @@ -139,17 +177,23 @@ impl StableWriter { /// The only condition where this will /// error out is if it cannot grow the memory. pub fn write(&mut self, buf: &[u8]) -> Result { - if self.offset + buf.len() > ((self.capacity as usize) << 16) { - self.grow((buf.len() >> 16) as u32 + 1)?; + let required_capacity_bytes = self.offset + buf.len(); + let required_capacity_pages = ((required_capacity_bytes + WASM_PAGE_SIZE_IN_BYTES - 1) + / WASM_PAGE_SIZE_IN_BYTES) as u32; + let current_pages = self.capacity; + let additional_pages_required = required_capacity_pages.saturating_sub(current_pages); + + if additional_pages_required > 0 { + self.grow(additional_pages_required)?; } - stable_write(self.offset as u32, buf); + self.memory.stable_write(self.offset as u32, buf); self.offset += buf.len(); Ok(buf.len()) } } -impl io::Write for StableWriter { +impl io::Write for StableWriter { fn write(&mut self, buf: &[u8]) -> Result { self.write(buf) .map_err(|e| io::Error::new(io::ErrorKind::OutOfMemory, e)) @@ -161,6 +205,44 @@ impl io::Write for StableWriter { } } +/// A writer to the stable memory which first writes the bytes to an in memory buffer and flushes +/// the buffer to stable memory each time it becomes full. +/// +/// Warning: This will overwrite any existing data in stable memory as it writes, so ensure you set +/// the `offset` value accordingly if you wish to preserve existing data. +/// +/// Note: Each call to grow or write to stable memory is a relatively expensive operation, so pick a +/// buffer size large enough to avoid excessive calls to stable memory. +pub struct BufferedStableWriter { + inner: io::BufWriter>, +} + +impl BufferedStableWriter { + /// Creates a new `BufferedStableWriter` + pub fn new(buffer_size: usize) -> BufferedStableWriter { + BufferedStableWriter::with_writer(buffer_size, StableWriter::default()) + } +} + +impl BufferedStableWriter { + /// Creates a new `BufferedStableWriter` which writes to the selected memory + pub fn with_writer(buffer_size: usize, writer: StableWriter) -> BufferedStableWriter { + BufferedStableWriter { + inner: io::BufWriter::with_capacity(buffer_size, writer), + } + } +} + +impl io::Write for BufferedStableWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + /// A reader to the stable memory. /// /// Keeps an offset and reads off stable memory consecutively. diff --git a/src/ic-cdk/src/api/stable/canister.rs b/src/ic-cdk/src/api/stable/canister.rs new file mode 100644 index 000000000..9c2c5fc5d --- /dev/null +++ b/src/ic-cdk/src/api/stable/canister.rs @@ -0,0 +1,57 @@ +use super::*; +use crate::api::ic0; + +#[derive(Default)] +pub struct CanisterStableMemory {} + +impl StableMemory for CanisterStableMemory { + fn stable_size(&self) -> u32 { + unsafe { ic0::stable_size() as u32 } + } + + fn stable64_size(&self) -> u64 { + unsafe { ic0::stable64_size() as u64 } + } + + fn stable_grow(&self, new_pages: u32) -> Result { + unsafe { + match ic0::stable_grow(new_pages as i32) { + -1 => Err(StableMemoryError::OutOfMemory), + x => Ok(x as u32), + } + } + } + + fn stable64_grow(&self, new_pages: u64) -> Result { + unsafe { + match ic0::stable64_grow(new_pages as i64) { + -1 => Err(StableMemoryError::OutOfMemory), + x => Ok(x as u64), + } + } + } + + fn stable_write(&self, offset: u32, buf: &[u8]) { + unsafe { + ic0::stable_write(offset as i32, buf.as_ptr() as i32, buf.len() as i32); + } + } + + fn stable64_write(&self, offset: u64, buf: &[u8]) { + unsafe { + ic0::stable64_write(offset as i64, buf.as_ptr() as i64, buf.len() as i64); + } + } + + fn stable_read(&self, offset: u32, buf: &mut [u8]) { + unsafe { + ic0::stable_read(buf.as_ptr() as i32, offset as i32, buf.len() as i32); + } + } + + fn stable64_read(&self, offset: u64, buf: &mut [u8]) { + unsafe { + ic0::stable64_read(buf.as_ptr() as i64, offset as i64, buf.len() as i64); + } + } +} diff --git a/src/ic-cdk/src/api/stable/tests.rs b/src/ic-cdk/src/api/stable/tests.rs new file mode 100644 index 000000000..1606dbd53 --- /dev/null +++ b/src/ic-cdk/src/api/stable/tests.rs @@ -0,0 +1,154 @@ +use super::*; +use std::rc::Rc; +use std::sync::Mutex; + +#[derive(Default)] +pub struct TestStableMemory { + memory: Rc>>, +} + +impl TestStableMemory { + pub fn new(memory: Rc>>) -> TestStableMemory { + TestStableMemory { memory } + } +} + +impl StableMemory for TestStableMemory { + fn stable_size(&self) -> u32 { + let bytes_len = self.memory.lock().unwrap().len(); + let page_size = WASM_PAGE_SIZE_IN_BYTES as usize; + ((bytes_len + page_size - 1) / page_size) as u32 + } + + fn stable64_size(&self) -> u64 { + self.stable_size() as u64 + } + + fn stable_grow(&self, new_pages: u32) -> Result { + let new_bytes = new_pages as usize * WASM_PAGE_SIZE_IN_BYTES as usize; + + let mut vec = self.memory.lock().unwrap(); + let previous_len = vec.len(); + let new_len = vec.len() + new_bytes; + vec.resize(new_len, 0); + Ok((previous_len / WASM_PAGE_SIZE_IN_BYTES as usize) as u32) + } + + fn stable64_grow(&self, new_pages: u64) -> Result { + self.stable_grow(new_pages as u32).map(|len| len as u64) + } + + fn stable_write(&self, offset: u32, buf: &[u8]) { + let offset = offset as usize; + + let mut vec = self.memory.lock().unwrap(); + if offset + buf.len() > vec.len() { + panic!("stable memory out of bounds"); + } + vec[offset..(offset + buf.len())].clone_from_slice(buf); + } + + fn stable64_write(&self, offset: u64, buf: &[u8]) { + self.stable_write(offset as u32, buf) + } + + fn stable_read(&self, offset: u32, buf: &mut [u8]) { + let offset = offset as usize; + + let vec = self.memory.lock().unwrap(); + if offset + buf.len() < vec.len() { + panic!("stable memory out of bounds"); + } + buf[..vec.len()].copy_from_slice(&vec[offset..]); + } + + fn stable64_read(&self, offset: u64, buf: &mut [u8]) { + self.stable_read(offset as u32, buf) + } +} + +mod stable_writer_tests { + use super::*; + use rstest::rstest; + use std::io::Write; + + #[rstest] + #[case(None)] + #[case(Some(1))] + #[case(Some(10))] + #[case(Some(100))] + #[case(Some(1000))] + fn write_single_slice(#[case] buffer_size: Option) { + let memory = Rc::new(Mutex::new(Vec::new())); + let mut writer = build_writer(TestStableMemory::new(memory.clone()), buffer_size); + + let bytes = vec![1; 100]; + + writer.write_all(&bytes).unwrap(); + writer.flush().unwrap(); + + let result = &*memory.lock().unwrap(); + + assert_eq!(bytes, result[..bytes.len()]); + } + + #[rstest] + #[case(None)] + #[case(Some(1))] + #[case(Some(10))] + #[case(Some(100))] + #[case(Some(1000))] + fn write_many_slices(#[case] buffer_size: Option) { + let memory = Rc::new(Mutex::new(Vec::new())); + let mut writer = build_writer(TestStableMemory::new(memory.clone()), buffer_size); + + for i in 1..100 { + let bytes = vec![i as u8; i]; + writer.write_all(&bytes).unwrap(); + } + writer.flush().unwrap(); + + let result = &*memory.lock().unwrap(); + + let mut offset = 0; + for i in 1..100 { + let bytes = &result[offset..offset + i]; + assert_eq!(bytes, vec![i as u8; i]); + offset += i; + } + } + + #[rstest] + #[case(None)] + #[case(Some(1))] + #[case(Some(10))] + #[case(Some(100))] + #[case(Some(1000))] + fn ensure_only_requests_min_number_of_pages_required(#[case] buffer_size: Option) { + let memory = Rc::new(Mutex::new(Vec::new())); + let mut writer = build_writer(TestStableMemory::new(memory.clone()), buffer_size); + + let mut total_bytes = 0; + for i in 1..10000 { + let bytes = vec![i as u8; i]; + writer.write_all(&bytes).unwrap(); + total_bytes += i; + } + writer.flush().unwrap(); + + let capacity_pages = TestStableMemory::new(memory).stable64_size(); + let min_pages_required = + (total_bytes + WASM_PAGE_SIZE_IN_BYTES - 1) / WASM_PAGE_SIZE_IN_BYTES; + + assert_eq!(capacity_pages, min_pages_required as u64); + } + + fn build_writer(memory: TestStableMemory, buffer_size: Option) -> Box { + let writer = StableWriter::with_memory(memory, 0); + if let Some(buffer_size) = buffer_size { + Box::new(BufferedStableWriter::with_writer(buffer_size, writer)) + } else { + Box::new(writer) + } + } +} From cfcf72001a9ff8b0ab756ae765341f13a24285a8 Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Tue, 19 Apr 2022 21:13:45 +0100 Subject: [PATCH 043/234] feat: Add `BufferedStableReader` for efficient reading from stable memory (#247) * feat: Add `BufferedStableReader` for efficiently reading from stable memory * Update CHANGELOG * clippy --- src/ic-cdk/CHANGELOG.md | 1 + src/ic-cdk/src/api/stable.rs | 61 ++++++++++++++++++++++++------ src/ic-cdk/src/api/stable/tests.rs | 54 +++++++++++++++++++++++--- 3 files changed, 99 insertions(+), 17 deletions(-) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 727fe2023..049230df7 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] ### Added +- Add `BufferedStableReader` for efficient reading from stable memory (#247) - Add `BufferedStableWriter` for efficient writing to stable memory (#245) ## [0.5.0] - 2022-03-29 diff --git a/src/ic-cdk/src/api/stable.rs b/src/ic-cdk/src/api/stable.rs index baf58e52b..704cfa132 100644 --- a/src/ic-cdk/src/api/stable.rs +++ b/src/ic-cdk/src/api/stable.rs @@ -246,43 +246,82 @@ impl io::Write for BufferedStableWriter { /// A reader to the stable memory. /// /// Keeps an offset and reads off stable memory consecutively. -pub struct StableReader { +pub struct StableReader { /// The offset of the next read. offset: usize, + /// The capacity, in pages. capacity: u32, + + /// The stable memory to read data from. + memory: M, } impl Default for StableReader { fn default() -> Self { + Self::with_memory(CanisterStableMemory::default(), 0) + } +} + +impl StableReader { + /// Creates a new `StableReader` which reads from the selected memory + pub fn with_memory(memory: M, offset: usize) -> Self { + let capacity = memory.stable_size(); + Self { - offset: 0, - capacity: stable_size(), + offset, + capacity, + memory, } } -} -impl StableReader { /// Reads data from the stable memory location specified by an offset. pub fn read(&mut self, buf: &mut [u8]) -> Result { - let cap = (self.capacity as usize) << 16; - let read_buf = if buf.len() + self.offset > cap { - if self.offset < cap { - &mut buf[..cap - self.offset] + let capacity_bytes = self.capacity as usize * WASM_PAGE_SIZE_IN_BYTES; + let read_buf = if buf.len() + self.offset > capacity_bytes { + if self.offset < capacity_bytes { + &mut buf[..capacity_bytes - self.offset] } else { return Err(StableMemoryError::OutOfBounds); } } else { buf }; - stable_read(self.offset as u32, read_buf); + self.memory.stable_read(self.offset as u32, read_buf); self.offset += read_buf.len(); Ok(read_buf.len()) } } -impl io::Read for StableReader { +impl io::Read for StableReader { fn read(&mut self, buf: &mut [u8]) -> Result { self.read(buf).or(Ok(0)) // Read defines EOF to be success } } + +/// A reader to the stable memory which reads bytes a chunk at a time as each chunk is required. +pub struct BufferedStableReader { + inner: io::BufReader>, +} + +impl BufferedStableReader { + /// Creates a new `BufferedStableReader` + pub fn new(buffer_size: usize) -> BufferedStableReader { + BufferedStableReader::with_reader(buffer_size, StableReader::default()) + } +} + +impl BufferedStableReader { + /// Creates a new `BufferedStableReader` which reads from the selected memory + pub fn with_reader(buffer_size: usize, reader: StableReader) -> BufferedStableReader { + BufferedStableReader { + inner: io::BufReader::with_capacity(buffer_size, reader), + } + } +} + +impl io::Read for BufferedStableReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } +} diff --git a/src/ic-cdk/src/api/stable/tests.rs b/src/ic-cdk/src/api/stable/tests.rs index 1606dbd53..4bcb38c38 100644 --- a/src/ic-cdk/src/api/stable/tests.rs +++ b/src/ic-cdk/src/api/stable/tests.rs @@ -9,6 +9,13 @@ pub struct TestStableMemory { impl TestStableMemory { pub fn new(memory: Rc>>) -> TestStableMemory { + let bytes_len = memory.lock().unwrap().len(); + if bytes_len > 0 { + let pages_required = pages_required(bytes_len); + let bytes_required = pages_required * WASM_PAGE_SIZE_IN_BYTES; + memory.lock().unwrap().resize(bytes_required, 0); + } + TestStableMemory { memory } } } @@ -16,8 +23,7 @@ impl TestStableMemory { impl StableMemory for TestStableMemory { fn stable_size(&self) -> u32 { let bytes_len = self.memory.lock().unwrap().len(); - let page_size = WASM_PAGE_SIZE_IN_BYTES as usize; - ((bytes_len + page_size - 1) / page_size) as u32 + pages_required(bytes_len) as u32 } fn stable64_size(&self) -> u64 { @@ -56,10 +62,9 @@ impl StableMemory for TestStableMemory { let offset = offset as usize; let vec = self.memory.lock().unwrap(); - if offset + buf.len() < vec.len() { - panic!("stable memory out of bounds"); - } - buf[..vec.len()].copy_from_slice(&vec[offset..]); + let count_to_copy = buf.len(); + + buf[..count_to_copy].copy_from_slice(&vec[offset..offset + count_to_copy]); } fn stable64_read(&self, offset: u64, buf: &mut [u8]) { @@ -67,6 +72,11 @@ impl StableMemory for TestStableMemory { } } +fn pages_required(bytes_len: usize) -> usize { + let page_size = WASM_PAGE_SIZE_IN_BYTES as usize; + (bytes_len + page_size - 1) / page_size +} + mod stable_writer_tests { use super::*; use rstest::rstest; @@ -152,3 +162,35 @@ mod stable_writer_tests { } } } + +mod stable_reader_tests { + use super::*; + use rstest::rstest; + use std::io::Read; + + #[rstest] + #[case(None)] + #[case(Some(1))] + #[case(Some(10))] + #[case(Some(100))] + #[case(Some(1000))] + fn reads_all_bytes(#[case] buffer_size: Option) { + let input = vec![1; 10_000]; + let memory = Rc::new(Mutex::new(input.clone())); + let mut reader = build_reader(TestStableMemory::new(memory), buffer_size); + + let mut output = Vec::new(); + reader.read_to_end(&mut output).unwrap(); + + assert_eq!(input, output[..input.len()]); + } + + fn build_reader(memory: TestStableMemory, buffer_size: Option) -> Box { + let reader = StableReader::with_memory(memory, 0); + if let Some(buffer_size) = buffer_size { + Box::new(BufferedStableReader::with_reader(buffer_size, reader)) + } else { + Box::new(reader) + } + } +} From 20dc31d1811877aff1d6cd2c206046c7e2bc85fd Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Wed, 20 Apr 2022 18:25:08 +0200 Subject: [PATCH 044/234] chore(SDK-417): e2e tests for Rust CDK (#246) * SDK-417: e2e tests for Rust CDK This change introduces a framework for writing end-to-end tests for Rust CDK. The tests use a simple test framework developed for the IC repo, ic-state-machine-tests. The framework provides an easy-to-use interface to messaging and execution layer. The Wasm execution happens directly in the test process. The compilation of ic-state-machine tests takes a while, but incremental builds are quite fast (10 sec). A single test execution is also quite fast (10 sec for debug test run, 2.5 sec in release test run). The overall approach to testing: 1. Write a simple canister that uses the desired feature and put it under tests/canisters. 2. Add a test in tests/tests/e2e.rs that builds, installs, and interacts with the canister. * sipmle -> simple * add escargot 'print' feature * add wasm32-unknown-unknown target * Run e2e tests only on linux * move e2e tests into a separate workflow * update ic version and run e2e on macOS --- .github/workflows/e2e.yml | 53 ++++++++++++++++ .github/workflows/test.yml | 5 +- Cargo.toml | 7 +++ e2e-tests/Cargo.toml | 23 +++++++ e2e-tests/canisters/simple_kv_store.rs | 33 ++++++++++ e2e-tests/src/lib.rs | 41 ++++++++++++ e2e-tests/tests/e2e.rs | 86 ++++++++++++++++++++++++++ rust-toolchain.toml | 1 + 8 files changed, 247 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/e2e.yml create mode 100644 e2e-tests/Cargo.toml create mode 100644 e2e-tests/canisters/simple_kv_store.rs create mode 100644 e2e-tests/src/lib.rs create mode 100644 e2e-tests/tests/e2e.rs diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 000000000..62dd703ae --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,53 @@ +name: End-to-end Test + +on: + push: + branches: + - main + pull_request: + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + build: [ linux-stable ] + include: + - build: linux-stable + os: ubuntu-latest + rust: 1.58.1 + - build: macos-stable + os: macos-latest + rust: 1.58.1 + + steps: + - uses: actions/checkout@v2 + + - uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-1 + + - name: Install Rust + run: | + rustup update ${{ matrix.rust }} --no-self-update + rustup default ${{ matrix.rust }} + + - name: E2E tests + run: | + cargo test -p ic-cdk-e2e-tests + env: + RUST_BACKTRACE: 1 + + - name: Purge for OSX + if: matrix.os == 'macos-latest' + run: | + # There is a bug with BSD tar on macOS where the first 8MB of the file are + # sometimes all NUL bytes. See https://github.com/actions/cache/issues/403 + # and https://github.com/rust-lang/cargo/issues/8603 for some more + # information. An alternative solution here is to install GNU tar, but + # flushing the disk cache seems to work, too. + sudo /usr/sbin/purge \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9270965cb..509a256f8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -53,8 +53,9 @@ jobs: - name: Run Tests shell: bash run: | - # Test all features and no features for each package. - for p in $(cargo metadata --no-deps --format-version 1 | jq -r .packages[].manifest_path); do + # Test all features and no features for each package except e2e-tests. + # We run e2e tests in a separate workflow. + for p in $(cargo metadata --no-deps --format-version 1 | jq -r .packages[].manifest_path | grep -v e2e-tests); do pushd $(dirname $p) cargo test --all-targets --all-features cargo test --all-targets --no-default-features diff --git a/Cargo.toml b/Cargo.toml index dad10f75e..e506fb2eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,12 @@ members = [ "src/ic-certified-assets", "src/ic-certified-map", "src/ic-ledger-types", + "e2e-tests", ] +[profile.canister-release] +inherits = "release" +debug = false +panic = "abort" +lto = true +opt-level = 'z' \ No newline at end of file diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml new file mode 100644 index 000000000..81d80b0d7 --- /dev/null +++ b/e2e-tests/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "ic-cdk-e2e-tests" +version = "0.1.0" +authors = ["DFINITY Stiftung "] +edition = "2021" +description = "End-to-end tests for the Rust Canister Development Kit" +license = "Apache-2.0" +repository = "https://github.com/dfinity/cdk-rs" + +[dependencies] +candid = "0.7.4" +cargo_metadata = "0.14.2" +escargot = { version = "0.5.7", features = ["print"] } +serde_bytes = "0.11" +ic-cdk = { path = "../src/ic-cdk" } +ic-cdk-macros = { path = "../src/ic-cdk-macros" } + +[[bin]] +name = "simple-kv-store" +path = "canisters/simple_kv_store.rs" + +[dev-dependencies] +ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "709f9caaffd39c5d63f7ef1ec694eeb2a1b7976a" } diff --git a/e2e-tests/canisters/simple_kv_store.rs b/e2e-tests/canisters/simple_kv_store.rs new file mode 100644 index 000000000..632ec861c --- /dev/null +++ b/e2e-tests/canisters/simple_kv_store.rs @@ -0,0 +1,33 @@ +use ic_cdk_macros::{post_upgrade, pre_upgrade, query, update}; +use serde_bytes::ByteBuf; +use std::cell::RefCell; +use std::collections::BTreeMap; + +type Store = BTreeMap; + +thread_local! { + static STORE: RefCell = RefCell::default(); +} + +#[update] +fn insert(key: String, value: ByteBuf) { + STORE.with(|store| store.borrow_mut().insert(key, value)); +} + +#[query] +fn lookup(key: String) -> Option { + STORE.with(|store| store.borrow().get(&key).cloned()) +} + +#[pre_upgrade] +fn pre_upgrade() { + STORE.with(|store| ic_cdk::storage::stable_save((store,)).unwrap()); +} + +#[post_upgrade] +fn post_upgrade() { + let (persisted_store,): (Store,) = ic_cdk::storage::stable_restore().unwrap(); + STORE.with(|store| *store.borrow_mut() = persisted_store); +} + +fn main() {} diff --git a/e2e-tests/src/lib.rs b/e2e-tests/src/lib.rs new file mode 100644 index 000000000..39bb9bdce --- /dev/null +++ b/e2e-tests/src/lib.rs @@ -0,0 +1,41 @@ +use cargo_metadata::MetadataCommand; +use escargot::CargoBuild; +use std::path::PathBuf; + +/// Builds a canister with the specified name from the current +/// package and returns the WebAssembly module. +pub fn cargo_build_canister(bin_name: &str) -> Vec { + let dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); + + let cargo_toml_path = dir.join("Cargo.toml"); + + let target_dir = MetadataCommand::new() + .manifest_path(&cargo_toml_path) + .no_deps() + .exec() + .expect("failed to run cargo metadata") + .target_directory; + + // We use a different target path to stop the native cargo build + // cache being invalidated every time we run this function + let wasm_target_dir = target_dir.join("canister-build"); + + let cargo_build = CargoBuild::new() + .target("wasm32-unknown-unknown") + .bin(bin_name.to_string()) + .args(["--profile", "canister-release"]) + .manifest_path(&cargo_toml_path) + .target_dir(&wasm_target_dir); + + let binary = cargo_build + .run() + .expect("Cargo failed to compile the wasm binary"); + + std::fs::read(binary.path()).unwrap_or_else(|e| { + panic!( + "failed to read compiled Wasm file from {}: {}", + binary.path().display(), + e + ) + }) +} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs new file mode 100644 index 000000000..e116a8a30 --- /dev/null +++ b/e2e-tests/tests/e2e.rs @@ -0,0 +1,86 @@ +use candid::utils::{decode_args, encode_args, ArgumentDecoder, ArgumentEncoder}; +use ic_cdk_e2e_tests::cargo_build_canister; +use ic_state_machine_tests::{CanisterId, StateMachine, UserError, WasmResult}; +use serde_bytes::ByteBuf; + +#[derive(Debug)] +enum CallError { + Reject(String), + UserError(UserError), +} + +/// A helper function that we use to implement both [`call_candid`] and +/// [`query_candid`]. +fn with_candid( + input: Input, + f: impl FnOnce(Vec) -> Result, +) -> Result +where + Input: ArgumentEncoder, + Output: for<'a> ArgumentDecoder<'a>, +{ + let in_bytes = encode_args(input).expect("failed to encode args"); + match f(in_bytes) { + Ok(WasmResult::Reply(out_bytes)) => Ok(decode_args(&out_bytes).unwrap_or_else(|e| { + panic!( + "Failed to decode bytes {:?} as candid type: {}", + std::any::type_name::(), + e + ) + })), + Ok(WasmResult::Reject(message)) => Err(CallError::Reject(message)), + Err(user_error) => Err(CallError::UserError(user_error)), + } +} + +/// Call a canister candid method. +fn call_candid( + env: &StateMachine, + canister_id: CanisterId, + method: &str, + input: Input, +) -> Result +where + Input: ArgumentEncoder, + Output: for<'a> ArgumentDecoder<'a>, +{ + with_candid(input, |bytes| { + env.execute_ingress(canister_id, method, bytes) + }) +} + +/// Query a canister candid method. +fn query_candid( + env: &StateMachine, + canister_id: CanisterId, + method: &str, + input: Input, +) -> Result +where + Input: ArgumentEncoder, + Output: for<'a> ArgumentDecoder<'a>, +{ + with_candid(input, |bytes| env.query(canister_id, method, bytes)) +} + +/// Checks that a canister that uses [`ic_cdk::storage::stable_store`] +/// and [`ic_cdk::storage::stable_restore`] functions can keep its data +/// across upgrades. +#[test] +fn test_storage_roundtrip() { + let env = StateMachine::new(); + let kv_store_wasm = cargo_build_canister("simple-kv-store"); + let canister_id = env + .install_canister(kv_store_wasm.clone(), vec![], None) + .unwrap(); + + let () = call_candid(&env, canister_id, "insert", (&"candid", &b"did")) + .expect("failed to insert 'candid'"); + + env.upgrade_canister(canister_id, kv_store_wasm, vec![]) + .expect("failed to upgrade the simple-kv-store canister"); + + let (result,): (Option,) = + query_candid(&env, canister_id, "lookup", (&"candid",)).expect("failed to lookup 'candid'"); + assert_eq!(result, Some(ByteBuf::from(b"did".to_vec()))); +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 76b44e44c..47462fc08 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,4 @@ [toolchain] channel = "1.58.1" +targets = ["wasm32-unknown-unknown"] components = ["rustfmt", "clippy"] From 4ff72359407cd6e26df36328f405fab03459c9d3 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Tue, 26 Apr 2022 23:31:17 +0200 Subject: [PATCH 045/234] chore(SDK-417): add an e2d test for async cleanup (#250) * chore(SDK-417): add an e2d test for async cleanup This change adds an end-to-end test checking that the CDK frees canister resources if the canister traps after an async call. This feature was implemented in https://github.com/dfinity/cdk-rs/pull/232. --- e2e-tests/Cargo.toml | 7 ++++++- e2e-tests/canisters/async.rs | 34 ++++++++++++++++++++++++++++++++++ e2e-tests/tests/e2e.rs | 35 ++++++++++++++++++++++++++++++++++- src/ic-cdk/src/api/call.rs | 20 +++++++++++--------- 4 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 e2e-tests/canisters/async.rs diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 81d80b0d7..54775be90 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -11,13 +11,18 @@ repository = "https://github.com/dfinity/cdk-rs" candid = "0.7.4" cargo_metadata = "0.14.2" escargot = { version = "0.5.7", features = ["print"] } -serde_bytes = "0.11" ic-cdk = { path = "../src/ic-cdk" } ic-cdk-macros = { path = "../src/ic-cdk-macros" } +lazy_static = "1.4.0" +serde_bytes = "0.11" [[bin]] name = "simple-kv-store" path = "canisters/simple_kv_store.rs" +[[bin]] +name = "async" +path = "canisters/async.rs" + [dev-dependencies] ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "709f9caaffd39c5d63f7ef1ec694eeb2a1b7976a" } diff --git a/e2e-tests/canisters/async.rs b/e2e-tests/canisters/async.rs new file mode 100644 index 000000000..ebfb4a593 --- /dev/null +++ b/e2e-tests/canisters/async.rs @@ -0,0 +1,34 @@ +use ic_cdk_macros::{query, update}; +use lazy_static::lazy_static; +use std::sync::RwLock; + +lazy_static! { + static ref RESOURCE: RwLock = RwLock::new(0); +} + +#[query] +fn inc(n: u64) -> u64 { + n + 1 +} + +#[query] +fn invocation_count() -> u64 { + let lock = RESOURCE + .read() + .unwrap_or_else(|_| ic_cdk::api::trap("failed to obtain a read lock")); + *lock +} + +#[update] +async fn panic_after_async() { + let mut lock = RESOURCE + .write() + .unwrap_or_else(|_| ic_cdk::api::trap("failed to obtain a write lock")); + *lock += 1; + let _: (u64,) = ic_cdk::call(ic_cdk::api::id(), "inc", (*lock,)) + .await + .expect("failed to call self"); + ic_cdk::api::trap("Goodbye, cruel world.") +} + +fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index e116a8a30..8747ddf3c 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -1,6 +1,6 @@ use candid::utils::{decode_args, encode_args, ArgumentDecoder, ArgumentEncoder}; use ic_cdk_e2e_tests::cargo_build_canister; -use ic_state_machine_tests::{CanisterId, StateMachine, UserError, WasmResult}; +use ic_state_machine_tests::{CanisterId, ErrorCode, StateMachine, UserError, WasmResult}; use serde_bytes::ByteBuf; #[derive(Debug)] @@ -84,3 +84,36 @@ fn test_storage_roundtrip() { query_candid(&env, canister_id, "lookup", (&"candid",)).expect("failed to lookup 'candid'"); assert_eq!(result, Some(ByteBuf::from(b"did".to_vec()))); } + +#[test] +fn test_panic_after_async_frees_resources() { + let env = StateMachine::new(); + let wasm = cargo_build_canister("async"); + let canister_id = env + .install_canister(wasm, vec![], None) + .expect("failed to install a canister"); + + for i in 1..3 { + match call_candid(&env, canister_id, "panic_after_async", ()) { + Ok(()) => (), + Err(CallError::Reject(msg)) => panic!("unexpected reject: {}", msg), + Err(CallError::UserError(e)) => { + println!("Got a user error as expected: {}", e); + + assert_eq!(e.code(), ErrorCode::CanisterCalledTrap); + let expected_message = "Goodbye, cruel world."; + assert!( + e.description().contains(expected_message), + "Expected the user error to contain '{}', got: {}", + expected_message, + e.description() + ); + } + } + + let (n,): (u64,) = call_candid(&env, canister_id, "invocation_count", ()) + .expect("failed to call invocation_count"); + + assert_eq!(i, n, "expected the invocation count to be {}, got {}", i, n); + } +} diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 4b8e275cf..6f06651d3 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -222,17 +222,19 @@ fn callback(state_ptr: *const InnerCell>>) { /// Waker is a very opaque API, so the best we can do is set a global flag and proceed normally. fn cleanup(state_ptr: *const InnerCell>>) { let state = unsafe { WasmCell::from_raw(state_ptr) }; - // We set the call result, even though it won't be read on the default executor, because we can't guarantee it was called on our executor. - // None of these calls trap - the rollback from the previous trap ensures that the Mutex is not in a poisoned state. - { - state.borrow_mut().result = Some(match reject_code() { - RejectionCode::NoError => unsafe { Ok(arg_data_raw()) }, - n => Err((n, reject_message())), - }); - } + // We set the call result, even though it won't be read on the + // default executor, because we can't guarantee it was called on + // our executor. However, we are not allowed to inspect + // reject_code() inside of a cleanup callback, so always set the + // result to a reject. + // + // Borrowing does not trap - the rollback from the + // previous trap ensures that the WasmCell can be borrowed again. + state.borrow_mut().result = Some(Err((RejectionCode::NoError, "cleanup".to_string()))); let w = state.borrow_mut().waker.take(); if let Some(waker) = w { - // Flag that we do not want to actually wake the task - we want to drop it *without* executing it. + // Flag that we do not want to actually wake the task - we + // want to drop it *without* executing it. crate::futures::CLEANUP.store(true, Ordering::Relaxed); waker.wake(); crate::futures::CLEANUP.store(false, Ordering::Relaxed); From 976c4b8956849cf3590211465db908c6e405aa2b Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Thu, 5 May 2022 00:03:55 +0200 Subject: [PATCH 046/234] chore: add asset canister did interface check (#251) This change introduces a new test that checks that the certified assets canister library satisfies the assets.did interface expected by the dfx. The test revealed a minor discrepancy: method "delete_asset" was called "delete_contents" for some reason. Apparently, dfx never invokes this method. --- src/ic-certified-assets/assets.did | 140 +++++++++++++++++++++++++++++ src/ic-certified-assets/src/lib.rs | 40 ++++++++- 2 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 src/ic-certified-assets/assets.did diff --git a/src/ic-certified-assets/assets.did b/src/ic-certified-assets/assets.did new file mode 100644 index 000000000..d11ecd992 --- /dev/null +++ b/src/ic-certified-assets/assets.did @@ -0,0 +1,140 @@ +type BatchId = nat; +type ChunkId = nat; +type Key = text; +type Time = int; + +type CreateAssetArguments = record { + key: Key; + content_type: text; +}; + +// Add or change content for an asset, by content encoding +type SetAssetContentArguments = record { + key: Key; + content_encoding: text; + chunk_ids: vec ChunkId; + sha256: opt blob; +}; + +// Remove content for an asset, by content encoding +type UnsetAssetContentArguments = record { + key: Key; + content_encoding: text; +}; + +// Delete an asset +type DeleteAssetArguments = record { + key: Key; +}; + +// Reset everything +type ClearArguments = record {}; + +type BatchOperationKind = variant { + CreateAsset: CreateAssetArguments; + SetAssetContent: SetAssetContentArguments; + + UnsetAssetContent: UnsetAssetContentArguments; + DeleteAsset: DeleteAssetArguments; + + Clear: ClearArguments; +}; + +type HeaderField = record { text; text; }; + +type HttpRequest = record { + method: text; + url: text; + headers: vec HeaderField; + body: blob; +}; + +type HttpResponse = record { + status_code: nat16; + headers: vec HeaderField; + body: blob; + streaming_strategy: opt StreamingStrategy; +}; + +type StreamingCallbackHttpResponse = record { + body: blob; + token: opt StreamingCallbackToken; +}; + +type StreamingCallbackToken = record { + key: Key; + content_encoding: text; + index: nat; + sha256: opt blob; +}; + +type StreamingStrategy = variant { + Callback: record { + callback: func (StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query; + token: StreamingCallbackToken; + }; +}; + +service: { + + get: (record { + key: Key; + accept_encodings: vec text; + }) -> (record { + content: blob; // may be the entirety of the content, or just chunk index 0 + content_type: text; + content_encoding: text; + sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments + total_length: nat; // all chunks except last have size == content.size() + }) query; + + // if get() returned chunks > 1, call this to retrieve them. + // chunks may or may not be split up at the same boundaries as presented to create_chunk(). + get_chunk: (record { + key: Key; + content_encoding: text; + index: nat; + sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments + }) -> (record { content: blob }) query; + + list : (record {}) -> (vec record { + key: Key; + content_type: text; + encodings: vec record { + content_encoding: text; + sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments + length: nat; // Size of this encoding's blob. Calculated when uploading assets. + modified: Time; + }; + }) query; + + create_batch : (record {}) -> (record { batch_id: BatchId }); + + create_chunk: (record { batch_id: BatchId; content: blob }) -> (record { chunk_id: ChunkId }); + + // Perform all operations successfully, or reject + commit_batch: (record { batch_id: BatchId; operations: vec BatchOperationKind }) -> (); + + create_asset: (CreateAssetArguments) -> (); + set_asset_content: (SetAssetContentArguments) -> (); + unset_asset_content: (UnsetAssetContentArguments) -> (); + + delete_asset: (DeleteAssetArguments) -> (); + + clear: (ClearArguments) -> (); + + // Single call to create an asset with content for a single content encoding that + // fits within the message ingress limit. + store: (record { + key: Key; + content_type: text; + content_encoding: text; + content: blob; + sha256: opt blob + }) -> (); + + http_request: (request: HttpRequest) -> (HttpResponse) query; + http_request_streaming_callback: (token: StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query; + + authorize: (principal) -> (); +} diff --git a/src/ic-certified-assets/src/lib.rs b/src/ic-certified-assets/src/lib.rs index 86136160b..f83051e34 100644 --- a/src/ic-certified-assets/src/lib.rs +++ b/src/ic-certified-assets/src/lib.rs @@ -3,8 +3,8 @@ mod rc_bytes; mod tests; use crate::rc_bytes::RcBytes; +use candid::{candid_method, CandidType, Deserialize, Func, Int, Nat, Principal}; use ic_cdk::api::{caller, data_certificate, set_certified_data, time, trap}; -use ic_cdk::export::candid::{CandidType, Deserialize, Func, Int, Nat, Principal}; use ic_cdk_macros::{query, update}; use ic_certified_map::{AsHashTree, Hash, HashTree, RbTree}; use num_traits::ToPrimitive; @@ -237,6 +237,7 @@ struct StreamingCallbackHttpResponse { } #[update] +#[candid_method(update)] fn authorize(other: Principal) { let caller = caller(); STATE.with(|s| { @@ -248,6 +249,7 @@ fn authorize(other: Principal) { } #[query] +#[candid_method(query)] fn retrieve(key: Key) -> RcBytes { STATE.with(|s| { let assets = s.assets.borrow(); @@ -264,6 +266,7 @@ fn retrieve(key: Key) -> RcBytes { } #[update(guard = "is_authorized")] +#[candid_method(update)] fn store(arg: StoreArg) { STATE.with(move |s| { let mut assets = s.assets.borrow_mut(); @@ -288,6 +291,7 @@ fn store(arg: StoreArg) { } #[update(guard = "is_authorized")] +#[candid_method(update)] fn create_batch() -> CreateBatchResponse { STATE.with(|s| { let batch_id = s.next_batch_id.borrow().clone(); @@ -315,6 +319,7 @@ fn create_batch() -> CreateBatchResponse { } #[update(guard = "is_authorized")] +#[candid_method(update)] fn create_chunk(arg: CreateChunkArg) -> CreateChunkResponse { STATE.with(|s| { let mut batches = s.batches.borrow_mut(); @@ -340,31 +345,37 @@ fn create_chunk(arg: CreateChunkArg) -> CreateChunkResponse { } #[update(guard = "is_authorized")] +#[candid_method(update)] fn create_asset(arg: CreateAssetArguments) { do_create_asset(arg); } #[update(guard = "is_authorized")] +#[candid_method(update)] fn set_asset_content(arg: SetAssetContentArguments) { do_set_asset_content(arg); } #[update(guard = "is_authorized")] +#[candid_method(update)] fn unset_asset_content(arg: UnsetAssetContentArguments) { do_unset_asset_content(arg); } #[update(guard = "is_authorized")] -fn delete_content(arg: DeleteAssetArguments) { +#[candid_method(update)] +fn delete_asset(arg: DeleteAssetArguments) { do_delete_asset(arg); } #[update(guard = "is_authorized")] +#[candid_method(update)] fn clear() { do_clear(); } #[update(guard = "is_authorized")] +#[candid_method(update)] fn commit_batch(arg: CommitBatchArguments) { let batch_id = arg.batch_id; for op in arg.operations { @@ -382,6 +393,7 @@ fn commit_batch(arg: CommitBatchArguments) { } #[query] +#[candid_method(query)] fn get(arg: GetArg) -> EncodedAsset { STATE.with(|s| { let assets = s.assets.borrow(); @@ -405,6 +417,7 @@ fn get(arg: GetArg) -> EncodedAsset { } #[query] +#[candid_method(query)] fn get_chunk(arg: GetChunkArg) -> GetChunkResponse { STATE.with(|s| { let assets = s.assets.borrow(); @@ -434,6 +447,7 @@ fn get_chunk(arg: GetChunkArg) -> GetChunkResponse { } #[query] +#[candid_method(query)] fn list() -> Vec { STATE.with(|s| { s.assets @@ -680,6 +694,7 @@ fn redirect_to_url(host: &str, url: &str) -> Option { } #[query] +#[candid_method(query)] fn http_request(req: HttpRequest) -> HttpResponse { let mut encodings = vec![]; for (name, value) in req.headers.iter() { @@ -720,6 +735,7 @@ fn http_request(req: HttpRequest) -> HttpResponse { } #[query] +#[candid_method(query)] fn http_request_streaming_callback( StreamingCallbackToken { key, @@ -1013,3 +1029,23 @@ pub fn post_upgrade(stable_state: StableState) { } }); } + +#[test] +fn candid_interface_compatibility() { + use candid::utils::{service_compatible, CandidSource}; + use std::path::PathBuf; + + candid::export_service!(); + let new_interface = __export_service(); + + let old_interface = + PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("assets.did"); + + println!("Exported interface: {}", new_interface); + + service_compatible( + CandidSource::Text(&new_interface), + CandidSource::File(old_interface.as_path()), + ) + .expect("The assets canister interface is not compatible with the assets.did file"); +} From 30d0b245718e047d07edea44de03d446144c3844 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Mon, 9 May 2022 23:58:15 +0200 Subject: [PATCH 047/234] refactor: move pure assets certification code into a module (#252) This change is an extensive refactoring of the ic-certified-assets package. The motivation for this change is to make the code more testable and organized before adding caching logic. The general idea behind the refactoring is to split out the "state machine" logic into pure code that does not depend on Rust CDK and accepts all the environment (time, certificates, etc.) as function parameters. This logic moved to state_machine.rs. lib.rs now contains the minimal glue to connect the state machine to the Rust CDK interface. Eventually, this part should move back to https://github.com/dfinity/certified-assets, making the ic-certified-assets package independent from Rust CDK. The refactoring does not affect the certification logic; all we do is moving the code around, improving memory-correctness guarantees (no more RefCells in the state), and adding tests. --- src/ic-certified-assets/src/lib.rs | 998 ++----------------- src/ic-certified-assets/src/rc_bytes.rs | 3 +- src/ic-certified-assets/src/state_machine.rs | 728 ++++++++++++++ src/ic-certified-assets/src/tests.rs | 344 ++++++- src/ic-certified-assets/src/types.rs | 140 +++ src/ic-certified-assets/src/url_decode.rs | 63 ++ 6 files changed, 1343 insertions(+), 933 deletions(-) create mode 100644 src/ic-certified-assets/src/state_machine.rs create mode 100644 src/ic-certified-assets/src/types.rs create mode 100644 src/ic-certified-assets/src/url_decode.rs diff --git a/src/ic-certified-assets/src/lib.rs b/src/ic-certified-assets/src/lib.rs index f83051e34..31ef65296 100644 --- a/src/ic-certified-assets/src/lib.rs +++ b/src/ic-certified-assets/src/lib.rs @@ -1,239 +1,24 @@ +//! This module declares canister methods expected by the assets canister client. mod rc_bytes; +mod state_machine; +mod types; +mod url_decode; + #[cfg(test)] mod tests; -use crate::rc_bytes::RcBytes; -use candid::{candid_method, CandidType, Deserialize, Func, Int, Nat, Principal}; +use crate::{ + rc_bytes::RcBytes, + state_machine::{AssetDetails, EncodedAsset, StableState, State}, + types::*, +}; +use candid::{candid_method, Principal}; use ic_cdk::api::{caller, data_certificate, set_certified_data, time, trap}; use ic_cdk_macros::{query, update}; -use ic_certified_map::{AsHashTree, Hash, HashTree, RbTree}; -use num_traits::ToPrimitive; -use serde::Serialize; -use serde_bytes::ByteBuf; -use sha2::Digest; use std::cell::RefCell; -use std::collections::HashMap; -use std::convert::TryInto; -use std::fmt; - -/// The amount of time a batch is kept alive. Modifying the batch -/// delays the expiry further. -const BATCH_EXPIRY_NANOS: u64 = 300_000_000_000; - -/// The order in which we pick encodings for certification. -const ENCODING_CERTIFICATION_ORDER: &[&str] = &["identity", "gzip", "compress", "deflate", "br"]; - -/// The file to serve if the requested file wasn't found. -const INDEX_FILE: &str = "/index.html"; thread_local! { - static STATE: State = State::default(); - static ASSET_HASHES: RefCell = RefCell::new(RbTree::new()); -} - -type AssetHashes = RbTree; - -#[derive(Default)] -struct State { - assets: RefCell>, - - chunks: RefCell>, - next_chunk_id: RefCell, - - batches: RefCell>, - next_batch_id: RefCell, - - authorized: RefCell>, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct StableState { - authorized: Vec, - stable_assets: HashMap, -} - -#[derive(Default, Clone, Debug, CandidType, Deserialize)] -struct AssetEncoding { - modified: Timestamp, - content_chunks: Vec, - total_length: usize, - certified: bool, - sha256: [u8; 32], -} - -#[derive(Default, Clone, Debug, CandidType, Deserialize)] -struct Asset { - content_type: String, - encodings: HashMap, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct EncodedAsset { - content: RcBytes, - content_type: String, - content_encoding: String, - total_length: Nat, - sha256: Option, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct AssetDetails { - key: String, - content_type: String, - encodings: Vec, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct AssetEncodingDetails { - content_encoding: String, - sha256: Option, - length: Nat, - modified: Timestamp, -} - -struct Chunk { - batch_id: BatchId, - content: RcBytes, -} - -struct Batch { - expires_at: Timestamp, -} - -type Timestamp = Int; -type BatchId = Nat; -type ChunkId = Nat; -type Key = String; - -// IDL Types - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct CreateAssetArguments { - key: Key, - content_type: String, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct SetAssetContentArguments { - key: Key, - content_encoding: String, - chunk_ids: Vec, - sha256: Option, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct UnsetAssetContentArguments { - key: Key, - content_encoding: String, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct DeleteAssetArguments { - key: Key, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct ClearArguments {} - -#[derive(Clone, Debug, CandidType, Deserialize)] -enum BatchOperation { - CreateAsset(CreateAssetArguments), - SetAssetContent(SetAssetContentArguments), - UnsetAssetContent(UnsetAssetContentArguments), - DeleteAsset(DeleteAssetArguments), - Clear(ClearArguments), -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct CommitBatchArguments { - batch_id: BatchId, - operations: Vec, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct StoreArg { - key: Key, - content_type: String, - content_encoding: String, - content: ByteBuf, - sha256: Option, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct GetArg { - key: Key, - accept_encodings: Vec, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct GetChunkArg { - key: Key, - content_encoding: String, - index: Nat, - sha256: Option, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct GetChunkResponse { - content: RcBytes, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct CreateBatchResponse { - batch_id: BatchId, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct CreateChunkArg { - batch_id: BatchId, - content: ByteBuf, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct CreateChunkResponse { - chunk_id: ChunkId, -} -// HTTP interface - -type HeaderField = (String, String); - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct HttpRequest { - method: String, - url: String, - headers: Vec<(String, String)>, - body: ByteBuf, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct HttpResponse { - status_code: u16, - headers: Vec, - body: RcBytes, - streaming_strategy: Option, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct StreamingCallbackToken { - key: String, - content_encoding: String, - index: Nat, - // We don't care about the sha, we just want to be backward compatible. - sha256: Option, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -enum StreamingStrategy { - Callback { - callback: Func, - token: StreamingCallbackToken, - }, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -struct StreamingCallbackHttpResponse { - body: RcBytes, - token: Option, + static STATE: RefCell = RefCell::new(State::default()); } #[update] @@ -241,9 +26,8 @@ struct StreamingCallbackHttpResponse { fn authorize(other: Principal) { let caller = caller(); STATE.with(|s| { - let caller_autorized = s.authorized.borrow().iter().any(|p| *p == caller); - if caller_autorized { - s.authorized.borrow_mut().push(other); + if let Err(msg) = s.borrow_mut().authorize(&caller, other) { + trap(&msg); } }) } @@ -251,17 +35,9 @@ fn authorize(other: Principal) { #[query] #[candid_method(query)] fn retrieve(key: Key) -> RcBytes { - STATE.with(|s| { - let assets = s.assets.borrow(); - let asset = assets.get(&key).unwrap_or_else(|| trap("asset not found")); - let id_enc = asset - .encodings - .get("identity") - .unwrap_or_else(|| trap("no identity encoding")); - if id_enc.content_chunks.len() > 1 { - trap("Asset too large. Use get() and get_chunk() instead."); - } - id_enc.content_chunks[0].clone() + STATE.with(|s| match s.borrow().retrieve(&key) { + Ok(bytes) => bytes, + Err(msg) => trap(&msg), }) } @@ -269,764 +45,168 @@ fn retrieve(key: Key) -> RcBytes { #[candid_method(update)] fn store(arg: StoreArg) { STATE.with(move |s| { - let mut assets = s.assets.borrow_mut(); - let asset = assets.entry(arg.key.clone()).or_default(); - asset.content_type = arg.content_type; - - let hash = hash_bytes(&arg.content); - if let Some(provided_hash) = arg.sha256 { - if hash != provided_hash.as_ref() { - trap("sha256 mismatch"); - } + if let Err(msg) = s.borrow_mut().store(arg, time()) { + trap(&msg); } - - let encoding = asset.encodings.entry(arg.content_encoding).or_default(); - encoding.total_length = arg.content.len(); - encoding.content_chunks = vec![RcBytes::from(arg.content)]; - encoding.modified = Int::from(time() as u64); - encoding.sha256 = hash; - - on_asset_change(&arg.key, asset); + set_certified_data(&s.borrow().root_hash()); }); } #[update(guard = "is_authorized")] #[candid_method(update)] fn create_batch() -> CreateBatchResponse { - STATE.with(|s| { - let batch_id = s.next_batch_id.borrow().clone(); - *s.next_batch_id.borrow_mut() += 1; - - let now = time() as u64; - - let mut batches = s.batches.borrow_mut(); - batches.insert( - batch_id.clone(), - Batch { - expires_at: Int::from(now + BATCH_EXPIRY_NANOS), - }, - ); - s.chunks.borrow_mut().retain(|_, c| { - batches - .get(&c.batch_id) - .map(|b| b.expires_at > now) - .unwrap_or(false) - }); - batches.retain(|_, b| b.expires_at > now); - - CreateBatchResponse { batch_id } + STATE.with(|s| CreateBatchResponse { + batch_id: s.borrow_mut().create_batch(time()), }) } #[update(guard = "is_authorized")] #[candid_method(update)] fn create_chunk(arg: CreateChunkArg) -> CreateChunkResponse { - STATE.with(|s| { - let mut batches = s.batches.borrow_mut(); - let now = time() as u64; - let mut batch = batches - .get_mut(&arg.batch_id) - .unwrap_or_else(|| trap("batch not found")); - batch.expires_at = Int::from(now + BATCH_EXPIRY_NANOS); - - let chunk_id = s.next_chunk_id.borrow().clone(); - *s.next_chunk_id.borrow_mut() += 1; - - s.chunks.borrow_mut().insert( - chunk_id.clone(), - Chunk { - batch_id: arg.batch_id, - content: RcBytes::from(arg.content), - }, - ); - - CreateChunkResponse { chunk_id } + STATE.with(|s| match s.borrow_mut().create_chunk(arg, time()) { + Ok(chunk_id) => CreateChunkResponse { chunk_id }, + Err(msg) => trap(&msg), }) } #[update(guard = "is_authorized")] #[candid_method(update)] fn create_asset(arg: CreateAssetArguments) { - do_create_asset(arg); + STATE.with(|s| { + if let Err(msg) = s.borrow_mut().create_asset(arg) { + trap(&msg); + } + set_certified_data(&s.borrow().root_hash()); + }) } #[update(guard = "is_authorized")] #[candid_method(update)] fn set_asset_content(arg: SetAssetContentArguments) { - do_set_asset_content(arg); + STATE.with(|s| { + if let Err(msg) = s.borrow_mut().set_asset_content(arg, time()) { + trap(&msg); + } + set_certified_data(&s.borrow().root_hash()); + }) } #[update(guard = "is_authorized")] #[candid_method(update)] fn unset_asset_content(arg: UnsetAssetContentArguments) { - do_unset_asset_content(arg); + STATE.with(|s| { + if let Err(msg) = s.borrow_mut().unset_asset_content(arg) { + trap(&msg); + } + set_certified_data(&s.borrow().root_hash()); + }) } #[update(guard = "is_authorized")] #[candid_method(update)] fn delete_asset(arg: DeleteAssetArguments) { - do_delete_asset(arg); + STATE.with(|s| { + s.borrow_mut().delete_asset(arg); + set_certified_data(&s.borrow().root_hash()); + }); } #[update(guard = "is_authorized")] #[candid_method(update)] fn clear() { - do_clear(); + STATE.with(|s| { + s.borrow_mut().clear(); + set_certified_data(&s.borrow().root_hash()); + }); } #[update(guard = "is_authorized")] #[candid_method(update)] fn commit_batch(arg: CommitBatchArguments) { - let batch_id = arg.batch_id; - for op in arg.operations { - match op { - BatchOperation::CreateAsset(arg) => do_create_asset(arg), - BatchOperation::SetAssetContent(arg) => do_set_asset_content(arg), - BatchOperation::UnsetAssetContent(arg) => do_unset_asset_content(arg), - BatchOperation::DeleteAsset(arg) => do_delete_asset(arg), - BatchOperation::Clear(_) => do_clear(), - } - } STATE.with(|s| { - s.batches.borrow_mut().remove(&batch_id); - }) + if let Err(msg) = s.borrow_mut().commit_batch(arg, time()) { + trap(&msg); + } + set_certified_data(&s.borrow().root_hash()); + }); } #[query] #[candid_method(query)] fn get(arg: GetArg) -> EncodedAsset { - STATE.with(|s| { - let assets = s.assets.borrow(); - let asset = assets.get(&arg.key).unwrap_or_else(|| { - trap("asset not found"); - }); - - for enc in arg.accept_encodings.iter() { - if let Some(asset_enc) = asset.encodings.get(enc) { - return EncodedAsset { - content: asset_enc.content_chunks[0].clone(), - content_type: asset.content_type.clone(), - content_encoding: enc.clone(), - total_length: Nat::from(asset_enc.total_length as u64), - sha256: Some(ByteBuf::from(asset_enc.sha256)), - }; - } - } - trap("no such encoding"); + STATE.with(|s| match s.borrow().get(arg) { + Ok(asset) => asset, + Err(msg) => trap(&msg), }) } #[query] #[candid_method(query)] fn get_chunk(arg: GetChunkArg) -> GetChunkResponse { - STATE.with(|s| { - let assets = s.assets.borrow(); - let asset = assets - .get(&arg.key) - .unwrap_or_else(|| trap("asset not found")); - - let enc = asset - .encodings - .get(&arg.content_encoding) - .unwrap_or_else(|| trap("no such encoding")); - - if let Some(expected_hash) = arg.sha256 { - if expected_hash != enc.sha256 { - trap("sha256 mismatch") - } - } - if arg.index >= enc.content_chunks.len() { - trap("chunk index out of bounds"); - } - let index: usize = arg.index.0.to_usize().unwrap(); - - GetChunkResponse { - content: enc.content_chunks[index].clone(), - } + STATE.with(|s| match s.borrow().get_chunk(arg) { + Ok(content) => GetChunkResponse { content }, + Err(msg) => trap(&msg), }) } #[query] #[candid_method(query)] fn list() -> Vec { - STATE.with(|s| { - s.assets - .borrow() - .iter() - .map(|(key, asset)| { - let mut encodings: Vec<_> = asset - .encodings - .iter() - .map(|(enc_name, enc)| AssetEncodingDetails { - content_encoding: enc_name.clone(), - sha256: Some(ByteBuf::from(enc.sha256)), - length: Nat::from(enc.total_length), - modified: enc.modified.clone(), - }) - .collect(); - encodings.sort_by(|l, r| l.content_encoding.cmp(&r.content_encoding)); - - AssetDetails { - key: key.clone(), - content_type: asset.content_type.clone(), - encodings, - } - }) - .collect::>() - }) -} - -fn create_token( - _asset: &Asset, - enc_name: &str, - enc: &AssetEncoding, - key: &str, - chunk_index: usize, -) -> Option { - if chunk_index + 1 >= enc.content_chunks.len() { - None - } else { - Some(StreamingCallbackToken { - key: key.to_string(), - content_encoding: enc_name.to_string(), - index: Nat::from(chunk_index + 1), - sha256: Some(ByteBuf::from(enc.sha256)), - }) - } -} - -fn create_strategy( - asset: &Asset, - enc_name: &str, - enc: &AssetEncoding, - key: &str, - chunk_index: usize, -) -> Option { - create_token(asset, enc_name, enc, key, chunk_index).map(|token| StreamingStrategy::Callback { - callback: ic_cdk::export::candid::Func { - method: "http_request_streaming_callback".to_string(), - principal: ic_cdk::id(), - }, - token, - }) -} - -fn build_200( - asset: &Asset, - enc_name: &str, - enc: &AssetEncoding, - key: &str, - chunk_index: usize, - certificate_header: Option, -) -> HttpResponse { - let mut headers = vec![("Content-Type".to_string(), asset.content_type.to_string())]; - if enc_name != "identity" { - headers.push(("Content-Encoding".to_string(), enc_name.to_string())); - } - if let Some(head) = certificate_header { - headers.push(head); - } - - let streaming_strategy = create_strategy(asset, enc_name, enc, key, chunk_index); - - HttpResponse { - status_code: 200, - headers, - body: enc.content_chunks[chunk_index].clone(), - streaming_strategy, - } -} - -fn build_404(certificate_header: HeaderField) -> HttpResponse { - HttpResponse { - status_code: 404, - headers: vec![certificate_header], - body: RcBytes::from(ByteBuf::from("not found")), - streaming_strategy: None, - } -} - -fn build_http_response(path: &str, encodings: Vec, index: usize) -> HttpResponse { - STATE.with(|s| { - let assets = s.assets.borrow(); - - let index_redirect_certificate = ASSET_HASHES.with(|t| { - let tree = t.borrow(); - if tree.get(path.as_bytes()).is_none() && tree.get(INDEX_FILE.as_bytes()).is_some() { - let absence_proof = tree.witness(path.as_bytes()); - let index_proof = tree.witness(INDEX_FILE.as_bytes()); - let combined_proof = merge_hash_trees(absence_proof, index_proof); - Some(witness_to_header(combined_proof)) - } else { - None - } - }); - - if let Some(certificate_header) = index_redirect_certificate { - if let Some(asset) = assets.get(INDEX_FILE) { - for enc_name in encodings.iter() { - if let Some(enc) = asset.encodings.get(enc_name) { - if enc.certified { - return build_200( - asset, - enc_name, - enc, - INDEX_FILE, - index, - Some(certificate_header), - ); - } - } - } - } - } - - let certificate_header = - ASSET_HASHES.with(|t| witness_to_header(t.borrow().witness(path.as_bytes()))); - - if let Some(asset) = assets.get(path) { - for enc_name in encodings.iter() { - if let Some(enc) = asset.encodings.get(enc_name) { - if enc.certified { - return build_200( - asset, - enc_name, - enc, - path, - index, - Some(certificate_header), - ); - } else { - // Find if identity is certified, if it's not. - if let Some(id_enc) = asset.encodings.get("identity") { - if id_enc.certified { - return build_200( - asset, - enc_name, - enc, - path, - index, - Some(certificate_header), - ); - } - } - } - } - } - } - - build_404(certificate_header) - }) -} - -/// An iterator-like structure that decode a URL. -struct UrlDecode<'a> { - bytes: std::slice::Iter<'a, u8>, -} - -fn convert_percent(iter: &mut std::slice::Iter) -> Option { - let mut cloned_iter = iter.clone(); - let result = match cloned_iter.next()? { - b'%' => b'%', - h => { - let h = char::from(*h).to_digit(16)?; - let l = char::from(*cloned_iter.next()?).to_digit(16)?; - h as u8 * 0x10 + l as u8 - } - }; - // Update this if we make it this far, otherwise "reset" the iterator. - *iter = cloned_iter; - Some(result) -} - -#[derive(Debug, PartialEq)] -pub enum UrlDecodeError { - InvalidPercentEncoding, -} - -impl fmt::Display for UrlDecodeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::InvalidPercentEncoding => write!(f, "invalid percent encoding"), - } - } -} - -impl<'a> Iterator for UrlDecode<'a> { - type Item = Result; - - fn next(&mut self) -> Option { - let b = self.bytes.next()?; - match b { - b'%' => Some( - convert_percent(&mut self.bytes) - .map(char::from) - .ok_or(UrlDecodeError::InvalidPercentEncoding), - ), - b'+' => Some(Ok(' ')), - x => Some(Ok(char::from(*x))), - } - } - - fn size_hint(&self) -> (usize, Option) { - let bytes = self.bytes.len(); - (bytes / 3, Some(bytes)) - } -} - -fn url_decode(url: &str) -> Result { - UrlDecode { - bytes: url.as_bytes().iter(), - } - .collect() -} - -fn redirect_to_url(host: &str, url: &str) -> Option { - if let Some(host) = host.split(':').next() { - let host = host.trim(); - if host == "raw.ic0.app" { - return Some(format!("https://ic0.app{}", url)); - } else if let Some(base) = host.strip_suffix(".raw.ic0.app") { - return Some(format!("https://{}.ic0.app{}", base, url)); - } - } - None + STATE.with(|s| s.borrow().list_assets()) } #[query] #[candid_method(query)] fn http_request(req: HttpRequest) -> HttpResponse { - let mut encodings = vec![]; - for (name, value) in req.headers.iter() { - if name.eq_ignore_ascii_case("Accept-Encoding") { - for v in value.split(',') { - encodings.push(v.trim().to_string()); - } - } - if name.eq_ignore_ascii_case("Host") { - if let Some(replacement_url) = redirect_to_url(value, &req.url) { - return HttpResponse { - status_code: 308, - headers: vec![("Location".to_string(), replacement_url)], - body: RcBytes::from(ByteBuf::default()), - streaming_strategy: None, - }; - } - } - } - encodings.push("identity".to_string()); - - let path = match req.url.find('?') { - Some(i) => &req.url[..i], - None => &req.url[..], - }; - match url_decode(path) { - Ok(path) => build_http_response(&path, encodings, 0), - Err(err) => HttpResponse { - status_code: 400, - headers: vec![], - body: RcBytes::from(ByteBuf::from(format!( - "failed to decode path '{}': {}", - path, err - ))), - streaming_strategy: None, - }, - } -} - -#[query] -#[candid_method(query)] -fn http_request_streaming_callback( - StreamingCallbackToken { - key, - content_encoding, - index, - sha256, - }: StreamingCallbackToken, -) -> StreamingCallbackHttpResponse { - STATE.with(|s| { - let assets = s.assets.borrow(); - let asset = assets - .get(&key) - .expect("Invalid token on streaming: key not found."); - let enc = asset - .encodings - .get(&content_encoding) - .expect("Invalid token on streaming: encoding not found."); - - if let Some(expected_hash) = sha256 { - if expected_hash != enc.sha256 { - trap("sha256 mismatch"); - } - } - - // MAX is good enough. This means a chunk would be above 64-bits, which is impossible... - let chunk_index = index.0.to_usize().unwrap_or(usize::MAX); - - StreamingCallbackHttpResponse { - body: enc.content_chunks[chunk_index].clone(), - token: create_token(asset, &content_encoding, enc, &key, chunk_index), - } - }) -} - -fn do_create_asset(arg: CreateAssetArguments) { - STATE.with(|s| { - let mut assets = s.assets.borrow_mut(); - if let Some(asset) = assets.get(&arg.key) { - if asset.content_type != arg.content_type { - trap("create_asset: content type mismatch"); - } - } else { - assets.insert( - arg.key, - Asset { - content_type: arg.content_type, - encodings: HashMap::new(), - }, - ); - } - }) -} - -fn do_set_asset_content(arg: SetAssetContentArguments) { - STATE.with(|s| { - if arg.chunk_ids.is_empty() { - trap("encoding must have at least one chunk"); - } - - let mut assets = s.assets.borrow_mut(); - let asset = assets - .get_mut(&arg.key) - .unwrap_or_else(|| trap("asset not found")); - let now = Int::from(time() as u64); - - let mut chunks = s.chunks.borrow_mut(); - - let mut content_chunks = vec![]; - for chunk_id in arg.chunk_ids.iter() { - let chunk = chunks.remove(chunk_id).expect("chunk not found"); - content_chunks.push(chunk.content); - } - - let sha256: [u8; 32] = match arg.sha256 { - Some(bytes) => bytes - .into_vec() - .try_into() - .unwrap_or_else(|_| trap("invalid SHA-256")), - None => { - let mut hasher = sha2::Sha256::new(); - for chunk in content_chunks.iter() { - hasher.update(chunk); - } - hasher.finalize().into() - } - }; - - let total_length: usize = content_chunks.iter().map(|c| c.len()).sum(); - let enc = AssetEncoding { - modified: now, - content_chunks, - certified: false, - total_length, - sha256, - }; - asset.encodings.insert(arg.content_encoding, enc); - - on_asset_change(&arg.key, asset); - }) -} + let certificate = data_certificate().unwrap_or_else(|| trap("no data certificate available")); -fn do_unset_asset_content(arg: UnsetAssetContentArguments) { STATE.with(|s| { - let mut assets = s.assets.borrow_mut(); - let asset = assets - .get_mut(&arg.key) - .unwrap_or_else(|| trap("asset not found")); - - if asset.encodings.remove(&arg.content_encoding).is_some() { - on_asset_change(&arg.key, asset); - } + s.borrow().http_request( + req, + &certificate, + candid::Func { + method: "http_request_streaming_callback".to_string(), + principal: ic_cdk::id(), + }, + ) }) } -fn do_delete_asset(arg: DeleteAssetArguments) { - STATE.with(|s| { - let mut assets = s.assets.borrow_mut(); - assets.remove(&arg.key); - }); - delete_asset_hash(&arg.key); -} - -fn do_clear() { +#[query] +#[candid_method(query)] +fn http_request_streaming_callback(token: StreamingCallbackToken) -> StreamingCallbackHttpResponse { STATE.with(|s| { - s.assets.borrow_mut().clear(); - s.batches.borrow_mut().clear(); - s.chunks.borrow_mut().clear(); - *s.next_batch_id.borrow_mut() = Nat::from(1); - *s.next_chunk_id.borrow_mut() = Nat::from(1); + s.borrow() + .http_request_streaming_callback(token) + .unwrap_or_else(|msg| trap(&msg)) }) } -pub fn is_authorized() -> Result<(), String> { +fn is_authorized() -> Result<(), String> { STATE.with(|s| { - s.authorized - .borrow() - .contains(&caller()) + s.borrow() + .is_authorized(&caller()) .then(|| ()) .ok_or_else(|| "Caller is not authorized".to_string()) }) } -fn on_asset_change(key: &str, asset: &mut Asset) { - // If the most preferred encoding is present and certified, - // there is nothing to do. - for enc_name in ENCODING_CERTIFICATION_ORDER.iter() { - if let Some(enc) = asset.encodings.get(*enc_name) { - if enc.certified { - return; - } else { - break; - } - } - } - - if asset.encodings.is_empty() { - delete_asset_hash(key); - return; - } - - // An encoding with a higher priority was added, let's certify it - // instead. - - for enc in asset.encodings.values_mut() { - enc.certified = false; - } - - for enc_name in ENCODING_CERTIFICATION_ORDER.iter() { - if let Some(enc) = asset.encodings.get_mut(*enc_name) { - certify_asset(key.to_string(), &enc.sha256); - enc.certified = true; - return; - } - } - - // No known encodings found. Just pick the first one. The exact - // order is hard to predict because we use a hash map. Should - // almost never happen anyway. - if let Some(enc) = asset.encodings.values_mut().next() { - certify_asset(key.to_string(), &enc.sha256); - enc.certified = true; - } -} - -fn certify_asset(key: Key, content_hash: &Hash) { - ASSET_HASHES.with(|t| { - let mut tree = t.borrow_mut(); - tree.insert(key, *content_hash); - set_root_hash(&*tree); - }); -} - -fn delete_asset_hash(key: &str) { - ASSET_HASHES.with(|t| { - let mut tree = t.borrow_mut(); - tree.delete(key.as_bytes()); - set_root_hash(&*tree); - }); -} - -fn set_root_hash(tree: &AssetHashes) { - use ic_certified_map::labeled_hash; - let full_tree_hash = labeled_hash(b"http_assets", &tree.root_hash()); - set_certified_data(&full_tree_hash); -} - -fn witness_to_header(witness: HashTree) -> HeaderField { - use ic_certified_map::labeled; - - let hash_tree = labeled(b"http_assets", witness); - let mut serializer = serde_cbor::ser::Serializer::new(vec![]); - serializer.self_describe().unwrap(); - hash_tree.serialize(&mut serializer).unwrap(); - - let certificate = data_certificate().unwrap_or_else(|| trap("no data certificate available")); - - ( - "IC-Certificate".to_string(), - String::from("certificate=:") - + &base64::encode(&certificate) - + ":, tree=:" - + &base64::encode(&serializer.into_inner()) - + ":", - ) -} - -fn merge_hash_trees<'a>(lhs: HashTree<'a>, rhs: HashTree<'a>) -> HashTree<'a> { - use HashTree::{Empty, Fork, Labeled, Leaf, Pruned}; - - match (lhs, rhs) { - (Pruned(l), Pruned(r)) => { - if l != r { - trap("merge_hash_trees: inconsistent hashes"); - } - Pruned(l) - } - (Pruned(_), r) => r, - (l, Pruned(_)) => l, - (Fork(l), Fork(r)) => Fork(Box::new(( - merge_hash_trees(l.0, r.0), - merge_hash_trees(l.1, r.1), - ))), - (Labeled(l_label, l), Labeled(r_label, r)) => { - if l_label != r_label { - trap("merge_hash_trees: inconsistent hash tree labels"); - } - Labeled(l_label, Box::new(merge_hash_trees(*l, *r))) - } - (Empty, Empty) => Empty, - (Leaf(l), Leaf(r)) => { - if l != r { - trap("merge_hash_trees: inconsistent leaves"); - } - Leaf(l) - } - (_l, _r) => { - trap("merge_hash_trees: inconsistent tree structure"); - } - } -} - -fn hash_bytes(bytes: &[u8]) -> Hash { - let mut hash = sha2::Sha256::new(); - hash.update(bytes); - hash.finalize().into() -} - pub fn init() { - do_clear(); - STATE.with(|s| s.authorized.borrow_mut().push(caller())); + STATE.with(|s| { + let mut s = s.borrow_mut(); + s.clear(); + s.authorize_unconditionally(caller()); + }); } pub fn pre_upgrade() -> StableState { - STATE.with(|s| StableState { - authorized: s.authorized.take(), - stable_assets: s.assets.take(), - }) + STATE.with(|s| s.take().into()) } pub fn post_upgrade(stable_state: StableState) { - do_clear(); STATE.with(|s| { - s.authorized.replace(stable_state.authorized); - s.assets.replace(stable_state.stable_assets); - - for (asset_name, asset) in s.assets.borrow_mut().iter_mut() { - for enc in asset.encodings.values_mut() { - enc.certified = false; - } - on_asset_change(asset_name, asset); - } + *s.borrow_mut() = State::from(stable_state); + set_certified_data(&s.borrow().root_hash()); }); } diff --git a/src/ic-certified-assets/src/rc_bytes.rs b/src/ic-certified-assets/src/rc_bytes.rs index bc376e85f..469d670cc 100644 --- a/src/ic-certified-assets/src/rc_bytes.rs +++ b/src/ic-certified-assets/src/rc_bytes.rs @@ -1,3 +1,4 @@ +//! This module contains an implementation of [RcBytes], a reference-counted byte array. use ic_cdk::export::candid::{ types::{internal::Type, Serializer}, CandidType, Deserialize, @@ -9,7 +10,7 @@ use std::ops::Deref; use std::rc::Rc; #[derive(Clone, Debug)] -pub(crate) struct RcBytes(Rc); +pub struct RcBytes(Rc); impl CandidType for RcBytes { fn _ty() -> Type { diff --git a/src/ic-certified-assets/src/state_machine.rs b/src/ic-certified-assets/src/state_machine.rs new file mode 100644 index 000000000..01182888d --- /dev/null +++ b/src/ic-certified-assets/src/state_machine.rs @@ -0,0 +1,728 @@ +//! This module contains a pure implementation of the certified assets state machine. + +// NB. This module should not depend on ic_cdk, it contains only pure state transition functions. +// All the environment (time, certificates, etc.) is passed to the state transition functions +// as formal arguments. This approach makes it very easy to test the state machine. + +use crate::{rc_bytes::RcBytes, types::*, url_decode::url_decode}; +use candid::{CandidType, Deserialize, Func, Int, Nat, Principal}; +use ic_certified_map::{AsHashTree, Hash, HashTree, RbTree}; +use num_traits::ToPrimitive; +use serde::Serialize; +use serde_bytes::ByteBuf; +use sha2::Digest; +use std::collections::HashMap; +use std::convert::TryInto; + +/// The amount of time a batch is kept alive. Modifying the batch +/// delays the expiry further. +pub const BATCH_EXPIRY_NANOS: u64 = 300_000_000_000; + +/// The order in which we pick encodings for certification. +const ENCODING_CERTIFICATION_ORDER: &[&str] = &["identity", "gzip", "compress", "deflate", "br"]; + +/// The file to serve if the requested file wasn't found. +const INDEX_FILE: &str = "/index.html"; + +type AssetHashes = RbTree; +type Timestamp = Int; + +#[derive(Default, Clone, Debug, CandidType, Deserialize)] +pub struct AssetEncoding { + pub modified: Timestamp, + pub content_chunks: Vec, + pub total_length: usize, + pub certified: bool, + pub sha256: [u8; 32], +} + +#[derive(Default, Clone, Debug, CandidType, Deserialize)] +pub struct Asset { + pub content_type: String, + pub encodings: HashMap, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct EncodedAsset { + pub content: RcBytes, + pub content_type: String, + pub content_encoding: String, + pub total_length: Nat, + pub sha256: Option, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct AssetDetails { + pub key: String, + pub content_type: String, + pub encodings: Vec, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct AssetEncodingDetails { + pub content_encoding: String, + pub sha256: Option, + pub length: Nat, + pub modified: Timestamp, +} + +pub struct Chunk { + pub batch_id: BatchId, + pub content: RcBytes, +} + +pub struct Batch { + pub expires_at: Timestamp, +} + +#[derive(Default)] +pub struct State { + assets: HashMap, + + chunks: HashMap, + next_chunk_id: ChunkId, + + batches: HashMap, + next_batch_id: BatchId, + + authorized: Vec, + + asset_hashes: AssetHashes, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct StableState { + authorized: Vec, + stable_assets: HashMap, +} + +impl State { + pub fn authorize_unconditionally(&mut self, principal: Principal) { + if !self.is_authorized(&principal) { + self.authorized.push(principal); + } + } + + pub fn authorize(&mut self, caller: &Principal, other: Principal) -> Result<(), String> { + if !self.is_authorized(caller) { + return Err("the caller is not authorized".to_string()); + } + self.authorize_unconditionally(other); + Ok(()) + } + + pub fn root_hash(&self) -> Hash { + use ic_certified_map::labeled_hash; + labeled_hash(b"http_assets", &self.asset_hashes.root_hash()) + } + + pub fn create_asset(&mut self, arg: CreateAssetArguments) -> Result<(), String> { + if let Some(asset) = self.assets.get(&arg.key) { + if asset.content_type != arg.content_type { + return Err("create_asset: content type mismatch".to_string()); + } + } else { + self.assets.insert( + arg.key, + Asset { + content_type: arg.content_type, + encodings: HashMap::new(), + }, + ); + } + Ok(()) + } + + pub fn set_asset_content( + &mut self, + arg: SetAssetContentArguments, + now: u64, + ) -> Result<(), String> { + if arg.chunk_ids.is_empty() { + return Err("encoding must have at least one chunk".to_string()); + } + + let asset = self + .assets + .get_mut(&arg.key) + .ok_or_else(|| "asset not found".to_string())?; + + let now = Int::from(now); + + let mut content_chunks = vec![]; + for chunk_id in arg.chunk_ids.iter() { + let chunk = self.chunks.remove(chunk_id).expect("chunk not found"); + content_chunks.push(chunk.content); + } + + let sha256: [u8; 32] = match arg.sha256 { + Some(bytes) => bytes + .into_vec() + .try_into() + .map_err(|_| "invalid SHA-256".to_string())?, + None => { + let mut hasher = sha2::Sha256::new(); + for chunk in content_chunks.iter() { + hasher.update(chunk); + } + hasher.finalize().into() + } + }; + + let total_length: usize = content_chunks.iter().map(|c| c.len()).sum(); + let enc = AssetEncoding { + modified: now, + content_chunks, + certified: false, + total_length, + sha256, + }; + asset.encodings.insert(arg.content_encoding, enc); + + on_asset_change(&mut self.asset_hashes, &arg.key, asset); + + Ok(()) + } + + pub fn unset_asset_content(&mut self, arg: UnsetAssetContentArguments) -> Result<(), String> { + let asset = self + .assets + .get_mut(&arg.key) + .ok_or_else(|| "asset not found".to_string())?; + + if asset.encodings.remove(&arg.content_encoding).is_some() { + on_asset_change(&mut self.asset_hashes, &arg.key, asset); + } + + Ok(()) + } + + pub fn delete_asset(&mut self, arg: DeleteAssetArguments) { + self.assets.remove(&arg.key); + self.asset_hashes.delete(arg.key.as_bytes()); + } + + pub fn clear(&mut self) { + self.assets.clear(); + self.batches.clear(); + self.chunks.clear(); + self.next_batch_id = Nat::from(1); + self.next_chunk_id = Nat::from(1); + } + + pub fn is_authorized(&self, principal: &Principal) -> bool { + self.authorized.contains(principal) + } + + pub fn retrieve(&self, key: &Key) -> Result { + let asset = self + .assets + .get(key) + .ok_or_else(|| "asset not found".to_string())?; + + let id_enc = asset + .encodings + .get("identity") + .ok_or_else(|| "no identity encoding".to_string())?; + + if id_enc.content_chunks.len() > 1 { + return Err("Asset too large. Use get() and get_chunk() instead.".to_string()); + } + + Ok(id_enc.content_chunks[0].clone()) + } + + pub fn store(&mut self, arg: StoreArg, time: u64) -> Result<(), String> { + let asset = self.assets.entry(arg.key.clone()).or_default(); + asset.content_type = arg.content_type; + + let hash = sha2::Sha256::digest(&arg.content).into(); + if let Some(provided_hash) = arg.sha256 { + if hash != provided_hash.as_ref() { + return Err("sha256 mismatch".to_string()); + } + } + + let encoding = asset.encodings.entry(arg.content_encoding).or_default(); + encoding.total_length = arg.content.len(); + encoding.content_chunks = vec![RcBytes::from(arg.content)]; + encoding.modified = Int::from(time); + encoding.sha256 = hash; + + on_asset_change(&mut self.asset_hashes, &arg.key, asset); + Ok(()) + } + + pub fn create_batch(&mut self, now: u64) -> BatchId { + let batch_id = self.next_batch_id.clone(); + self.next_batch_id += 1; + + self.batches.insert( + batch_id.clone(), + Batch { + expires_at: Int::from(now + BATCH_EXPIRY_NANOS), + }, + ); + self.chunks.retain(|_, c| { + self.batches + .get(&c.batch_id) + .map(|b| b.expires_at > now) + .unwrap_or(false) + }); + self.batches.retain(|_, b| b.expires_at > now); + + batch_id + } + + pub fn create_chunk(&mut self, arg: CreateChunkArg, now: u64) -> Result { + let mut batch = self + .batches + .get_mut(&arg.batch_id) + .ok_or_else(|| "batch not found".to_string())?; + + batch.expires_at = Int::from(now + BATCH_EXPIRY_NANOS); + + let chunk_id = self.next_chunk_id.clone(); + self.next_chunk_id += 1; + + self.chunks.insert( + chunk_id.clone(), + Chunk { + batch_id: arg.batch_id, + content: RcBytes::from(arg.content), + }, + ); + + Ok(chunk_id) + } + + pub fn commit_batch(&mut self, arg: CommitBatchArguments, now: u64) -> Result<(), String> { + let batch_id = arg.batch_id; + for op in arg.operations { + match op { + BatchOperation::CreateAsset(arg) => self.create_asset(arg)?, + BatchOperation::SetAssetContent(arg) => self.set_asset_content(arg, now)?, + BatchOperation::UnsetAssetContent(arg) => self.unset_asset_content(arg)?, + BatchOperation::DeleteAsset(arg) => self.delete_asset(arg), + BatchOperation::Clear(_) => self.clear(), + } + } + self.batches.remove(&batch_id); + Ok(()) + } + + pub fn list_assets(&self) -> Vec { + self.assets + .iter() + .map(|(key, asset)| { + let mut encodings: Vec<_> = asset + .encodings + .iter() + .map(|(enc_name, enc)| AssetEncodingDetails { + content_encoding: enc_name.clone(), + sha256: Some(ByteBuf::from(enc.sha256)), + length: Nat::from(enc.total_length), + modified: enc.modified.clone(), + }) + .collect(); + encodings.sort_by(|l, r| l.content_encoding.cmp(&r.content_encoding)); + + AssetDetails { + key: key.clone(), + content_type: asset.content_type.clone(), + encodings, + } + }) + .collect::>() + } + + pub fn get(&self, arg: GetArg) -> Result { + let asset = self + .assets + .get(&arg.key) + .ok_or_else(|| "asset not found".to_string())?; + + for enc in arg.accept_encodings.iter() { + if let Some(asset_enc) = asset.encodings.get(enc) { + return Ok(EncodedAsset { + content: asset_enc.content_chunks[0].clone(), + content_type: asset.content_type.clone(), + content_encoding: enc.clone(), + total_length: Nat::from(asset_enc.total_length as u64), + sha256: Some(ByteBuf::from(asset_enc.sha256)), + }); + } + } + Err("no such encoding".to_string()) + } + + pub fn get_chunk(&self, arg: GetChunkArg) -> Result { + let asset = self + .assets + .get(&arg.key) + .ok_or_else(|| "asset not found".to_string())?; + + let enc = asset + .encodings + .get(&arg.content_encoding) + .ok_or_else(|| "no such encoding".to_string())?; + + if let Some(expected_hash) = arg.sha256 { + if expected_hash != enc.sha256 { + return Err("sha256 mismatch".to_string()); + } + } + if arg.index >= enc.content_chunks.len() { + return Err("chunk index out of bounds".to_string()); + } + let index: usize = arg.index.0.to_usize().unwrap(); + + Ok(enc.content_chunks[index].clone()) + } + + fn build_http_response( + &self, + certificate: &[u8], + path: &str, + encodings: Vec, + index: usize, + callback: Func, + ) -> HttpResponse { + let index_redirect_certificate = if self.asset_hashes.get(path.as_bytes()).is_none() + && self.asset_hashes.get(INDEX_FILE.as_bytes()).is_some() + { + let absence_proof = self.asset_hashes.witness(path.as_bytes()); + let index_proof = self.asset_hashes.witness(INDEX_FILE.as_bytes()); + let combined_proof = merge_hash_trees(absence_proof, index_proof); + Some(witness_to_header(combined_proof, certificate)) + } else { + None + }; + + if let Some(certificate_header) = index_redirect_certificate { + if let Some(asset) = self.assets.get(INDEX_FILE) { + for enc_name in encodings.iter() { + if let Some(enc) = asset.encodings.get(enc_name) { + if enc.certified { + return build_200( + asset, + enc_name, + enc, + INDEX_FILE, + index, + Some(certificate_header), + callback, + ); + } + } + } + } + } + + let certificate_header = + witness_to_header(self.asset_hashes.witness(path.as_bytes()), certificate); + + if let Some(asset) = self.assets.get(path) { + for enc_name in encodings.iter() { + if let Some(enc) = asset.encodings.get(enc_name) { + if enc.certified { + return build_200( + asset, + enc_name, + enc, + path, + index, + Some(certificate_header), + callback, + ); + } else { + // Find if identity is certified, if it's not. + if let Some(id_enc) = asset.encodings.get("identity") { + if id_enc.certified { + return build_200( + asset, + enc_name, + enc, + path, + index, + Some(certificate_header), + callback, + ); + } + } + } + } + } + } + + build_404(certificate_header) + } + + pub fn http_request( + &self, + req: HttpRequest, + certificate: &[u8], + callback: Func, + ) -> HttpResponse { + let mut encodings = vec![]; + for (name, value) in req.headers.iter() { + if name.eq_ignore_ascii_case("Accept-Encoding") { + for v in value.split(',') { + encodings.push(v.trim().to_string()); + } + } + if name.eq_ignore_ascii_case("Host") { + if let Some(replacement_url) = redirect_to_url(value, &req.url) { + return HttpResponse { + status_code: 308, + headers: vec![("Location".to_string(), replacement_url)], + body: RcBytes::from(ByteBuf::default()), + streaming_strategy: None, + }; + } + } + } + encodings.push("identity".to_string()); + + let path = match req.url.find('?') { + Some(i) => &req.url[..i], + None => &req.url[..], + }; + + match url_decode(path) { + Ok(path) => self.build_http_response(certificate, &path, encodings, 0, callback), + Err(err) => HttpResponse { + status_code: 400, + headers: vec![], + body: RcBytes::from(ByteBuf::from(format!( + "failed to decode path '{}': {}", + path, err + ))), + streaming_strategy: None, + }, + } + } + + pub fn http_request_streaming_callback( + &self, + StreamingCallbackToken { + key, + content_encoding, + index, + sha256, + }: StreamingCallbackToken, + ) -> Result { + let asset = self + .assets + .get(&key) + .ok_or_else(|| "Invalid token on streaming: key not found.".to_string())?; + let enc = asset + .encodings + .get(&content_encoding) + .ok_or_else(|| "Invalid token on streaming: encoding not found.".to_string())?; + + if let Some(expected_hash) = sha256 { + if expected_hash != enc.sha256 { + return Err("sha256 mismatch".to_string()); + } + } + + // MAX is good enough. This means a chunk would be above 64-bits, which is impossible... + let chunk_index = index.0.to_usize().unwrap_or(usize::MAX); + + Ok(StreamingCallbackHttpResponse { + body: enc.content_chunks[chunk_index].clone(), + token: create_token(asset, &content_encoding, enc, &key, chunk_index), + }) + } +} + +impl From for StableState { + fn from(state: State) -> Self { + Self { + authorized: state.authorized, + stable_assets: state.assets, + } + } +} + +impl From for State { + fn from(stable_state: StableState) -> Self { + let mut state = Self { + authorized: stable_state.authorized, + assets: stable_state.stable_assets, + ..Self::default() + }; + + for (asset_name, asset) in state.assets.iter_mut() { + for enc in asset.encodings.values_mut() { + enc.certified = false; + } + on_asset_change(&mut state.asset_hashes, asset_name, asset); + } + state + } +} + +fn on_asset_change(asset_hashes: &mut AssetHashes, key: &str, asset: &mut Asset) { + // If the most preferred encoding is present and certified, + // there is nothing to do. + for enc_name in ENCODING_CERTIFICATION_ORDER.iter() { + if let Some(enc) = asset.encodings.get(*enc_name) { + if enc.certified { + return; + } else { + break; + } + } + } + + if asset.encodings.is_empty() { + asset_hashes.delete(key.as_bytes()); + return; + } + + // An encoding with a higher priority was added, let's certify it + // instead. + + for enc in asset.encodings.values_mut() { + enc.certified = false; + } + + for enc_name in ENCODING_CERTIFICATION_ORDER.iter() { + if let Some(enc) = asset.encodings.get_mut(*enc_name) { + asset_hashes.insert(key.to_string(), enc.sha256); + enc.certified = true; + return; + } + } + + // No known encodings found. Just pick the first one. The exact + // order is hard to predict because we use a hash map. Should + // almost never happen anyway. + if let Some(enc) = asset.encodings.values_mut().next() { + asset_hashes.insert(key.to_string(), enc.sha256); + enc.certified = true; + } +} + +fn witness_to_header(witness: HashTree, certificate: &[u8]) -> HeaderField { + use ic_certified_map::labeled; + + let hash_tree = labeled(b"http_assets", witness); + let mut serializer = serde_cbor::ser::Serializer::new(vec![]); + serializer.self_describe().unwrap(); + hash_tree.serialize(&mut serializer).unwrap(); + + ( + "IC-Certificate".to_string(), + String::from("certificate=:") + + &base64::encode(certificate) + + ":, tree=:" + + &base64::encode(&serializer.into_inner()) + + ":", + ) +} + +fn merge_hash_trees<'a>(lhs: HashTree<'a>, rhs: HashTree<'a>) -> HashTree<'a> { + use HashTree::{Empty, Fork, Labeled, Leaf, Pruned}; + + match (lhs, rhs) { + (Pruned(l), Pruned(r)) => { + if l != r { + panic!("merge_hash_trees: inconsistent hashes"); + } + Pruned(l) + } + (Pruned(_), r) => r, + (l, Pruned(_)) => l, + (Fork(l), Fork(r)) => Fork(Box::new(( + merge_hash_trees(l.0, r.0), + merge_hash_trees(l.1, r.1), + ))), + (Labeled(l_label, l), Labeled(r_label, r)) => { + if l_label != r_label { + panic!("merge_hash_trees: inconsistent hash tree labels"); + } + Labeled(l_label, Box::new(merge_hash_trees(*l, *r))) + } + (Empty, Empty) => Empty, + (Leaf(l), Leaf(r)) => { + if l != r { + panic!("merge_hash_trees: inconsistent leaves"); + } + Leaf(l) + } + (_l, _r) => { + panic!("merge_hash_trees: inconsistent tree structure"); + } + } +} + +fn create_token( + _asset: &Asset, + enc_name: &str, + enc: &AssetEncoding, + key: &str, + chunk_index: usize, +) -> Option { + if chunk_index + 1 >= enc.content_chunks.len() { + None + } else { + Some(StreamingCallbackToken { + key: key.to_string(), + content_encoding: enc_name.to_string(), + index: Nat::from(chunk_index + 1), + sha256: Some(ByteBuf::from(enc.sha256)), + }) + } +} + +fn build_200( + asset: &Asset, + enc_name: &str, + enc: &AssetEncoding, + key: &str, + chunk_index: usize, + certificate_header: Option, + callback: Func, +) -> HttpResponse { + let mut headers = vec![("Content-Type".to_string(), asset.content_type.to_string())]; + if enc_name != "identity" { + headers.push(("Content-Encoding".to_string(), enc_name.to_string())); + } + if let Some(head) = certificate_header { + headers.push(head); + } + + let streaming_strategy = create_token(asset, enc_name, enc, key, chunk_index) + .map(|token| StreamingStrategy::Callback { callback, token }); + + HttpResponse { + status_code: 200, + headers, + body: enc.content_chunks[chunk_index].clone(), + streaming_strategy, + } +} + +fn build_404(certificate_header: HeaderField) -> HttpResponse { + HttpResponse { + status_code: 404, + headers: vec![certificate_header], + body: RcBytes::from(ByteBuf::from("not found")), + streaming_strategy: None, + } +} + +fn redirect_to_url(host: &str, url: &str) -> Option { + if let Some(host) = host.split(':').next() { + let host = host.trim(); + if host == "raw.ic0.app" { + return Some(format!("https://ic0.app{}", url)); + } else if let Some(base) = host.strip_suffix(".raw.ic0.app") { + return Some(format!("https://{}.ic0.app{}", base, url)); + } + } + None +} diff --git a/src/ic-certified-assets/src/tests.rs b/src/ic-certified-assets/src/tests.rs index c775de9fd..876b747c7 100644 --- a/src/ic-certified-assets/src/tests.rs +++ b/src/ic-certified-assets/src/tests.rs @@ -1,24 +1,286 @@ -use crate::*; +use crate::state_machine::{StableState, State, BATCH_EXPIRY_NANOS}; +use crate::types::{ + BatchId, BatchOperation, CommitBatchArguments, CreateAssetArguments, CreateChunkArg, + HttpRequest, HttpResponse, SetAssetContentArguments, StreamingStrategy, +}; +use crate::url_decode::{url_decode, UrlDecodeError}; +use candid::Principal; +use serde_bytes::ByteBuf; -use std::panic::catch_unwind; +fn some_principal() -> Principal { + Principal::from_text("ryjl3-tyaaa-aaaaa-aaaba-cai").unwrap() +} + +fn unused_callback() -> candid::Func { + candid::Func { + method: "unused".to_string(), + principal: some_principal(), + } +} + +type Encodings<'a> = Vec<(&'a str, Vec<&'a [u8]>)>; + +fn create_assets( + state: &mut State, + time_now: u64, + assets: Vec<(&str, &str, Encodings<'_>)>, +) -> BatchId { + let batch_id = state.create_batch(time_now); + + let mut operations = vec![]; + + for (asset, content_type, encodings) in assets { + operations.push(BatchOperation::CreateAsset(CreateAssetArguments { + key: asset.to_string(), + content_type: content_type.to_string(), + })); + for (enc, chunks) in encodings { + let mut chunk_ids = vec![]; + for chunk in chunks { + chunk_ids.push( + state + .create_chunk( + CreateChunkArg { + batch_id: batch_id.clone(), + content: ByteBuf::from(chunk.to_vec()), + }, + time_now, + ) + .unwrap(), + ); + } + + operations.push(BatchOperation::SetAssetContent({ + SetAssetContentArguments { + key: asset.to_string(), + content_encoding: enc.to_string(), + chunk_ids, + sha256: None, + } + })); + } + } + + state + .commit_batch( + CommitBatchArguments { + batch_id: batch_id.clone(), + operations, + }, + time_now, + ) + .unwrap(); + + batch_id +} #[test] -fn check_url_decode() { - assert_eq!( - url_decode("/%"), - Err(UrlDecodeError::InvalidPercentEncoding) +fn can_create_assets_using_batch_api() { + let mut state = State::default(); + let time_now = 100_000_000_000; + + const BODY: &[u8] = b""; + + let batch_id = create_assets( + &mut state, + time_now, + vec![( + "/contents.html", + "text/html", + vec![("identity", vec![BODY])], + )], ); - assert_eq!(url_decode("/%%"), Ok("/%".to_string())); - assert_eq!(url_decode("/%20a"), Ok("/ a".to_string())); - assert_eq!( - url_decode("/%%+a%20+%@"), - Err(UrlDecodeError::InvalidPercentEncoding) + + let response = state.http_request( + HttpRequest { + body: ByteBuf::new(), + headers: vec![("Accept-Encoding".to_string(), "gzip,identity".to_string())], + method: "GET".to_string(), + url: "/contents.html".to_string(), + }, + &[], + unused_callback(), ); - assert_eq!( - url_decode("/has%percent.txt"), - Err(UrlDecodeError::InvalidPercentEncoding) + + assert_eq!(response.status_code, 200); + assert_eq!(response.body.as_ref(), BODY); + + // Try to update a completed batch. + let error_msg = state + .create_chunk( + CreateChunkArg { + batch_id, + content: ByteBuf::new(), + }, + time_now, + ) + .unwrap_err(); + + let expected = "batch not found"; + assert!( + error_msg.contains(expected), + "expected '{}' error, got: {}", + expected, + error_msg + ); +} + +#[test] +fn batches_are_dropped_after_timeout() { + let mut state = State::default(); + let time_now = 100_000_000_000; + + let batch_1 = state.create_batch(time_now); + + const BODY: &[u8] = b""; + + let _chunk_1 = state + .create_chunk( + CreateChunkArg { + batch_id: batch_1.clone(), + content: ByteBuf::from(BODY.to_vec()), + }, + time_now, + ) + .unwrap(); + + let time_now = time_now + BATCH_EXPIRY_NANOS + 1; + let _batch_2 = state.create_batch(time_now); + + match state.create_chunk( + CreateChunkArg { + batch_id: batch_1, + content: ByteBuf::from(BODY.to_vec()), + }, + time_now, + ) { + Err(err) if err.contains("batch not found") => (), + other => panic!("expected 'batch not found' error, got: {:?}", other), + } +} + +#[test] +fn returns_index_file_for_missing_assets() { + let mut state = State::default(); + let time_now = 100_000_000_000; + + const INDEX_BODY: &[u8] = b"Index"; + const OTHER_BODY: &[u8] = b"Other"; + + create_assets( + &mut state, + time_now, + vec![ + ( + "/index.html", + "text/html", + vec![("identity", vec![INDEX_BODY])], + ), + ( + "/other.html", + "text/html", + vec![("identity", vec![OTHER_BODY])], + ), + ], + ); + + let response = state.http_request( + HttpRequest { + body: ByteBuf::new(), + headers: vec![("Accept-Encoding".to_string(), "gzip,identity".to_string())], + method: "GET".to_string(), + url: "/missing.html".to_string(), + }, + &[], + unused_callback(), + ); + + assert_eq!(response.status_code, 200); + assert_eq!(response.body.as_ref(), INDEX_BODY); +} + +#[test] +fn preserves_state_on_stable_roundtrip() { + let mut state = State::default(); + let time_now = 100_000_000_000; + + const INDEX_BODY: &[u8] = b"Index"; + + create_assets( + &mut state, + time_now, + vec![( + "/index.html", + "text/html", + vec![("identity", vec![INDEX_BODY])], + )], + ); + + let stable_state: StableState = state.into(); + let state: State = stable_state.into(); + + let response = state.http_request( + HttpRequest { + body: ByteBuf::new(), + headers: vec![("Accept-Encoding".to_string(), "gzip,identity".to_string())], + method: "GET".to_string(), + url: "/index.html".to_string(), + }, + &[], + unused_callback(), + ); + assert_eq!(response.status_code, 200); + assert_eq!(response.body.as_ref(), INDEX_BODY); +} + +#[test] +fn uses_streaming_for_multichunk_assets() { + let mut state = State::default(); + let time_now = 100_000_000_000; + + const INDEX_BODY_CHUNK_1: &[u8] = b""; + const INDEX_BODY_CHUNK_2: &[u8] = b"Index"; + + create_assets( + &mut state, + time_now, + vec![( + "/index.html", + "text/html", + vec![("identity", vec![INDEX_BODY_CHUNK_1, INDEX_BODY_CHUNK_2])], + )], + ); + + let streaming_callback = candid::Func { + method: "stream".to_string(), + principal: some_principal(), + }; + let response = state.http_request( + HttpRequest { + body: ByteBuf::new(), + headers: vec![("Accept-Encoding".to_string(), "gzip,identity".to_string())], + method: "GET".to_string(), + url: "/index.html".to_string(), + }, + &[], + streaming_callback.clone(), + ); + + assert_eq!(response.status_code, 200); + assert_eq!(response.body.as_ref(), INDEX_BODY_CHUNK_1); + + let StreamingStrategy::Callback { callback, token } = response + .streaming_strategy + .expect("missing streaming strategy"); + assert_eq!(callback, streaming_callback); + + let streaming_response = state.http_request_streaming_callback(token).unwrap(); + assert_eq!(streaming_response.body.as_ref(), INDEX_BODY_CHUNK_2); + assert!( + streaming_response.token.is_none(), + "Unexpected streaming response: {:?}", + streaming_response ); - assert_eq!(url_decode("/%e6"), Ok("/æ".to_string())); } #[test] @@ -38,24 +300,60 @@ fn redirects_cleanly() { .iter() .any(|(key, value)| key == "Location" && value == expected)); } + + let state = State::default(); + let fake_cert = [0xca, 0xfe]; + assert_308( - &http_request(fake("aaaaa-aa.raw.ic0.app")), + &state.http_request(fake("aaaaa-aa.raw.ic0.app"), &fake_cert, unused_callback()), "https://aaaaa-aa.ic0.app/asset.blob", ); assert_308( - &http_request(fake("my.http.files.raw.ic0.app")), + &state.http_request( + fake("my.http.files.raw.ic0.app"), + &fake_cert, + unused_callback(), + ), "https://my.http.files.ic0.app/asset.blob", ); assert_308( - &http_request(fake("raw.ic0.app.raw.ic0.app")), + &state.http_request( + fake("raw.ic0.app.raw.ic0.app"), + &fake_cert, + unused_callback(), + ), "https://raw.ic0.app.ic0.app/asset.blob", ); assert_308( - &http_request(fake("raw.ic0.app")), // for ?canisterId= + &state.http_request(fake("raw.ic0.app"), &fake_cert, unused_callback()), // for ?canisterId= "https://ic0.app/asset.blob", ); - let no_redirect = catch_unwind(|| http_request(fake("raw.ic0.app.ic0.app")).status_code); - assert!(!matches!(no_redirect, Ok(308))); - let no_redirect2 = catch_unwind(|| http_request(fake("straw.ic0.app")).status_code); - assert!(!matches!(no_redirect2, Ok(308))); + let no_redirect = state + .http_request(fake("raw.ic0.app.ic0.app"), &fake_cert, unused_callback()) + .status_code; + assert!(!matches!(no_redirect, 308)); + + let no_redirect2 = state + .http_request(fake("straw.ic0.app"), &fake_cert, unused_callback()) + .status_code; + assert!(!matches!(no_redirect2, 308)); +} + +#[test] +fn check_url_decode() { + assert_eq!( + url_decode("/%"), + Err(UrlDecodeError::InvalidPercentEncoding) + ); + assert_eq!(url_decode("/%%"), Ok("/%".to_string())); + assert_eq!(url_decode("/%20a"), Ok("/ a".to_string())); + assert_eq!( + url_decode("/%%+a%20+%@"), + Err(UrlDecodeError::InvalidPercentEncoding) + ); + assert_eq!( + url_decode("/has%percent.txt"), + Err(UrlDecodeError::InvalidPercentEncoding) + ); + assert_eq!(url_decode("/%e6"), Ok("/æ".to_string())); } diff --git a/src/ic-certified-assets/src/types.rs b/src/ic-certified-assets/src/types.rs new file mode 100644 index 000000000..9d65f0ad4 --- /dev/null +++ b/src/ic-certified-assets/src/types.rs @@ -0,0 +1,140 @@ +//! This module defines types shared by the certified assets state machine and the canister +//! endpoints. +use crate::rc_bytes::RcBytes; +use candid::{CandidType, Deserialize, Func, Nat}; +use serde_bytes::ByteBuf; + +pub type BatchId = Nat; +pub type ChunkId = Nat; +pub type Key = String; + +// IDL Types + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct CreateAssetArguments { + pub key: Key, + pub content_type: String, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct SetAssetContentArguments { + pub key: Key, + pub content_encoding: String, + pub chunk_ids: Vec, + pub sha256: Option, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct UnsetAssetContentArguments { + pub key: Key, + pub content_encoding: String, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct DeleteAssetArguments { + pub key: Key, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct ClearArguments {} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub enum BatchOperation { + CreateAsset(CreateAssetArguments), + SetAssetContent(SetAssetContentArguments), + UnsetAssetContent(UnsetAssetContentArguments), + DeleteAsset(DeleteAssetArguments), + Clear(ClearArguments), +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct CommitBatchArguments { + pub batch_id: BatchId, + pub operations: Vec, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct StoreArg { + pub key: Key, + pub content_type: String, + pub content_encoding: String, + pub content: ByteBuf, + pub sha256: Option, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct GetArg { + pub key: Key, + pub accept_encodings: Vec, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct GetChunkArg { + pub key: Key, + pub content_encoding: String, + pub index: Nat, + pub sha256: Option, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct GetChunkResponse { + pub content: RcBytes, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct CreateBatchResponse { + pub batch_id: BatchId, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct CreateChunkArg { + pub batch_id: BatchId, + pub content: ByteBuf, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct CreateChunkResponse { + pub chunk_id: ChunkId, +} +// HTTP interface + +pub type HeaderField = (String, String); + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct HttpRequest { + pub method: String, + pub url: String, + pub headers: Vec<(String, String)>, + pub body: ByteBuf, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct HttpResponse { + pub status_code: u16, + pub headers: Vec, + pub body: RcBytes, + pub streaming_strategy: Option, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct StreamingCallbackToken { + pub key: String, + pub content_encoding: String, + pub index: Nat, + // We don't care about the sha, we just want to be backward compatible. + pub sha256: Option, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub enum StreamingStrategy { + Callback { + callback: Func, + token: StreamingCallbackToken, + }, +} + +#[derive(Clone, Debug, CandidType, Deserialize)] +pub struct StreamingCallbackHttpResponse { + pub body: RcBytes, + pub token: Option, +} diff --git a/src/ic-certified-assets/src/url_decode.rs b/src/ic-certified-assets/src/url_decode.rs new file mode 100644 index 000000000..e7c6c9ca0 --- /dev/null +++ b/src/ic-certified-assets/src/url_decode.rs @@ -0,0 +1,63 @@ +use std::fmt; + +/// An iterator-like structure that decode a URL. +struct UrlDecode<'a> { + bytes: std::slice::Iter<'a, u8>, +} + +fn convert_percent(iter: &mut std::slice::Iter) -> Option { + let mut cloned_iter = iter.clone(); + let result = match cloned_iter.next()? { + b'%' => b'%', + h => { + let h = char::from(*h).to_digit(16)?; + let l = char::from(*cloned_iter.next()?).to_digit(16)?; + h as u8 * 0x10 + l as u8 + } + }; + // Update this if we make it this far, otherwise "reset" the iterator. + *iter = cloned_iter; + Some(result) +} + +#[derive(Debug, PartialEq)] +pub enum UrlDecodeError { + InvalidPercentEncoding, +} + +impl fmt::Display for UrlDecodeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::InvalidPercentEncoding => write!(f, "invalid percent encoding"), + } + } +} + +impl<'a> Iterator for UrlDecode<'a> { + type Item = Result; + + fn next(&mut self) -> Option { + let b = self.bytes.next()?; + match b { + b'%' => Some( + convert_percent(&mut self.bytes) + .map(char::from) + .ok_or(UrlDecodeError::InvalidPercentEncoding), + ), + b'+' => Some(Ok(' ')), + x => Some(Ok(char::from(*x))), + } + } + + fn size_hint(&self) -> (usize, Option) { + let bytes = self.bytes.len(); + (bytes / 3, Some(bytes)) + } +} + +pub fn url_decode(url: &str) -> Result { + UrlDecode { + bytes: url.as_bytes().iter(), + } + .collect() +} From 8e41a1987a7f8c6375ac8ea9d6b9992c60aea5f6 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Tue, 10 May 2022 09:39:47 +0200 Subject: [PATCH 048/234] feat: support ETags in certified assets (#254) This change implements [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) caching headers support in the ic-certified-assets package. --- src/ic-certified-assets/src/rc_bytes.rs | 2 +- src/ic-certified-assets/src/state_machine.rs | 47 +++++++-- src/ic-certified-assets/src/tests.rs | 102 +++++++++++++++++++ 3 files changed, 143 insertions(+), 8 deletions(-) diff --git a/src/ic-certified-assets/src/rc_bytes.rs b/src/ic-certified-assets/src/rc_bytes.rs index 469d670cc..e2dbd5335 100644 --- a/src/ic-certified-assets/src/rc_bytes.rs +++ b/src/ic-certified-assets/src/rc_bytes.rs @@ -9,7 +9,7 @@ use std::convert::AsRef; use std::ops::Deref; use std::rc::Rc; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct RcBytes(Rc); impl CandidType for RcBytes { diff --git a/src/ic-certified-assets/src/state_machine.rs b/src/ic-certified-assets/src/state_machine.rs index 01182888d..dea5b2eda 100644 --- a/src/ic-certified-assets/src/state_machine.rs +++ b/src/ic-certified-assets/src/state_machine.rs @@ -387,6 +387,7 @@ impl State { encodings: Vec, index: usize, callback: Func, + etag: Option, ) -> HttpResponse { let index_redirect_certificate = if self.asset_hashes.get(path.as_bytes()).is_none() && self.asset_hashes.get(INDEX_FILE.as_bytes()).is_some() @@ -404,7 +405,7 @@ impl State { for enc_name in encodings.iter() { if let Some(enc) = asset.encodings.get(enc_name) { if enc.certified { - return build_200( + return build_ok( asset, enc_name, enc, @@ -412,6 +413,7 @@ impl State { index, Some(certificate_header), callback, + etag, ); } } @@ -426,7 +428,7 @@ impl State { for enc_name in encodings.iter() { if let Some(enc) = asset.encodings.get(enc_name) { if enc.certified { - return build_200( + return build_ok( asset, enc_name, enc, @@ -434,12 +436,13 @@ impl State { index, Some(certificate_header), callback, + etag, ); } else { // Find if identity is certified, if it's not. if let Some(id_enc) = asset.encodings.get("identity") { if id_enc.certified { - return build_200( + return build_ok( asset, enc_name, enc, @@ -447,6 +450,7 @@ impl State { index, Some(certificate_header), callback, + etag, ); } } @@ -465,6 +469,7 @@ impl State { callback: Func, ) -> HttpResponse { let mut encodings = vec![]; + let mut etag = None; for (name, value) in req.headers.iter() { if name.eq_ignore_ascii_case("Accept-Encoding") { for v in value.split(',') { @@ -481,6 +486,25 @@ impl State { }; } } + if name.eq_ignore_ascii_case("If-None-Match") { + let mut hash = Hash::default(); + match hex::decode_to_slice(value, &mut hash[..]) { + Ok(()) => { + etag = Some(hash); + } + Err(err) => { + return HttpResponse { + status_code: 400, + headers: vec![], + body: RcBytes::from(ByteBuf::from(format!( + "Invalid {} header: {}", + name, err + ))), + streaming_strategy: None, + }; + } + } + } } encodings.push("identity".to_string()); @@ -490,7 +514,7 @@ impl State { }; match url_decode(path) { - Ok(path) => self.build_http_response(certificate, &path, encodings, 0, callback), + Ok(path) => self.build_http_response(certificate, &path, encodings, 0, callback, etag), Err(err) => HttpResponse { status_code: 400, headers: vec![], @@ -678,7 +702,8 @@ fn create_token( } } -fn build_200( +#[allow(clippy::too_many_arguments)] +fn build_ok( asset: &Asset, enc_name: &str, enc: &AssetEncoding, @@ -686,6 +711,7 @@ fn build_200( chunk_index: usize, certificate_header: Option, callback: Func, + etag: Option, ) -> HttpResponse { let mut headers = vec![("Content-Type".to_string(), asset.content_type.to_string())]; if enc_name != "identity" { @@ -698,10 +724,17 @@ fn build_200( let streaming_strategy = create_token(asset, enc_name, enc, key, chunk_index) .map(|token| StreamingStrategy::Callback { callback, token }); + let (status_code, body) = if etag == Some(enc.sha256) { + (304, RcBytes::default()) + } else { + headers.push(("ETag".to_string(), hex::encode(enc.sha256))); + (200, enc.content_chunks[chunk_index].clone()) + }; + HttpResponse { - status_code: 200, + status_code, headers, - body: enc.content_chunks[chunk_index].clone(), + body, streaming_strategy, } } diff --git a/src/ic-certified-assets/src/tests.rs b/src/ic-certified-assets/src/tests.rs index 876b747c7..40573ad06 100644 --- a/src/ic-certified-assets/src/tests.rs +++ b/src/ic-certified-assets/src/tests.rs @@ -6,6 +6,7 @@ use crate::types::{ use crate::url_decode::{url_decode, UrlDecodeError}; use candid::Principal; use serde_bytes::ByteBuf; +use sha2::Digest; fn some_principal() -> Principal { Principal::from_text("ryjl3-tyaaa-aaaaa-aaaba-cai").unwrap() @@ -283,6 +284,107 @@ fn uses_streaming_for_multichunk_assets() { ); } +#[test] +fn supports_etag_caching() { + let mut state = State::default(); + let time_now = 100_000_000_000; + + const BODY: &[u8] = b""; + let hash: [u8; 32] = sha2::Sha256::digest(BODY).into(); + let etag = hex::encode(hash); + + create_assets( + &mut state, + time_now, + vec![( + "/contents.html", + "text/html", + vec![("identity", vec![BODY])], + )], + ); + + let response = state.http_request( + HttpRequest { + body: ByteBuf::new(), + headers: vec![("Accept-Encoding".to_string(), "gzip,identity".to_string())], + method: "GET".to_string(), + url: "/contents.html".to_string(), + }, + &[], + unused_callback(), + ); + + assert_eq!(response.status_code, 200); + assert_eq!(response.body.as_ref(), BODY); + assert!( + response + .headers + .contains(&("ETag".to_string(), etag.clone())), + "No matching ETag header in response: {:#?}, expected ETag {}", + response, + etag + ); + assert!( + response + .headers + .iter() + .any(|(name, _)| name.eq_ignore_ascii_case("IC-Certificate")), + "No IC-Certificate header in response: {:#?}", + response + ); + + let response = state.http_request( + HttpRequest { + body: ByteBuf::new(), + headers: vec![ + ("Accept-Encoding".to_string(), "gzip,identity".to_string()), + ("If-None-Match".to_string(), etag), + ], + method: "GET".to_string(), + url: "/contents.html".to_string(), + }, + &[], + unused_callback(), + ); + + assert_eq!(response.status_code, 304); + assert_eq!(response.body.as_ref(), &[] as &[u8]); +} + +#[test] +fn returns_400_on_invalid_etag() { + let mut state = State::default(); + let time_now = 100_000_000_000; + + const BODY: &[u8] = b""; + + create_assets( + &mut state, + time_now, + vec![( + "/contents.html", + "text/html", + vec![("identity", vec![BODY])], + )], + ); + + let response = state.http_request( + HttpRequest { + body: ByteBuf::new(), + headers: vec![ + ("Accept-Encoding".to_string(), "gzip,identity".to_string()), + ("If-None-Match".to_string(), "cafe".to_string()), + ], + method: "GET".to_string(), + url: "/contents.html".to_string(), + }, + &[], + unused_callback(), + ); + + assert_eq!(response.status_code, 400); +} + #[test] fn redirects_cleanly() { fn fake(host: &str) -> HttpRequest { From c80ebd91ed0f284265090049c8464038cfa874e6 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Tue, 10 May 2022 18:38:59 +0200 Subject: [PATCH 049/234] feat: add support for max_age field (#255) This change extends the certified assets canister interface to support setting max_age field for an asset. If the field is present, the canister will translate it into "Cache-Control: max-age={max_age}" header. --- src/ic-certified-assets/assets.did | 1 + src/ic-certified-assets/src/state_machine.rs | 5 + src/ic-certified-assets/src/tests.rs | 286 ++++++++++++------- src/ic-certified-assets/src/types.rs | 1 + 4 files changed, 183 insertions(+), 110 deletions(-) diff --git a/src/ic-certified-assets/assets.did b/src/ic-certified-assets/assets.did index d11ecd992..0b8d606b9 100644 --- a/src/ic-certified-assets/assets.did +++ b/src/ic-certified-assets/assets.did @@ -6,6 +6,7 @@ type Time = int; type CreateAssetArguments = record { key: Key; content_type: text; + max_age: opt nat64; }; // Add or change content for an asset, by content encoding diff --git a/src/ic-certified-assets/src/state_machine.rs b/src/ic-certified-assets/src/state_machine.rs index dea5b2eda..2d5467870 100644 --- a/src/ic-certified-assets/src/state_machine.rs +++ b/src/ic-certified-assets/src/state_machine.rs @@ -40,6 +40,7 @@ pub struct AssetEncoding { pub struct Asset { pub content_type: String, pub encodings: HashMap, + pub max_age: Option, } #[derive(Clone, Debug, CandidType, Deserialize)] @@ -127,6 +128,7 @@ impl State { Asset { content_type: arg.content_type, encodings: HashMap::new(), + max_age: arg.max_age, }, ); } @@ -720,6 +722,9 @@ fn build_ok( if let Some(head) = certificate_header { headers.push(head); } + if let Some(max_age) = asset.max_age { + headers.push(("Cache-Control".to_string(), format!("max-age={}", max_age))); + } let streaming_strategy = create_token(asset, enc_name, enc, key, chunk_index) .map(|token| StreamingStrategy::Callback { callback, token }); diff --git a/src/ic-certified-assets/src/tests.rs b/src/ic-certified-assets/src/tests.rs index 40573ad06..1c04195ea 100644 --- a/src/ic-certified-assets/src/tests.rs +++ b/src/ic-certified-assets/src/tests.rs @@ -19,23 +19,86 @@ fn unused_callback() -> candid::Func { } } -type Encodings<'a> = Vec<(&'a str, Vec<&'a [u8]>)>; +struct AssetBuilder { + name: String, + content_type: String, + max_age: Option, + encodings: Vec<(String, Vec)>, +} + +impl AssetBuilder { + fn new(name: impl AsRef, content_type: impl AsRef) -> Self { + Self { + name: name.as_ref().to_string(), + content_type: content_type.as_ref().to_string(), + max_age: None, + encodings: vec![], + } + } + + fn with_max_age(mut self, max_age: u64) -> Self { + self.max_age = Some(max_age); + self + } + + fn with_encoding(mut self, name: impl AsRef, chunks: Vec>) -> Self { + self.encodings.push(( + name.as_ref().to_string(), + chunks + .into_iter() + .map(|c| ByteBuf::from(c.as_ref().to_vec())) + .collect(), + )); + self + } +} + +struct RequestBuilder { + resource: String, + method: String, + headers: Vec<(String, String)>, + body: ByteBuf, +} + +impl RequestBuilder { + fn get(resource: impl AsRef) -> Self { + Self { + resource: resource.as_ref().to_string(), + method: "GET".to_string(), + headers: vec![], + body: ByteBuf::new(), + } + } -fn create_assets( - state: &mut State, - time_now: u64, - assets: Vec<(&str, &str, Encodings<'_>)>, -) -> BatchId { + fn with_header(mut self, name: impl AsRef, value: impl AsRef) -> Self { + self.headers + .push((name.as_ref().to_string(), value.as_ref().to_string())); + self + } + + fn build(self) -> HttpRequest { + HttpRequest { + method: self.method, + url: self.resource, + headers: self.headers, + body: self.body, + } + } +} + +fn create_assets(state: &mut State, time_now: u64, assets: Vec) -> BatchId { let batch_id = state.create_batch(time_now); let mut operations = vec![]; - for (asset, content_type, encodings) in assets { + for asset in assets { operations.push(BatchOperation::CreateAsset(CreateAssetArguments { - key: asset.to_string(), - content_type: content_type.to_string(), + key: asset.name.clone(), + content_type: asset.content_type, + max_age: asset.max_age, })); - for (enc, chunks) in encodings { + + for (enc, chunks) in asset.encodings { let mut chunk_ids = vec![]; for chunk in chunks { chunk_ids.push( @@ -43,7 +106,7 @@ fn create_assets( .create_chunk( CreateChunkArg { batch_id: batch_id.clone(), - content: ByteBuf::from(chunk.to_vec()), + content: chunk, }, time_now, ) @@ -53,8 +116,8 @@ fn create_assets( operations.push(BatchOperation::SetAssetContent({ SetAssetContentArguments { - key: asset.to_string(), - content_encoding: enc.to_string(), + key: asset.name.clone(), + content_encoding: enc, chunk_ids, sha256: None, } @@ -75,6 +138,13 @@ fn create_assets( batch_id } +fn lookup_header<'a>(response: &'a HttpResponse, header: &str) -> Option<&'a str> { + response + .headers + .iter() + .find_map(|(h, v)| h.eq_ignore_ascii_case(header).then(|| v.as_str())) +} + #[test] fn can_create_assets_using_batch_api() { let mut state = State::default(); @@ -85,20 +155,13 @@ fn can_create_assets_using_batch_api() { let batch_id = create_assets( &mut state, time_now, - vec![( - "/contents.html", - "text/html", - vec![("identity", vec![BODY])], - )], + vec![AssetBuilder::new("/contents.html", "text/html").with_encoding("identity", vec![BODY])], ); let response = state.http_request( - HttpRequest { - body: ByteBuf::new(), - headers: vec![("Accept-Encoding".to_string(), "gzip,identity".to_string())], - method: "GET".to_string(), - url: "/contents.html".to_string(), - }, + RequestBuilder::get("/contents.html") + .with_header("Accept-Encoding", "gzip,identity") + .build(), &[], unused_callback(), ); @@ -172,26 +235,17 @@ fn returns_index_file_for_missing_assets() { &mut state, time_now, vec![ - ( - "/index.html", - "text/html", - vec![("identity", vec![INDEX_BODY])], - ), - ( - "/other.html", - "text/html", - vec![("identity", vec![OTHER_BODY])], - ), + AssetBuilder::new("/index.html", "text/html") + .with_encoding("identity", vec![INDEX_BODY]), + AssetBuilder::new("/other.html", "text/html") + .with_encoding("identity", vec![OTHER_BODY]), ], ); let response = state.http_request( - HttpRequest { - body: ByteBuf::new(), - headers: vec![("Accept-Encoding".to_string(), "gzip,identity".to_string())], - method: "GET".to_string(), - url: "/missing.html".to_string(), - }, + RequestBuilder::get("/missing.html") + .with_header("Accept-Encoding", "gzip,identity") + .build(), &[], unused_callback(), ); @@ -210,23 +264,17 @@ fn preserves_state_on_stable_roundtrip() { create_assets( &mut state, time_now, - vec![( - "/index.html", - "text/html", - vec![("identity", vec![INDEX_BODY])], - )], + vec![AssetBuilder::new("/index.html", "text/html") + .with_encoding("identity", vec![INDEX_BODY])], ); let stable_state: StableState = state.into(); let state: State = stable_state.into(); let response = state.http_request( - HttpRequest { - body: ByteBuf::new(), - headers: vec![("Accept-Encoding".to_string(), "gzip,identity".to_string())], - method: "GET".to_string(), - url: "/index.html".to_string(), - }, + RequestBuilder::get("/index.html") + .with_header("Accept-Encoding", "gzip,identity") + .build(), &[], unused_callback(), ); @@ -245,11 +293,8 @@ fn uses_streaming_for_multichunk_assets() { create_assets( &mut state, time_now, - vec![( - "/index.html", - "text/html", - vec![("identity", vec![INDEX_BODY_CHUNK_1, INDEX_BODY_CHUNK_2])], - )], + vec![AssetBuilder::new("/index.html", "text/html") + .with_encoding("identity", vec![INDEX_BODY_CHUNK_1, INDEX_BODY_CHUNK_2])], ); let streaming_callback = candid::Func { @@ -257,12 +302,9 @@ fn uses_streaming_for_multichunk_assets() { principal: some_principal(), }; let response = state.http_request( - HttpRequest { - body: ByteBuf::new(), - headers: vec![("Accept-Encoding".to_string(), "gzip,identity".to_string())], - method: "GET".to_string(), - url: "/index.html".to_string(), - }, + RequestBuilder::get("/index.html") + .with_header("Accept-Encoding", "gzip,identity") + .build(), &[], streaming_callback.clone(), ); @@ -296,53 +338,37 @@ fn supports_etag_caching() { create_assets( &mut state, time_now, - vec![( - "/contents.html", - "text/html", - vec![("identity", vec![BODY])], - )], + vec![AssetBuilder::new("/contents.html", "text/html").with_encoding("identity", vec![BODY])], ); let response = state.http_request( - HttpRequest { - body: ByteBuf::new(), - headers: vec![("Accept-Encoding".to_string(), "gzip,identity".to_string())], - method: "GET".to_string(), - url: "/contents.html".to_string(), - }, + RequestBuilder::get("/contents.html") + .with_header("Accept-Encoding", "gzip,identity") + .build(), &[], unused_callback(), ); assert_eq!(response.status_code, 200); assert_eq!(response.body.as_ref(), BODY); - assert!( - response - .headers - .contains(&("ETag".to_string(), etag.clone())), + assert_eq!( + lookup_header(&response, "ETag"), + Some(etag.as_str()), "No matching ETag header in response: {:#?}, expected ETag {}", response, etag ); assert!( - response - .headers - .iter() - .any(|(name, _)| name.eq_ignore_ascii_case("IC-Certificate")), + lookup_header(&response, "IC-Certificate").is_some(), "No IC-Certificate header in response: {:#?}", response ); let response = state.http_request( - HttpRequest { - body: ByteBuf::new(), - headers: vec![ - ("Accept-Encoding".to_string(), "gzip,identity".to_string()), - ("If-None-Match".to_string(), etag), - ], - method: "GET".to_string(), - url: "/contents.html".to_string(), - }, + RequestBuilder::get("/contents.html") + .with_header("Accept-Encoding", "gzip,identity") + .with_header("If-None-Match", &etag) + .build(), &[], unused_callback(), ); @@ -361,23 +387,14 @@ fn returns_400_on_invalid_etag() { create_assets( &mut state, time_now, - vec![( - "/contents.html", - "text/html", - vec![("identity", vec![BODY])], - )], + vec![AssetBuilder::new("/contents.html", "text/html").with_encoding("identity", vec![BODY])], ); let response = state.http_request( - HttpRequest { - body: ByteBuf::new(), - headers: vec![ - ("Accept-Encoding".to_string(), "gzip,identity".to_string()), - ("If-None-Match".to_string(), "cafe".to_string()), - ], - method: "GET".to_string(), - url: "/contents.html".to_string(), - }, + RequestBuilder::get("/contents.html") + .with_header("Accept-Encoding", "gzip,identity") + .with_header("If-None-Match", "cafe") + .build(), &[], unused_callback(), ); @@ -385,15 +402,64 @@ fn returns_400_on_invalid_etag() { assert_eq!(response.status_code, 400); } +#[test] +fn supports_max_age_headers() { + let mut state = State::default(); + let time_now = 100_000_000_000; + + const BODY: &[u8] = b""; + + create_assets( + &mut state, + time_now, + vec![ + AssetBuilder::new("/contents.html", "text/html").with_encoding("identity", vec![BODY]), + AssetBuilder::new("/max-age.html", "text/html") + .with_max_age(604800) + .with_encoding("identity", vec![BODY]), + ], + ); + + let response = state.http_request( + RequestBuilder::get("/contents.html") + .with_header("Accept-Encoding", "gzip,identity") + .build(), + &[], + unused_callback(), + ); + + assert_eq!(response.status_code, 200); + assert_eq!(response.body.as_ref(), BODY); + assert!( + lookup_header(&response, "Cache-Control").is_none(), + "Unexpected Cache-Control header in response: {:#?}", + response, + ); + + let response = state.http_request( + RequestBuilder::get("/max-age.html") + .with_header("Accept-Encoding", "gzip,identity") + .build(), + &[], + unused_callback(), + ); + + assert_eq!(response.status_code, 200); + assert_eq!(response.body.as_ref(), BODY); + assert_eq!( + lookup_header(&response, "Cache-Control"), + Some("max-age=604800"), + "No matching Cache-Control header in response: {:#?}", + response, + ); +} + #[test] fn redirects_cleanly() { fn fake(host: &str) -> HttpRequest { - HttpRequest { - body: ByteBuf::new(), - headers: vec![("Host".to_string(), host.to_string())], - method: "GET".to_string(), - url: "/asset.blob".to_string(), - } + RequestBuilder::get("/asset.blob") + .with_header("Host", host) + .build() } fn assert_308(resp: &HttpResponse, expected: &str) { assert_eq!(resp.status_code, 308); diff --git a/src/ic-certified-assets/src/types.rs b/src/ic-certified-assets/src/types.rs index 9d65f0ad4..06628b61d 100644 --- a/src/ic-certified-assets/src/types.rs +++ b/src/ic-certified-assets/src/types.rs @@ -14,6 +14,7 @@ pub type Key = String; pub struct CreateAssetArguments { pub key: Key, pub content_type: String, + pub max_age: Option, } #[derive(Clone, Debug, CandidType, Deserialize)] From 936d61e2ef4bba1f63eaf17997aa81c5c6b6d5c9 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Wed, 11 May 2022 19:28:23 +0200 Subject: [PATCH 050/234] chore: release ic-certified-assets 0.2.0 (#257) --- src/ic-certified-assets/CHANGELOG.md | 5 +++++ src/ic-certified-assets/Cargo.toml | 2 +- src/ic-certified-assets/README.md | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ic-certified-assets/CHANGELOG.md b/src/ic-certified-assets/CHANGELOG.md index 8de61aba1..a36db5d13 100644 --- a/src/ic-certified-assets/CHANGELOG.md +++ b/src/ic-certified-assets/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.2.0] - 2022-05-11 +### Added +- Support for asset caching based on [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) +- Support for asset caching based on [max-age](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) + ## [0.1.0] - 2022-02-02 ### Added - First release diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml index f9d0ed67d..8aaaf0fe6 100644 --- a/src/ic-certified-assets/Cargo.toml +++ b/src/ic-certified-assets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-certified-assets" -version = "0.1.0" +version = "0.2.0" edition = "2021" authors = ["DFINITY Stiftung "] description = "Rust support for asset certification." diff --git a/src/ic-certified-assets/README.md b/src/ic-certified-assets/README.md index 14f3c4844..e68ec7816 100644 --- a/src/ic-certified-assets/README.md +++ b/src/ic-certified-assets/README.md @@ -8,7 +8,7 @@ Certified assets can also be served from any Rust canister by including this lib ``` [dependencies] -ic-certified-assets = "0.1.0" +ic-certified-assets = "0.2.0" ``` The assets are preserved over upgrades by including the corresponding functions in the `init/pre_upgrade/upgrade` @@ -26,7 +26,7 @@ fn init() { crate::assets::init(); } ->>#[pre_upgrade] +#[pre_upgrade] fn pre_upgrade() { let stable_state = STATE.with(|s| StableState { my_state: s.my_state, @@ -35,7 +35,7 @@ fn pre_upgrade() { ic_cdk::storage::stable_save((stable_state,)).expect("failed to save stable state"); } ->>#[post_upgrade] +#[post_upgrade] fn post_upgrade() { let (StableState { assets, my_state },): (StableState,) = ic_cdk::storage::stable_restore().expect("failed to restore stable state"); From 7b289bccb020985c0c6548c5ab4ba75d4a1c682c Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Wed, 11 May 2022 23:09:27 +0200 Subject: [PATCH 051/234] fix: make StableState public again (#258) This change makes the StableState type from ic-certified-assets package public again. Making it private was a bug that prevents us from upgrading the certified assets canister to a newer version of ic-certified-assets. --- src/ic-certified-assets/CHANGELOG.md | 4 ++++ src/ic-certified-assets/Cargo.toml | 2 +- src/ic-certified-assets/README.md | 2 +- src/ic-certified-assets/src/lib.rs | 9 +++++---- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/ic-certified-assets/CHANGELOG.md b/src/ic-certified-assets/CHANGELOG.md index a36db5d13..3fdd045f3 100644 --- a/src/ic-certified-assets/CHANGELOG.md +++ b/src/ic-certified-assets/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.2.1] - 2022-05-12 +### Fixed +- Make StableState public again + ## [0.2.0] - 2022-05-11 ### Added - Support for asset caching based on [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml index 8aaaf0fe6..60bf31ecd 100644 --- a/src/ic-certified-assets/Cargo.toml +++ b/src/ic-certified-assets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-certified-assets" -version = "0.2.0" +version = "0.2.1" edition = "2021" authors = ["DFINITY Stiftung "] description = "Rust support for asset certification." diff --git a/src/ic-certified-assets/README.md b/src/ic-certified-assets/README.md index e68ec7816..d128ed891 100644 --- a/src/ic-certified-assets/README.md +++ b/src/ic-certified-assets/README.md @@ -8,7 +8,7 @@ Certified assets can also be served from any Rust canister by including this lib ``` [dependencies] -ic-certified-assets = "0.2.0" +ic-certified-assets = "0.2.1" ``` The assets are preserved over upgrades by including the corresponding functions in the `init/pre_upgrade/upgrade` diff --git a/src/ic-certified-assets/src/lib.rs b/src/ic-certified-assets/src/lib.rs index 31ef65296..ab6cc3a1c 100644 --- a/src/ic-certified-assets/src/lib.rs +++ b/src/ic-certified-assets/src/lib.rs @@ -1,15 +1,16 @@ //! This module declares canister methods expected by the assets canister client. -mod rc_bytes; -mod state_machine; -mod types; +pub mod rc_bytes; +pub mod state_machine; +pub mod types; mod url_decode; #[cfg(test)] mod tests; +pub use crate::state_machine::StableState; use crate::{ rc_bytes::RcBytes, - state_machine::{AssetDetails, EncodedAsset, StableState, State}, + state_machine::{AssetDetails, EncodedAsset, State}, types::*, }; use candid::{candid_method, Principal}; From d823c7c5bb2a3b07c13e2210239e74a15669ba59 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Thu, 12 May 2022 16:11:28 +0200 Subject: [PATCH 052/234] fix: certified assets: parse and produce ETag headers with quotes (#259) --- src/ic-certified-assets/CHANGELOG.md | 4 +- src/ic-certified-assets/README.md | 2 +- src/ic-certified-assets/src/state_machine.rs | 94 +++++++++++++++++--- src/ic-certified-assets/src/tests.rs | 4 +- 4 files changed, 86 insertions(+), 18 deletions(-) diff --git a/src/ic-certified-assets/CHANGELOG.md b/src/ic-certified-assets/CHANGELOG.md index 3fdd045f3..7f933ca10 100644 --- a/src/ic-certified-assets/CHANGELOG.md +++ b/src/ic-certified-assets/CHANGELOG.md @@ -4,7 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.2.2] - 2022-05-12 +### Fixed +- Parse and produce ETag headers with quotes around the hash ## [0.2.1] - 2022-05-12 ### Fixed diff --git a/src/ic-certified-assets/README.md b/src/ic-certified-assets/README.md index d128ed891..9478c816e 100644 --- a/src/ic-certified-assets/README.md +++ b/src/ic-certified-assets/README.md @@ -8,7 +8,7 @@ Certified assets can also be served from any Rust canister by including this lib ``` [dependencies] -ic-certified-assets = "0.2.1" +ic-certified-assets = "0.2.2" ``` The assets are preserved over upgrades by including the corresponding functions in the `init/pre_upgrade/upgrade` diff --git a/src/ic-certified-assets/src/state_machine.rs b/src/ic-certified-assets/src/state_machine.rs index 2d5467870..ac5d76bd5 100644 --- a/src/ic-certified-assets/src/state_machine.rs +++ b/src/ic-certified-assets/src/state_machine.rs @@ -389,7 +389,7 @@ impl State { encodings: Vec, index: usize, callback: Func, - etag: Option, + etags: Vec, ) -> HttpResponse { let index_redirect_certificate = if self.asset_hashes.get(path.as_bytes()).is_none() && self.asset_hashes.get(INDEX_FILE.as_bytes()).is_some() @@ -415,7 +415,7 @@ impl State { index, Some(certificate_header), callback, - etag, + etags, ); } } @@ -438,7 +438,7 @@ impl State { index, Some(certificate_header), callback, - etag, + etags, ); } else { // Find if identity is certified, if it's not. @@ -452,7 +452,7 @@ impl State { index, Some(certificate_header), callback, - etag, + etags, ); } } @@ -471,7 +471,7 @@ impl State { callback: Func, ) -> HttpResponse { let mut encodings = vec![]; - let mut etag = None; + let mut etags = Vec::new(); for (name, value) in req.headers.iter() { if name.eq_ignore_ascii_case("Accept-Encoding") { for v in value.split(',') { @@ -489,17 +489,16 @@ impl State { } } if name.eq_ignore_ascii_case("If-None-Match") { - let mut hash = Hash::default(); - match hex::decode_to_slice(value, &mut hash[..]) { - Ok(()) => { - etag = Some(hash); + match decode_etag_seq(value) { + Ok(decoded_etags) => { + etags = decoded_etags; } Err(err) => { return HttpResponse { status_code: 400, headers: vec![], body: RcBytes::from(ByteBuf::from(format!( - "Invalid {} header: {}", + "Invalid {} header value: {}", name, err ))), streaming_strategy: None, @@ -516,7 +515,7 @@ impl State { }; match url_decode(path) { - Ok(path) => self.build_http_response(certificate, &path, encodings, 0, callback, etag), + Ok(path) => self.build_http_response(certificate, &path, encodings, 0, callback, etags), Err(err) => HttpResponse { status_code: 400, headers: vec![], @@ -590,6 +589,70 @@ impl From for State { } } +fn decode_etag_seq(value: &str) -> Result, String> { + // Hex-encoded 32-byte hash + 2 quotes + const EXPECTED_ETAG_LEN: usize = 66; + let mut etags = Vec::with_capacity(1); + for etag in value.split(',') { + let etag = etag.trim(); + if etag.len() != EXPECTED_ETAG_LEN { + return Err(format!( + "invalid length of component {}: expected {}, got {}", + etag, + EXPECTED_ETAG_LEN, + etag.len() + )); + } + if !etag.starts_with('"') { + return Err(format!("missing first quote of component {}", etag)); + } + if !etag.ends_with('"') { + return Err(format!("missing final quote of component {}", etag)); + } + let mut hash = Hash::default(); + match hex::decode_to_slice(&etag[1..EXPECTED_ETAG_LEN - 1], &mut hash) { + Ok(()) => { + etags.push(hash); + } + Err(e) => return Err(format!("invalid hex of component {}: {}", etag, e)), + } + } + Ok(etags) +} + +#[test] +fn test_decode_seq() { + for (value, expected) in [ + ( + r#""0000000000000000000000000000000000000000000000000000000000000000""#, + vec![[0u8; 32]], + ), + ( + r#""0000000000000000000000000000000000000000000000000000000000000000", "1111111111111111111111111111111111111111111111111111111111111111""#, + vec![[0u8; 32], [17u8; 32]], + ), + ] { + let decoded = decode_etag_seq(value) + .unwrap_or_else(|e| panic!("failed to parse good ETag value {}: {}", value, e)); + assert_eq!(decoded, expected); + } + + for value in [ + r#""00000000000000000000000000000000""#, + r#"0000000000000000000000000000000000000000000000000000000000000000"#, + r#""0000000000000000000000000000000000000000000000000000000000000000" "1111111111111111111111111111111111111111111111111111111111111111""#, + r#"0000000000000000000000000000000000000000000000000000000000000000 1111111111111111111111111111111111111111111111111111111111111111"#, + ] { + let result = decode_etag_seq(value); + assert!( + result.is_err(), + "should have failed to parse invalid ETag value {}, got: {:?}", + value, + result + ); + } +} + fn on_asset_change(asset_hashes: &mut AssetHashes, key: &str, asset: &mut Asset) { // If the most preferred encoding is present and certified, // there is nothing to do. @@ -713,7 +776,7 @@ fn build_ok( chunk_index: usize, certificate_header: Option, callback: Func, - etag: Option, + etags: Vec, ) -> HttpResponse { let mut headers = vec![("Content-Type".to_string(), asset.content_type.to_string())]; if enc_name != "identity" { @@ -729,10 +792,13 @@ fn build_ok( let streaming_strategy = create_token(asset, enc_name, enc, key, chunk_index) .map(|token| StreamingStrategy::Callback { callback, token }); - let (status_code, body) = if etag == Some(enc.sha256) { + let (status_code, body) = if etags.contains(&enc.sha256) { (304, RcBytes::default()) } else { - headers.push(("ETag".to_string(), hex::encode(enc.sha256))); + headers.push(( + "ETag".to_string(), + format!("\"{}\"", hex::encode(enc.sha256)), + )); (200, enc.content_chunks[chunk_index].clone()) }; diff --git a/src/ic-certified-assets/src/tests.rs b/src/ic-certified-assets/src/tests.rs index 1c04195ea..6e897df57 100644 --- a/src/ic-certified-assets/src/tests.rs +++ b/src/ic-certified-assets/src/tests.rs @@ -353,7 +353,7 @@ fn supports_etag_caching() { assert_eq!(response.body.as_ref(), BODY); assert_eq!( lookup_header(&response, "ETag"), - Some(etag.as_str()), + Some(format!("\"{}\"", etag).as_str()), "No matching ETag header in response: {:#?}, expected ETag {}", response, etag @@ -367,7 +367,7 @@ fn supports_etag_caching() { let response = state.http_request( RequestBuilder::get("/contents.html") .with_header("Accept-Encoding", "gzip,identity") - .with_header("If-None-Match", &etag) + .with_header("If-None-Match", format!("\"{}\"", etag)) .build(), &[], unused_callback(), From 334f2aa456a3d00bcb9af54cf7c827b272a1b509 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 12 May 2022 17:04:38 -0400 Subject: [PATCH 053/234] chore: ic-certified-assets v0.2.2 (#260) --- src/ic-certified-assets/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml index 60bf31ecd..15938160f 100644 --- a/src/ic-certified-assets/Cargo.toml +++ b/src/ic-certified-assets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-certified-assets" -version = "0.2.1" +version = "0.2.2" edition = "2021" authors = ["DFINITY Stiftung "] description = "Rust support for asset certification." From c4aa446857f5cab5513dbc2cb7fde0ba798fb83a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=BCller?= <649785+chmllr@users.noreply.github.com> Date: Thu, 12 May 2022 23:06:11 +0200 Subject: [PATCH 054/234] feat: adds serialization-agnostic API for reading arguments and replying (#256) * adds serialization-agnostic API * remove unsafe from reply_raw and arg_data_raw * adds a test * Update src/ic-cdk/src/api/call.rs Co-authored-by: Roman Kashitsyn Co-authored-by: Roman Kashitsyn --- e2e-tests/Cargo.toml | 4 ++++ e2e-tests/canisters/reverse.rs | 14 ++++++++++++++ e2e-tests/tests/e2e.rs | 10 ++++++++++ src/ic-cdk/CHANGELOG.md | 1 + src/ic-cdk/src/api/call.rs | 30 +++++++++++++++++++++--------- 5 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 e2e-tests/canisters/reverse.rs diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 54775be90..df930738f 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -24,5 +24,9 @@ path = "canisters/simple_kv_store.rs" name = "async" path = "canisters/async.rs" +[[bin]] +name = "reverse" +path = "canisters/reverse.rs" + [dev-dependencies] ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "709f9caaffd39c5d63f7ef1ec694eeb2a1b7976a" } diff --git a/e2e-tests/canisters/reverse.rs b/e2e-tests/canisters/reverse.rs new file mode 100644 index 000000000..02b199b0e --- /dev/null +++ b/e2e-tests/canisters/reverse.rs @@ -0,0 +1,14 @@ +use ic_cdk::api::call::{arg_data_raw, reply_raw}; + +#[export_name = "canister_query reverse"] +fn reverse() { + reply_raw( + arg_data_raw() + .into_iter() + .rev() + .collect::>() + .as_ref(), + ); +} + +fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 8747ddf3c..f44723d47 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -117,3 +117,13 @@ fn test_panic_after_async_frees_resources() { assert_eq!(i, n, "expected the invocation count to be {}, got {}", i, n); } } + +#[test] +fn test_raw_api() { + let env = StateMachine::new(); + let rev = cargo_build_canister("reverse"); + let canister_id = env.install_canister(rev, vec![], None).unwrap(); + + let result = env.query(canister_id, "reverse", vec![1, 2, 3, 4]).unwrap(); + assert_eq!(result, WasmResult::Reply(vec![4, 3, 2, 1])); +} diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 049230df7..c289bf1ce 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add `BufferedStableReader` for efficient reading from stable memory (#247) - Add `BufferedStableWriter` for efficient writing to stable memory (#245) +- Add `reply_raw` and publish `arg_data_raw` for serialization-agnostic arguments fetching and replies ## [0.5.0] - 2022-03-29 ### Added diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 6f06651d3..0813d6a70 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -205,7 +205,7 @@ fn callback(state_ptr: *const InnerCell>>) { // Make sure to un-borrow_mut the state. { state.borrow_mut().result = Some(match reject_code() { - RejectionCode::NoError => unsafe { Ok(arg_data_raw()) }, + RejectionCode::NoError => Ok(arg_data_raw()), n => Err((n, reject_message())), }); } @@ -366,8 +366,9 @@ pub fn call_with_payment128 ArgumentDecoder<'a>>( /// and [reject_message()] if it failed. pub fn result ArgumentDecoder<'a>>() -> Result { match reject_code() { - RejectionCode::NoError => decode_args(&unsafe { arg_data_raw() }) - .map_err(|e| format!("Failed to decode arguments: {}", e)), + RejectionCode::NoError => { + decode_args(&arg_data_raw()).map_err(|e| format!("Failed to decode arguments: {}", e)) + } _ => Err(reject_message()), } } @@ -476,16 +477,27 @@ pub fn msg_cycles_accept128(max_amount: u128) -> u128 { } /// Returns the argument data as bytes. -pub(crate) unsafe fn arg_data_raw() -> Vec { - let len: usize = ic0::msg_arg_data_size() as usize; - let mut bytes = vec![0u8; len as usize]; - ic0::msg_arg_data_copy(bytes.as_mut_ptr() as i32, 0, len as i32); - bytes +pub fn arg_data_raw() -> Vec { + unsafe { + let len: usize = ic0::msg_arg_data_size() as usize; + let mut bytes = Vec::with_capacity(len); + ic0::msg_arg_data_copy(bytes.as_mut_ptr() as i32, 0, len as i32); + bytes.set_len(len); + bytes + } +} + +/// Replies with the bytes passed +pub fn reply_raw(buf: &[u8]) { + unsafe { + ic0::msg_reply_data_append(buf.as_ptr() as i32, buf.len() as i32); + ic0::msg_reply(); + } } /// Returns the argument data in the current call. pub fn arg_data ArgumentDecoder<'a>>() -> R { - let bytes = unsafe { arg_data_raw() }; + let bytes = arg_data_raw(); match decode_args(&bytes) { Err(e) => trap(&format!("{:?}", e)), From 8d52f0fd2155fab490ee225df6cf32d5fb61b16d Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Mon, 16 May 2022 18:31:27 +0200 Subject: [PATCH 055/234] feat: support for one-way notifications (#261) * feat: support for one-way notifications This change adds support for calls that do not require replies. * add e2e test for notifications * improve docs * fix clippy * make naming more consistent --- e2e-tests/canisters/async.rs | 22 +++++++++ e2e-tests/tests/e2e.rs | 24 ++++++++++ src/ic-cdk/CHANGELOG.md | 10 ++-- src/ic-cdk/src/api/call.rs | 92 +++++++++++++++++++++++++++++++++--- src/ic-cdk/src/lib.rs | 1 + 5 files changed, 139 insertions(+), 10 deletions(-) diff --git a/e2e-tests/canisters/async.rs b/e2e-tests/canisters/async.rs index ebfb4a593..36b9dcc68 100644 --- a/e2e-tests/canisters/async.rs +++ b/e2e-tests/canisters/async.rs @@ -1,9 +1,11 @@ +use candid::Principal; use ic_cdk_macros::{query, update}; use lazy_static::lazy_static; use std::sync::RwLock; lazy_static! { static ref RESOURCE: RwLock = RwLock::new(0); + static ref NOTIFICATIONS_RECEIVED: RwLock = RwLock::new(0); } #[query] @@ -31,4 +33,24 @@ async fn panic_after_async() { ic_cdk::api::trap("Goodbye, cruel world.") } +#[query] +fn notifications_received() -> u64 { + *NOTIFICATIONS_RECEIVED.read().unwrap() +} + +#[update] +fn on_notify() { + *NOTIFICATIONS_RECEIVED.write().unwrap() += 1; +} + +#[update] +fn notify(whom: Principal, method: String) { + ic_cdk::notify(whom, method.as_str(), ()).unwrap_or_else(|reject| { + ic_cdk::api::trap(&format!( + "failed to notify (callee={}, method={}): {:?}", + whom, method, reject + )) + }); +} + fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index f44723d47..bc9574f5e 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -127,3 +127,27 @@ fn test_raw_api() { let result = env.query(canister_id, "reverse", vec![1, 2, 3, 4]).unwrap(); assert_eq!(result, WasmResult::Reply(vec![4, 3, 2, 1])); } + +#[test] +fn test_notify_calls() { + let env = StateMachine::new(); + let wasm = cargo_build_canister("async"); + let sender_id = env + .install_canister(wasm.clone(), vec![], None) + .expect("failed to install a canister"); + + let receiver_id = env + .install_canister(wasm, vec![], None) + .expect("failed to install a canister"); + + let (n,): (u64,) = query_candid(&env, receiver_id, "notifications_received", ()) + .expect("failed to query 'notifications_received'"); + assert_eq!(n, 0); + + let () = call_candid(&env, sender_id, "notify", (receiver_id, "on_notify")) + .expect("failed to call 'notify'"); + + let (n,): (u64,) = query_candid(&env, receiver_id, "notifications_received", ()) + .expect("failed to query 'notifications_received'"); + assert_eq!(n, 1); +} diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index c289bf1ce..ee43f4523 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,9 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] ### Added -- Add `BufferedStableReader` for efficient reading from stable memory (#247) -- Add `BufferedStableWriter` for efficient writing to stable memory (#245) -- Add `reply_raw` and publish `arg_data_raw` for serialization-agnostic arguments fetching and replies +- `BufferedStableReader` for efficient reading from stable memory (#247) +- `BufferedStableWriter` for efficient writing to stable memory (#245) +- `reply_raw` and publish `arg_data_raw` for serialization-agnostic arguments fetching and replies (#256) +- Support for one-way calls (see `notify` and `notify_raw` functions) (#261) + +### Fixed +- Panicking after `.await` does not leak resources anymore (#232, #250) ## [0.5.0] - 2022-03-29 ### Added diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 0813d6a70..29803fcd4 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -241,6 +241,90 @@ fn cleanup(state_ptr: *const InnerCell>>) { } } +fn add_payment(payment: u128) { + if payment == 0 { + return; + } + let high = (payment >> 64) as u64; + let low = (payment & u64::MAX as u128) as u64; + unsafe { + ic0::call_cycles_add128(high as i64, low as i64); + } +} + +/// Sends a one-way message with `payment` cycles attached to it that invokes `method` with +/// arguments `args` on the principal identified by `id`, ignoring the reply. +/// +/// Returns `Ok(())` if the message was successfully enqueued, otherwise returns a reject code. +/// +/// # Notes +/// +/// * The caller has no way of checking whether the destination processed the notification. +/// The system can drop the notification if the destination does not have resources to +/// process the message (for example, if it's out of cycles or queue slots). +/// +/// * The callee cannot tell whether the call is one-way or not. +/// The callee must produce replies for all incoming messages. +/// +/// * It is safe to upgrade a canister without stopping it first if it sends out *only* +/// one-way messages. +/// +/// * If the payment is non-zero and the system fails to deliver the notification, the behaviour +/// is unspecified: the funds can be either reimbursed or consumed irrevocably by the IC depending +/// on the underlying implementation of one-way calls. +pub fn notify_with_payment128( + id: Principal, + method: &str, + args: T, + payment: u128, +) -> Result<(), RejectionCode> { + let args_raw = encode_args(args).expect("failed to encode arguments"); + notify_raw(id, method, &args_raw, payment) +} + +/// Like [notify_with_payment128], but sets the payment to zero. +pub fn notify( + id: Principal, + method: &str, + args: T, +) -> Result<(), RejectionCode> { + notify_with_payment128(id, method, args, 0) +} + +/// Like [notify], but sends the argument as raw bytes, skipping Candid serialization. +pub fn notify_raw( + id: Principal, + method: &str, + args_raw: &[u8], + payment: u128, +) -> Result<(), RejectionCode> { + let callee = id.as_slice(); + // We set all callbacks to -1, which is guaranteed to be invalid callback index. + // The system will still deliver the reply, but it will trap immediately because the callback + // is not a valid function. See + // https://www.joachim-breitner.de/blog/789-Zero-downtime_upgrades_of_Internet_Computer_canisters#one-way-calls + // for more context. + let err_code = unsafe { + ic0::call_new( + callee.as_ptr() as i32, + callee.len() as i32, + method.as_ptr() as i32, + method.len() as i32, + /* reply_fun = */ -1, + /* reply_env = */ -1, + /* reject_fun = */ -1, + /* reject_env = */ -1, + ); + add_payment(payment); + ic0::call_data_append(args_raw.as_ptr() as i32, args_raw.len() as i32); + ic0::call_perform() + }; + match err_code { + 0 => Ok(()), + c => Err(RejectionCode::from(c)), + } +} + /// Similar to `call`, but without serialization. pub fn call_raw( id: Principal, @@ -265,13 +349,7 @@ pub fn call_raw128( payment: u128, ) -> impl Future>> { call_raw_internal(id, method, args_raw, move || { - if payment > 0 { - unsafe { - let high = (payment >> 64) as u64; - let low = (payment & u64::MAX as u128) as u64; - ic0::call_cycles_add128(high as i64, low as i64); - } - } + add_payment(payment); }) } diff --git a/src/ic-cdk/src/lib.rs b/src/ic-cdk/src/lib.rs index 22407aea0..3229beaa1 100644 --- a/src/ic-cdk/src/lib.rs +++ b/src/ic-cdk/src/lib.rs @@ -12,6 +12,7 @@ mod printer; pub mod storage; pub use api::call::call; +pub use api::call::notify; pub use api::{caller, id, print, trap}; static mut DONE: bool = false; From d056a9cc8a0eee4a2adda2dd60285d0c8ee1061c Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 16 May 2022 14:06:23 -0400 Subject: [PATCH 056/234] Prepare for release 0.5.1 (#262) --- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 2 +- src/ic-cdk/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index e4ae20d91..b42e6b765 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.5.0" +version = "0.5.1" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index ee43f4523..824e66bd6 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [unreleased] +## [0.5.1] - 2022-05-16 ### Added - `BufferedStableReader` for efficient reading from stable memory (#247) - `BufferedStableWriter` for efficient writing to stable memory (#245) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index ef3775b90..082c30d02 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.5.0" +version = "0.5.1" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." From 760e298a817ef244b47473c889f48482d75b5cff Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 19 May 2022 09:37:28 -0400 Subject: [PATCH 057/234] fix: use explicitly type u8 in vector initialization (#264) --- src/ic-cdk/CHANGELOG.md | 4 ++++ src/ic-cdk/src/api.rs | 4 ++-- src/ic-cdk/src/api/call.rs | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 824e66bd6..839af2b42 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Fixed +- Use explicitly type u8 in vector initialization (#264) + ## [0.5.1] - 2022-05-16 ### Added - `BufferedStableReader` for efficient reading from stable memory (#247) diff --git a/src/ic-cdk/src/api.rs b/src/ic-cdk/src/api.rs index 14199c317..5867fdc1e 100644 --- a/src/ic-cdk/src/api.rs +++ b/src/ic-cdk/src/api.rs @@ -31,7 +31,7 @@ pub fn time() -> u64 { /// Returns the caller of the current call. pub fn caller() -> Principal { let len: u32 = unsafe { ic0::msg_caller_size() as u32 }; - let mut bytes = vec![0; len as usize]; + let mut bytes = vec![0u8; len as usize]; unsafe { ic0::msg_caller_copy(bytes.as_mut_ptr() as i32, 0, len as i32); } @@ -41,7 +41,7 @@ pub fn caller() -> Principal { /// Returns the canister id as a blob. pub fn id() -> Principal { let len: u32 = unsafe { ic0::canister_self_size() as u32 }; - let mut bytes = vec![0; len as usize]; + let mut bytes = vec![0u8; len as usize]; unsafe { ic0::canister_self_copy(bytes.as_mut_ptr() as i32, 0, len as i32); } diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 29803fcd4..088f61b68 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -460,7 +460,7 @@ pub fn reject_code() -> RejectionCode { /// Returns the rejection message. pub fn reject_message() -> String { let len: u32 = unsafe { ic0::msg_reject_msg_size() as u32 }; - let mut bytes = vec![0; len as usize]; + let mut bytes = vec![0u8; len as usize]; unsafe { ic0::msg_reject_msg_copy(bytes.as_mut_ptr() as i32, 0, len as i32); } @@ -593,7 +593,7 @@ pub fn accept_message() { /// Returns the name of current canister method. pub fn method_name() -> String { let len: u32 = unsafe { ic0::msg_method_name_size() as u32 }; - let mut bytes = vec![0; len as usize]; + let mut bytes = vec![0u8; len as usize]; unsafe { ic0::msg_method_name_copy(bytes.as_mut_ptr() as i32, 0, len as i32); } From a0246dfe9567405aaebc69c6a0856f4c399b64fd Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 19 May 2022 17:58:30 -0400 Subject: [PATCH 058/234] Create CODEOWNERS (#266) --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..216bca7cf --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +@dfinity/dx From bff7a59cd2e7c6d6f39f55bd8a4075d984ffe9e4 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 24 May 2022 15:45:46 -0400 Subject: [PATCH 059/234] fix: CODEOWNERS needs a pattern (#271) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 216bca7cf..3e4ca7db3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -@dfinity/dx +* @dfinity/dx From 1396c7740f3b7ccaf03610467987c6170727fec4 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Wed, 25 May 2022 15:11:36 -0700 Subject: [PATCH 060/234] fix: switch to correct DFX environment variable (#270) * switch to correct DFX environment variable --- src/ic-cdk-macros/src/import.rs | 2 +- src/ic-cdk/CHANGELOG.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ic-cdk-macros/src/import.rs b/src/ic-cdk-macros/src/import.rs index c606ed918..4665b3735 100644 --- a/src/ic-cdk-macros/src/import.rs +++ b/src/ic-cdk-macros/src/import.rs @@ -15,7 +15,7 @@ struct ImportAttributes { fn get_env_id_and_candid(canister_name: &str) -> Result<(String, PathBuf), Error> { let canister_id_var_name = format!("CANISTER_ID_{}", canister_name); - let candid_path_var_name = format!("CANISTER_CANDID_{}", canister_name); + let candid_path_var_name = format!("CANISTER_CANDID_PATH_{}", canister_name); Ok(( std::env::var(canister_id_var_name).map_err(|_| { diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 839af2b42..80d0aaead 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Fixed - Use explicitly type u8 in vector initialization (#264) +- Uses new format for candid environment variables in import macros. Requires DFX >=0.9.2 (#270) ## [0.5.1] - 2022-05-16 ### Added From 468cc63b89453ec9c334e49a81060c7c7aa4b742 Mon Sep 17 00:00:00 2001 From: Levi <31335633+levifeldman@users.noreply.github.com> Date: Thu, 26 May 2022 11:14:36 -0400 Subject: [PATCH 061/234] feat: public function: arg_data_raw_size (#263) * Add public function: arg_data_raw_size Add test for the arg_data_raw_size function * Unreleased * fmt Co-authored-by: Linwei Shang --- e2e-tests/canisters/reverse.rs | 12 ++++-------- src/ic-cdk/CHANGELOG.md | 5 ++++- src/ic-cdk/src/api/call.rs | 5 +++++ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/e2e-tests/canisters/reverse.rs b/e2e-tests/canisters/reverse.rs index 02b199b0e..f8f16c8d4 100644 --- a/e2e-tests/canisters/reverse.rs +++ b/e2e-tests/canisters/reverse.rs @@ -1,14 +1,10 @@ -use ic_cdk::api::call::{arg_data_raw, reply_raw}; +use ic_cdk::api::call::{arg_data_raw, arg_data_raw_size, reply_raw}; #[export_name = "canister_query reverse"] fn reverse() { - reply_raw( - arg_data_raw() - .into_iter() - .rev() - .collect::>() - .as_ref(), - ); + let arg_bytes: Vec = arg_data_raw(); + assert_eq!(arg_bytes.len(), arg_data_raw_size()); + reply_raw(arg_bytes.into_iter().rev().collect::>().as_ref()); } fn main() {} diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 80d0aaead..75ace612e 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -4,7 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [Unreleased] +### Added +- pub fn `arg_data_raw_size` for checking the size of the arg-data-raw before copying to a vector or deserializing (#263) + ### Fixed - Use explicitly type u8 in vector initialization (#264) - Uses new format for candid environment variables in import macros. Requires DFX >=0.9.2 (#270) diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 088f61b68..04c1888f2 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -565,6 +565,11 @@ pub fn arg_data_raw() -> Vec { } } +/// Get the len of the raw-argument-data-bytes. +pub fn arg_data_raw_size() -> usize { + unsafe { ic0::msg_arg_data_size() as usize } +} + /// Replies with the bytes passed pub fn reply_raw(buf: &[u8]) { unsafe { From a080645844d2c761639707a58e51d400543eabce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=BCller?= <649785+chmllr@users.noreply.github.com> Date: Thu, 26 May 2022 18:09:45 +0200 Subject: [PATCH 062/234] do not append on empty buffer (#268) Co-authored-by: Linwei Shang --- e2e-tests/canisters/reverse.rs | 4 ++++ e2e-tests/tests/e2e.rs | 5 +++++ src/ic-cdk/CHANGELOG.md | 1 + src/ic-cdk/src/api/call.rs | 4 +++- 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/e2e-tests/canisters/reverse.rs b/e2e-tests/canisters/reverse.rs index f8f16c8d4..5afa9ce12 100644 --- a/e2e-tests/canisters/reverse.rs +++ b/e2e-tests/canisters/reverse.rs @@ -6,5 +6,9 @@ fn reverse() { assert_eq!(arg_bytes.len(), arg_data_raw_size()); reply_raw(arg_bytes.into_iter().rev().collect::>().as_ref()); } +#[export_name = "canister_update empty_call"] +fn empty_call() { + reply_raw(&[]); +} fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index bc9574f5e..6512d09b7 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -126,6 +126,11 @@ fn test_raw_api() { let result = env.query(canister_id, "reverse", vec![1, 2, 3, 4]).unwrap(); assert_eq!(result, WasmResult::Reply(vec![4, 3, 2, 1])); + + let result = env + .execute_ingress(canister_id, "empty_call", Default::default()) + .unwrap(); + assert_eq!(result, WasmResult::Reply(Default::default())); } #[test] diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 75ace612e..1d4d779c4 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Use explicitly type u8 in vector initialization (#264) +- Make `reply_raw` avoid writing empty replies - Uses new format for candid environment variables in import macros. Requires DFX >=0.9.2 (#270) ## [0.5.1] - 2022-05-16 diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 04c1888f2..b3bc5a419 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -573,7 +573,9 @@ pub fn arg_data_raw_size() -> usize { /// Replies with the bytes passed pub fn reply_raw(buf: &[u8]) { unsafe { - ic0::msg_reply_data_append(buf.as_ptr() as i32, buf.len() as i32); + if !buf.is_empty() { + ic0::msg_reply_data_append(buf.as_ptr() as i32, buf.len() as i32) + }; ic0::msg_reply(); } } From ec218cf4830e149022f0ee933bee4edb501b3512 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Tue, 31 May 2022 15:29:08 +0200 Subject: [PATCH 063/234] feat: interface to query ledger blocks (#269) * feat: interface to query ledger blocks This change introduces new interface in `ic-ledger-types` to query blocks (the [`query_blocks` endpoint](https://github.com/dfinity/ic/blob/7456121c506acaaa79d2251b803709abf0bdcbb3/rs/rosetta-api/ledger_canister/ledger.did#L236) of the ICP ledger). * make block fields pub --- src/ic-ledger-types/CHANGELOG.md | 5 + src/ic-ledger-types/Cargo.toml | 1 + src/ic-ledger-types/src/lib.rs | 184 ++++++++++++++++++++++++++++++- 3 files changed, 189 insertions(+), 1 deletion(-) diff --git a/src/ic-ledger-types/CHANGELOG.md b/src/ic-ledger-types/CHANGELOG.md index ac5b5afc5..53d6b66e9 100644 --- a/src/ic-ledger-types/CHANGELOG.md +++ b/src/ic-ledger-types/CHANGELOG.md @@ -4,8 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Added +* Methods to query ledger blocks. + ### Changed * Support conversion from `[u8; 32]` to `AccountIdentifier` via `TryFrom` with CRC-32 check. +* Upgrade `ic-cdk` to 0.5.0 ## [0.1.1] - 2022-02-04 ### Changed diff --git a/src/ic-ledger-types/Cargo.toml b/src/ic-ledger-types/Cargo.toml index 717ef11d7..58cc7ea81 100644 --- a/src/ic-ledger-types/Cargo.toml +++ b/src/ic-ledger-types/Cargo.toml @@ -22,5 +22,6 @@ candid = "0.7.4" crc32fast = "1.2.0" hex = "0.4" serde = "1" +serde_bytes = "0.11" sha2 = "0.9" diff --git a/src/ic-ledger-types/src/lib.rs b/src/ic-ledger-types/src/lib.rs index d21bd2c48..7efc5590c 100644 --- a/src/ic-ledger-types/src/lib.rs +++ b/src/ic-ledger-types/src/lib.rs @@ -1,6 +1,7 @@ +use candid::{types::reference::Func, CandidType, Principal}; use ic_cdk::api::call::CallResult; -use ic_cdk::export::candid::{CandidType, Principal}; use serde::{Deserialize, Serialize}; +use serde_bytes::ByteBuf; use sha2::Digest; use std::convert::TryFrom; use std::fmt; @@ -246,6 +247,143 @@ impl fmt::Display for TransferError { } } +#[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub enum Operation { + Mint { + to: AccountIdentifier, + amount: Tokens, + }, + Burn { + from: AccountIdentifier, + amount: Tokens, + }, + Transfer { + from: AccountIdentifier, + to: AccountIdentifier, + amount: Tokens, + fee: Tokens, + }, +} + +#[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct Transaction { + pub memo: Memo, + pub operation: Option, + /// The time at which the client of the ledger constructed the transaction. + pub created_at_time: Timestamp, +} + +#[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct Block { + /// The hash of the parent block. + pub parent_hash: Option<[u8; 32]>, + pub transaction: Transaction, + /// The time at which the ledger constructed the block. + pub timestamp: Timestamp, +} + +#[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct GetBlocksArgs { + /// The index of the first block to fetch. + pub start: BlockIndex, + /// Max number of blocks to fetch. + pub length: u64, +} + +#[derive(CandidType, Deserialize, Clone, Debug)] +pub struct QueryBlocksResponse { + pub chain_length: u64, + /// The replica certificate for the last block hash (see https://internetcomputer.org/docs/current/references/ic-interface-spec#certification-encoding). + /// Not available when querying blocks from a canister. + pub certificate: Option, + pub blocks: Vec, + /// The index of the first block in [QueryBlocksResponse::blocks]. + pub first_block_index: BlockIndex, + pub archived_blocks: Vec, +} + +#[derive(CandidType, Deserialize, Clone, Debug)] +pub struct ArchivedBlockRange { + pub start: BlockIndex, + pub length: u64, + pub callback: QueryArchiveFn, +} + +#[derive(CandidType, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct BlockRange { + pub blocks: Vec, +} + +pub type GetBlocksResult = Result; + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, CandidType)] +pub enum GetBlocksError { + BadFirstBlockIndex { + requested_index: BlockIndex, + first_valid_index: BlockIndex, + }, + Other { + error_code: u64, + error_message: String, + }, +} + +impl fmt::Display for GetBlocksError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::BadFirstBlockIndex { + requested_index, + first_valid_index, + } => write!( + f, + "invalid first block index: requested block = {}, first valid block = {}", + requested_index, first_valid_index + ), + Self::Other { + error_code, + error_message, + } => write!( + f, + "failed to query blocks (error code {}): {}", + error_code, error_message + ), + } + } +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(transparent)] +pub struct QueryArchiveFn(Func); + +impl From for QueryArchiveFn { + fn from(func: Func) -> Self { + Self(func) + } +} + +impl From for Func { + fn from(query_func: QueryArchiveFn) -> Self { + query_func.0 + } +} + +impl CandidType for QueryArchiveFn { + fn _ty() -> candid::types::Type { + candid::types::Type::Func(candid::types::Function { + modes: vec![candid::parser::types::FuncMode::Query], + args: vec![GetBlocksArgs::_ty()], + rets: vec![GetBlocksResult::_ty()], + }) + } + + fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> + where + S: candid::types::Serializer, + { + Func::from(self.clone()).idl_serialize(serializer) + } +} + /// Calls the "account_balance" method on the specified canister. /// /// # Example @@ -298,6 +436,50 @@ pub async fn transfer( Ok(result) } +/// Calls the "query_block" method on the specified canister. +/// # Example +/// ```no_run +/// use candid::Principal; +/// use ic_cdk::api::call::CallResult; +/// use ic_ledger_types::{BlockIndex, Block, GetBlocksArgs, query_blocks, query_archived_blocks}; +/// +/// async fn query_one_block(ledger: Principal, block_index: BlockIndex) -> CallResult> { +/// let args = GetBlocksArgs { start: block_index, length: 1 }; +/// +/// let blocks_result = query_blocks(ledger, args.clone()).await?; +/// +/// if blocks_result.blocks.len() >= 1 { +/// debug_assert_eq!(blocks_result.first_block_index, block_index); +/// return Ok(blocks_result.blocks.into_iter().next()); +/// } +/// +/// if let Some(func) = blocks_result +/// .archived_blocks +/// .into_iter() +/// .find_map(|b| (b.start <= block_index && (block_index - b.start) < b.length).then(|| b.callback)) { +/// match query_archived_blocks(&func, args).await? { +/// Ok(range) => return Ok(range.blocks.into_iter().next()), +/// _ => (), +/// } +/// } +/// Ok(None) +/// } +pub async fn query_blocks( + ledger_canister_id: Principal, + args: GetBlocksArgs, +) -> CallResult { + let (result,) = ic_cdk::call(ledger_canister_id, "query_blocks", (args,)).await?; + Ok(result) +} + +pub async fn query_archived_blocks( + func: &QueryArchiveFn, + args: GetBlocksArgs, +) -> CallResult { + let (result,) = ic_cdk::api::call::call(func.0.principal, &func.0.method, (args,)).await?; + Ok(result) +} + #[cfg(test)] mod tests { use super::*; From ebcd6f0203198575c1979f0d074df4d76660986b Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Tue, 31 May 2022 15:03:23 +0100 Subject: [PATCH 064/234] feat: integrate with the ledger's `token_symbol` method (#267) * Integrate with the ledger's `token_symbol` method * Update CHANGELOG Co-authored-by: Linwei Shang --- src/ic-ledger-types/CHANGELOG.md | 11 ++++++----- src/ic-ledger-types/src/lib.rs | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/ic-ledger-types/CHANGELOG.md b/src/ic-ledger-types/CHANGELOG.md index 53d6b66e9..9b78a031a 100644 --- a/src/ic-ledger-types/CHANGELOG.md +++ b/src/ic-ledger-types/CHANGELOG.md @@ -6,16 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -* Methods to query ledger blocks. +- Integrate with the ledger's `token_symbol` method +- Methods to query ledger blocks. ### Changed -* Support conversion from `[u8; 32]` to `AccountIdentifier` via `TryFrom` with CRC-32 check. -* Upgrade `ic-cdk` to 0.5.0 +- Support conversion from `[u8; 32]` to `AccountIdentifier` via `TryFrom` with CRC-32 check. +- Upgrade `ic-cdk` to 0.5.0 ## [0.1.1] - 2022-02-04 ### Changed -* Upgrade `ic-cdk` to v0.4.0. +- Upgrade `ic-cdk` to v0.4.0. ## [0.1.0] - 2021-11-11 ### Added -* Initial release of the library. +- Initial release of the library. diff --git a/src/ic-ledger-types/src/lib.rs b/src/ic-ledger-types/src/lib.rs index 7efc5590c..6b04ad877 100644 --- a/src/ic-ledger-types/src/lib.rs +++ b/src/ic-ledger-types/src/lib.rs @@ -436,6 +436,27 @@ pub async fn transfer( Ok(result) } +#[derive(Serialize, Deserialize, CandidType, Clone, Hash, Debug, PartialEq, Eq)] +pub struct Symbol { + pub symbol: String, +} + +/// Calls the "token_symbol" method on the specified canister. +/// # Example +/// ```no_run +/// use candid::Principal; +/// use ic_cdk::api::{caller, call::call}; +/// use ic_ledger_types::{Symbol, token_symbol}; +/// +/// async fn symbol(ledger_canister_id: Principal) -> String { +/// token_symbol(ledger_canister_id).await.expect("call to ledger failed").symbol +/// } +/// ``` +pub async fn token_symbol(ledger_canister_id: Principal) -> CallResult { + let (result,) = ic_cdk::call(ledger_canister_id, "token_symbol", ()).await?; + Ok(result) +} + /// Calls the "query_block" method on the specified canister. /// # Example /// ```no_run From 3c18d2413f1c76de0aaf1ae6ff396256aecedcc4 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 31 May 2022 13:43:59 -0400 Subject: [PATCH 065/234] chore: relase ic-ledger-types v0.1.2 (#272) --- src/ic-ledger-types/CHANGELOG.md | 2 +- src/ic-ledger-types/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ic-ledger-types/CHANGELOG.md b/src/ic-ledger-types/CHANGELOG.md index 9b78a031a..569f6aef3 100644 --- a/src/ic-ledger-types/CHANGELOG.md +++ b/src/ic-ledger-types/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.1.2] - 2022-05-31 ### Added - Integrate with the ledger's `token_symbol` method - Methods to query ledger blocks. diff --git a/src/ic-ledger-types/Cargo.toml b/src/ic-ledger-types/Cargo.toml index 58cc7ea81..71e04be81 100644 --- a/src/ic-ledger-types/Cargo.toml +++ b/src/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.1.1" +version = "0.1.2" edition = "2021" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." From dcf6c94c688be597111ae9f857ba85a7ddf633f7 Mon Sep 17 00:00:00 2001 From: Eric Swanson <64809312+ericswanson-dfinity@users.noreply.github.com> Date: Tue, 31 May 2022 11:11:32 -0700 Subject: [PATCH 066/234] chore: aggregate matrix checks for required statuses (#274) --- .github/workflows/e2e.yml | 12 +++++++++++- .github/workflows/examples.yml | 10 ++++++++++ .github/workflows/fmt.yml | 10 ++++++++++ .github/workflows/lint.yml | 10 ++++++++++ .github/workflows/test.yml | 10 ++++++++++ 5 files changed, 51 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 62dd703ae..ec8254baf 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -50,4 +50,14 @@ jobs: # and https://github.com/rust-lang/cargo/issues/8603 for some more # information. An alternative solution here is to install GNU tar, but # flushing the disk cache seems to work, too. - sudo /usr/sbin/purge \ No newline at end of file + sudo /usr/sbin/purge + + aggregate: + name: e2e:required + if: ${{ always() }} + needs: test + runs-on: ubuntu-latest + steps: + - name: check step result directly + if: ${{ needs.test.result != 'success' }} + run: exit 1 diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 7ab0aa40b..3297a1e8f 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -65,3 +65,13 @@ jobs: # information. An alternative solution here is to install GNU tar, but # flushing the disk cache seems to work, too. sudo /usr/sbin/purge + + aggregate: + name: examples:required + if: ${{ always() }} + needs: test + runs-on: ubuntu-latest + steps: + - name: check step result directly + if: ${{ needs.test.result != 'success' }} + run: exit 1 diff --git a/.github/workflows/fmt.yml b/.github/workflows/fmt.yml index 25d737e69..68d61c16e 100644 --- a/.github/workflows/fmt.yml +++ b/.github/workflows/fmt.yml @@ -34,3 +34,13 @@ jobs: run: cargo fmt --all -- --check env: RUST_BACKTRACE: 1 + + aggregate: + name: fmt:required + if: ${{ always() }} + needs: test + runs-on: ubuntu-latest + steps: + - name: check step result directly + if: ${{ needs.test.result != 'success' }} + run: exit 1 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 000b41319..653a02c23 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -31,3 +31,13 @@ jobs: run: cargo clippy --tests --benches -- -D clippy::all env: RUST_BACKTRACE: 1 + + aggregate: + name: lint:required + if: ${{ always() }} + needs: test + runs-on: ubuntu-latest + steps: + - name: check step result directly + if: ${{ needs.test.result != 'success' }} + run: exit 1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 509a256f8..7c3aa63bc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -73,3 +73,13 @@ jobs: # information. An alternative solution here is to install GNU tar, but # flushing the disk cache seems to work, too. sudo /usr/sbin/purge + + aggregate: + name: test:required + if: ${{ always() }} + needs: test + runs-on: ubuntu-latest + steps: + - name: check step result directly + if: ${{ needs.test.result != 'success' }} + run: exit 1 From 7e42edb016186097d2acea17f72fc7e869e19d79 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Tue, 31 May 2022 12:15:54 -0700 Subject: [PATCH 067/234] Future-proof against multithreading (#273) --- src/ic-cdk/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ic-cdk/src/lib.rs b/src/ic-cdk/src/lib.rs index 3229beaa1..af9c6a859 100644 --- a/src/ic-cdk/src/lib.rs +++ b/src/ic-cdk/src/lib.rs @@ -6,6 +6,9 @@ //! https://smartcontracts.org/docs/interface-spec/index.html#system-api-imports) //! for a full list of the system API functions. +#[cfg(target_feature = "atomics")] +compile_error!("This version of the CDK does not support multithreading."); + pub mod api; mod futures; mod printer; From 67fd25c8cc3e085ade080a0b1349da5cbb17bba3 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 22 Jun 2022 19:25:12 -0400 Subject: [PATCH 068/234] feat: support performance_counter (#277) * update API definition from spec * update rust & ic rev * Add safe API * Add test api-call * rust in ci * changelog * lint --- .github/workflows/e2e.yml | 4 ++-- .github/workflows/examples.yml | 2 +- .github/workflows/fmt.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 6 +++--- e2e-tests/Cargo.toml | 6 +++++- e2e-tests/canisters/api_call.rs | 8 ++++++++ e2e-tests/src/lib.rs | 2 +- e2e-tests/tests/e2e.rs | 11 +++++++++++ rust-toolchain.toml | 2 +- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-optimizer/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 3 ++- src/ic-cdk/Cargo.toml | 2 +- src/ic-cdk/src/api/call.rs | 8 ++++++++ src/ic-cdk/src/api/ic0.rs | 19 ++++++++++--------- src/ic-certified-assets/Cargo.toml | 2 +- src/ic-certified-map/Cargo.toml | 2 +- src/ic-ledger-types/Cargo.toml | 2 +- 19 files changed, 60 insertions(+), 27 deletions(-) create mode 100644 e2e-tests/canisters/api_call.rs diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index ec8254baf..a10db3fda 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -15,10 +15,10 @@ jobs: include: - build: linux-stable os: ubuntu-latest - rust: 1.58.1 + rust: 1.60.0 - build: macos-stable os: macos-latest - rust: 1.58.1 + rust: 1.60.0 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 3297a1e8f..c9d5b3aec 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -16,7 +16,7 @@ jobs: include: - build: linux-stable os: ubuntu-latest - rust: 1.58.1 + rust: 1.60.0 dfx: 0.9.3 steps: diff --git a/.github/workflows/fmt.yml b/.github/workflows/fmt.yml index 68d61c16e..0b9361382 100644 --- a/.github/workflows/fmt.yml +++ b/.github/workflows/fmt.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust: [ 1.58.1 ] + rust: [ 1.60.0 ] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 653a02c23..2516e8724 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust: [ 1.58.1 ] + rust: [ 1.60.0 ] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7c3aa63bc..6deae052e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,13 +15,13 @@ jobs: include: - build: linux-stable os: ubuntu-latest - rust: 1.58.1 + rust: 1.60.0 - build: macos-stable os: macos-latest - rust: 1.58.1 + rust: 1.60.0 - build: windows-stable os: windows-latest - rust: 1.58.1 + rust: 1.60.0 steps: - uses: actions/checkout@v2 diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index df930738f..e6b85ebab 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -28,5 +28,9 @@ path = "canisters/async.rs" name = "reverse" path = "canisters/reverse.rs" +[[bin]] +name = "api-call" +path = "canisters/api_call.rs" + [dev-dependencies] -ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "709f9caaffd39c5d63f7ef1ec694eeb2a1b7976a" } +ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "92e6b0ed36cdc9322a3588f46a8c8c7cc567e143" } diff --git a/e2e-tests/canisters/api_call.rs b/e2e-tests/canisters/api_call.rs new file mode 100644 index 000000000..73a3fbf9e --- /dev/null +++ b/e2e-tests/canisters/api_call.rs @@ -0,0 +1,8 @@ +use ic_cdk_macros::query; + +#[query] +fn instruction_counter() -> u64 { + ic_cdk::api::call::performance_counter(0) +} + +fn main() {} diff --git a/e2e-tests/src/lib.rs b/e2e-tests/src/lib.rs index 39bb9bdce..baae339d2 100644 --- a/e2e-tests/src/lib.rs +++ b/e2e-tests/src/lib.rs @@ -22,7 +22,7 @@ pub fn cargo_build_canister(bin_name: &str) -> Vec { let cargo_build = CargoBuild::new() .target("wasm32-unknown-unknown") - .bin(bin_name.to_string()) + .bin(bin_name) .args(["--profile", "canister-release"]) .manifest_path(&cargo_toml_path) .target_dir(&wasm_target_dir); diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 6512d09b7..da5eb4745 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -156,3 +156,14 @@ fn test_notify_calls() { .expect("failed to query 'notifications_received'"); assert_eq!(n, 1); } + +#[test] +fn test_api_call() { + let env = StateMachine::new(); + let rev = cargo_build_canister("api-call"); + let canister_id = env.install_canister(rev, vec![], None).unwrap(); + + let (result,): (u64,) = query_candid(&env, canister_id, "instruction_counter", ()) + .expect("failed to query instruction_counter"); + assert!(result > 0); +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 47462fc08..9b31b1996 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.58.1" +channel = "1.60.0" targets = ["wasm32-unknown-unknown"] components = ["rustfmt", "clippy"] diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index b42e6b765..71abfd243 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -12,7 +12,7 @@ categories = ["api-bindings", "data-structures", "no-std", "development-tools::f keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.58.1" +rust-version = "1.60.0" [lib] proc-macro = true diff --git a/src/ic-cdk-optimizer/Cargo.toml b/src/ic-cdk-optimizer/Cargo.toml index 335ccc868..9c368b735 100644 --- a/src/ic-cdk-optimizer/Cargo.toml +++ b/src/ic-cdk-optimizer/Cargo.toml @@ -12,7 +12,7 @@ categories = ["api-bindings", "data-structures", "no-std", "command-line-utiliti keywords = ["internet-computer", "dfinity", "canister", "cli", "optimizer"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.58.1" +rust-version = "1.60.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 1d4d779c4..dff2d5af6 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,7 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- pub fn `arg_data_raw_size` for checking the size of the arg-data-raw before copying to a vector or deserializing (#263) +- `arg_data_raw_size` for checking the size of the arg-data-raw before copying to a vector or deserializing (#263) +- `performance_counter` for getting the value of specified performance counter (#277) ### Fixed - Use explicitly type u8 in vector initialization (#264) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 082c30d02..26803805a 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -12,7 +12,7 @@ categories = ["api-bindings", "data-structures", "no-std", "development-tools::f keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.58.1" +rust-version = "1.60.0" [dependencies] candid = "0.7.4" diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index b3bc5a419..df5dc3ac5 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -607,6 +607,14 @@ pub fn method_name() -> String { String::from_utf8_lossy(&bytes).to_string() } +/// Get the value of specified performance counter +/// +/// Supported counter type: +/// 0 : instruction counter. The number of WebAssembly instructions the system has determined that the canister has executed. +pub fn performance_counter(counter_type: u32) -> u64 { + unsafe { ic0::performance_counter(counter_type as i32) as u64 } +} + /// Pretends to have the Candid type `T`, but unconditionally errors /// when serialized. /// diff --git a/src/ic-cdk/src/api/ic0.rs b/src/ic-cdk/src/api/ic0.rs index 7ef411f2d..6d0e57c81 100644 --- a/src/ic-cdk/src/api/ic0.rs +++ b/src/ic-cdk/src/api/ic0.rs @@ -61,19 +61,20 @@ macro_rules! ic0_module { // This is a private module that can only be used internally in this file. // Copy-paste the spec section of the API here. -// Current spec version: 0.18.2 +// https://github.com/dfinity/interface-spec/blob/master/spec/ic0.txt /* The comment after each function lists from where these functions may be invoked: I: from canister_init or canister_post_upgrade G: from canister_pre_upgrade -U: from canister_update +U: from canister_update … Q: from canister_query … Ry: from a reply callback Rt: from a reject callback C: from a cleanup callback s: the (start) module initialization function F: from canister_inspect_message -* = I G U Q Ry Rt C F (NB: Not (start)) +H: from canister_heartbeat +* = I G U Q Ry Rt C F H (NB: Not (start)) */ ic0_module! { ic0.msg_arg_data_size : () -> i32; // I U Q Ry F @@ -92,9 +93,9 @@ ic0_module! { ic0.msg_cycles_available128 : (dst : i32) -> (); // U Rt Ry ic0.msg_cycles_refunded : () -> i64; // Rt Ry ic0.msg_cycles_refunded128 : (dst : i32) -> (); // Rt Ry - ic0.msg_cycles_accept : ( max_amount : i64) -> ( amount : i64 ); // U Rt Ry - ic0.msg_cycles_accept128 : ( max_amount_high : i64, max_amount_low: i64, dst : i32) - -> (); // U Rt Ry + ic0.msg_cycles_accept : (max_amount : i64) -> (amount : i64); // U Rt Ry + ic0.msg_cycles_accept128 : (max_amount_high : i64, max_amount_low: i64, dst : i32) + -> (); // U Rt Ry ic0.canister_self_size : () -> i32; // * ic0.canister_self_copy : (dst : i32, offset : i32, size : i32) -> (); // * @@ -118,8 +119,8 @@ ic0_module! { ) -> (); ic0.call_on_cleanup : (fun : i32, env : i32) -> (); // U Ry Rt H ic0.call_data_append : (src : i32, size : i32) -> (); // U Ry Rt H - ic0.call_cycles_add : ( amount : i64 ) -> (); // U Ry Rt H - ic0.call_cycles_add128 : ( amount_high : i64, amount_low: i64 ) -> (); // U Ry Rt H + ic0.call_cycles_add : (amount : i64) -> (); // U Ry Rt H + ic0.call_cycles_add128 : (amount_high : i64, amount_low: i64) -> (); // U Ry Rt H ic0.call_perform : () -> ( err_code : i32 ); // U Ry Rt H ic0.stable_size : () -> (page_count : i32); // * @@ -137,7 +138,7 @@ ic0_module! { ic0.data_certificate_copy : (dst: i32, offset: i32, size: i32) -> (); // * ic0.time : () -> (timestamp : i64); // * - ic0.performance_counter : () -> (counter : i64); // * s + ic0.performance_counter : (counter_type : i32) -> (counter : i64); // * s ic0.debug_print : (src : i32, size : i32) -> (); // * s ic0.trap : (src : i32, size : i32) -> (); // * s diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml index 15938160f..635f80d0d 100644 --- a/src/ic-certified-assets/Cargo.toml +++ b/src/ic-certified-assets/Cargo.toml @@ -8,7 +8,7 @@ license = "Apache-2.0" keywords = ["internet-computer", "dfinity"] categories = ["wasm", "filesystem", "data-structures"] repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.58.1" +rust-version = "1.60.0" [dependencies] base64 = "0.13" diff --git a/src/ic-certified-map/Cargo.toml b/src/ic-certified-map/Cargo.toml index 22c8ad48f..6d0dec7c4 100644 --- a/src/ic-certified-map/Cargo.toml +++ b/src/ic-certified-map/Cargo.toml @@ -12,7 +12,7 @@ categories = ["data-structures", "cryptography", "cryptography::cryptocurrencies keywords = ["internet-computer", "types", "dfinity", "map"] include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.58.1" +rust-version = "1.60.0" [dependencies] serde = "1" diff --git a/src/ic-ledger-types/Cargo.toml b/src/ic-ledger-types/Cargo.toml index 71e04be81..15d07d83c 100644 --- a/src/ic-ledger-types/Cargo.toml +++ b/src/ic-ledger-types/Cargo.toml @@ -12,7 +12,7 @@ keywords = ["internet-computer", "ledger"] categories = ["cryptography::cryptocurrencies", "data-structures"] include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.58.1" +rust-version = "1.60.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 6f646b016f177877f48ae7316e6d9aa91e9c5c1c Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 23 Jun 2022 10:00:17 -0400 Subject: [PATCH 069/234] chore: release cdk v0.5.2 (#279) * chore: release cdk v0.5.2 * include unrelease section --- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 4 +++- src/ic-cdk/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 71abfd243..b7b4a6e37 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.5.1" +version = "0.5.2" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index dff2d5af6..31368ce8d 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -4,7 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [unreleased] + +## [0.5.2] - 2022-06-23 ### Added - `arg_data_raw_size` for checking the size of the arg-data-raw before copying to a vector or deserializing (#263) - `performance_counter` for getting the value of specified performance counter (#277) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 26803805a..9f951dc35 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.5.1" +version = "0.5.2" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." From a253ef473f83e62a48fe3510d0ddf7509ebd96a6 Mon Sep 17 00:00:00 2001 From: Jason <98767015+dfx-json@users.noreply.github.com> Date: Wed, 29 Jun 2022 08:38:52 -0700 Subject: [PATCH 070/234] Update CODEOWNERS (#280) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3e4ca7db3..a7d188778 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @dfinity/dx +* @dfinity/sdk From 51df528571b4286feead6bb3b83d1ca92c713503 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 30 Jun 2022 10:49:02 -0400 Subject: [PATCH 071/234] feat: make CanisterStableMemory public (#281) * feat: make CanisterStableMemory public * changelog --- src/ic-cdk/CHANGELOG.md | 3 +++ src/ic-cdk/src/api/stable.rs | 2 +- src/ic-cdk/src/api/stable/canister.rs | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 31368ce8d..ad0cc74b3 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Changed +- Make `CanisterStableMemory` public (#281) + ## [0.5.2] - 2022-06-23 ### Added - `arg_data_raw_size` for checking the size of the arg-data-raw before copying to a vector or deserializing (#263) diff --git a/src/ic-cdk/src/api/stable.rs b/src/ic-cdk/src/api/stable.rs index 704cfa132..3c291491a 100644 --- a/src/ic-cdk/src/api/stable.rs +++ b/src/ic-cdk/src/api/stable.rs @@ -6,7 +6,7 @@ mod canister; #[cfg(test)] mod tests; -use canister::CanisterStableMemory; +pub use canister::CanisterStableMemory; use std::{error, fmt, io}; const WASM_PAGE_SIZE_IN_BYTES: usize = 64 * 1024; // 64KB diff --git a/src/ic-cdk/src/api/stable/canister.rs b/src/ic-cdk/src/api/stable/canister.rs index 9c2c5fc5d..113e3c3f7 100644 --- a/src/ic-cdk/src/api/stable/canister.rs +++ b/src/ic-cdk/src/api/stable/canister.rs @@ -1,6 +1,9 @@ use super::*; use crate::api::ic0; +/// A standard implementation of [`StableMemory`]. +/// +/// Useful for creating [`StableWriter`] and [`StableReader`]. #[derive(Default)] pub struct CanisterStableMemory {} From 58d276340c2592aa9dcbc4a3e79ef4ac4fca023b Mon Sep 17 00:00:00 2001 From: Marcin Nowak-Liebiediew Date: Wed, 6 Jul 2022 21:47:26 +0200 Subject: [PATCH 072/234] feat: support for setting custom HTTP headers on asset creation (#282) * (untested) support for setting custom HTTP headers on asset creation * add test * bump version in `Cargo.toml` (0.2.2 -> 0.2.3) * changelog --- src/ic-certified-assets/CHANGELOG.md | 4 + src/ic-certified-assets/Cargo.toml | 2 +- src/ic-certified-assets/assets.did | 1 + src/ic-certified-assets/src/state_machine.rs | 7 ++ src/ic-certified-assets/src/tests.rs | 81 ++++++++++++++++++++ src/ic-certified-assets/src/types.rs | 3 + 6 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/ic-certified-assets/CHANGELOG.md b/src/ic-certified-assets/CHANGELOG.md index 7f933ca10..d8e93749c 100644 --- a/src/ic-certified-assets/CHANGELOG.md +++ b/src/ic-certified-assets/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.3] - 2022-07-06 +### Added +- Support for setting custom HTTP headers on asset creation + ## [0.2.2] - 2022-05-12 ### Fixed - Parse and produce ETag headers with quotes around the hash diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml index 635f80d0d..c146a2681 100644 --- a/src/ic-certified-assets/Cargo.toml +++ b/src/ic-certified-assets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-certified-assets" -version = "0.2.2" +version = "0.2.3" edition = "2021" authors = ["DFINITY Stiftung "] description = "Rust support for asset certification." diff --git a/src/ic-certified-assets/assets.did b/src/ic-certified-assets/assets.did index 0b8d606b9..deaa63fce 100644 --- a/src/ic-certified-assets/assets.did +++ b/src/ic-certified-assets/assets.did @@ -7,6 +7,7 @@ type CreateAssetArguments = record { key: Key; content_type: text; max_age: opt nat64; + headers: opt HeaderField; }; // Add or change content for an asset, by content encoding diff --git a/src/ic-certified-assets/src/state_machine.rs b/src/ic-certified-assets/src/state_machine.rs index ac5d76bd5..e754bcc44 100644 --- a/src/ic-certified-assets/src/state_machine.rs +++ b/src/ic-certified-assets/src/state_machine.rs @@ -41,6 +41,7 @@ pub struct Asset { pub content_type: String, pub encodings: HashMap, pub max_age: Option, + pub headers: Option>, } #[derive(Clone, Debug, CandidType, Deserialize)] @@ -129,6 +130,7 @@ impl State { content_type: arg.content_type, encodings: HashMap::new(), max_age: arg.max_age, + headers: arg.headers, }, ); } @@ -788,6 +790,11 @@ fn build_ok( if let Some(max_age) = asset.max_age { headers.push(("Cache-Control".to_string(), format!("max-age={}", max_age))); } + if let Some(arg_headers) = asset.headers.as_ref() { + for (k, v) in arg_headers { + headers.push((k.to_owned(), v.to_owned())); + } + } let streaming_strategy = create_token(asset, enc_name, enc, key, chunk_index) .map(|token| StreamingStrategy::Callback { callback, token }); diff --git a/src/ic-certified-assets/src/tests.rs b/src/ic-certified-assets/src/tests.rs index 6e897df57..c86f533d4 100644 --- a/src/ic-certified-assets/src/tests.rs +++ b/src/ic-certified-assets/src/tests.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use crate::state_machine::{StableState, State, BATCH_EXPIRY_NANOS}; use crate::types::{ BatchId, BatchOperation, CommitBatchArguments, CreateAssetArguments, CreateChunkArg, @@ -24,6 +26,7 @@ struct AssetBuilder { content_type: String, max_age: Option, encodings: Vec<(String, Vec)>, + headers: Option>, } impl AssetBuilder { @@ -33,6 +36,7 @@ impl AssetBuilder { content_type: content_type.as_ref().to_string(), max_age: None, encodings: vec![], + headers: None, } } @@ -51,6 +55,12 @@ impl AssetBuilder { )); self } + + fn with_header(mut self, header_key: &str, header_value: &str) -> Self { + let hm = self.headers.get_or_insert(HashMap::new()); + hm.insert(header_key.to_string(), header_value.to_string()); + self + } } struct RequestBuilder { @@ -96,6 +106,7 @@ fn create_assets(state: &mut State, time_now: u64, assets: Vec) -> key: asset.name.clone(), content_type: asset.content_type, max_age: asset.max_age, + headers: asset.headers, })); for (enc, chunks) in asset.encodings { @@ -525,3 +536,73 @@ fn check_url_decode() { ); assert_eq!(url_decode("/%e6"), Ok("/æ".to_string())); } + +#[test] +fn supports_custom_http_headers() { + let mut state = State::default(); + let time_now = 100_000_000_000; + + const BODY: &[u8] = b""; + + create_assets( + &mut state, + time_now, + vec![ + AssetBuilder::new("/contents.html", "text/html") + .with_encoding("identity", vec![BODY]) + .with_header("Access-Control-Allow-Origin", "*"), + AssetBuilder::new("/max-age.html", "text/html") + .with_max_age(604800) + .with_encoding("identity", vec![BODY]) + .with_header("X-Content-Type-Options", "nosniff"), + ], + ); + + let response = state.http_request( + RequestBuilder::get("/contents.html") + .with_header("Accept-Encoding", "gzip,identity") + .build(), + &[], + unused_callback(), + ); + + assert_eq!(response.status_code, 200); + assert_eq!(response.body.as_ref(), BODY); + assert!( + lookup_header(&response, "Access-Control-Allow-Origin").is_some(), + "Missing Access-Control-Allow-Origin header in response: {:#?}", + response, + ); + assert!( + lookup_header(&response, "Access-Control-Allow-Origin") == Some("*"), + "Incorrect value for Access-Control-Allow-Origin header in response: {:#?}", + response, + ); + + let response = state.http_request( + RequestBuilder::get("/max-age.html") + .with_header("Accept-Encoding", "gzip,identity") + .build(), + &[], + unused_callback(), + ); + + assert_eq!(response.status_code, 200); + assert_eq!(response.body.as_ref(), BODY); + assert_eq!( + lookup_header(&response, "Cache-Control"), + Some("max-age=604800"), + "No matching Cache-Control header in response: {:#?}", + response, + ); + assert!( + lookup_header(&response, "X-Content-Type-Options").is_some(), + "Missing X-Content-Type-Options header in response: {:#?}", + response, + ); + assert!( + lookup_header(&response, "X-Content-Type-Options") == Some("nosniff"), + "Incorrect value for X-Content-Type-Options header in response: {:#?}", + response, + ); +} diff --git a/src/ic-certified-assets/src/types.rs b/src/ic-certified-assets/src/types.rs index 06628b61d..d62cf803c 100644 --- a/src/ic-certified-assets/src/types.rs +++ b/src/ic-certified-assets/src/types.rs @@ -1,5 +1,7 @@ //! This module defines types shared by the certified assets state machine and the canister //! endpoints. +use std::collections::HashMap; + use crate::rc_bytes::RcBytes; use candid::{CandidType, Deserialize, Func, Nat}; use serde_bytes::ByteBuf; @@ -15,6 +17,7 @@ pub struct CreateAssetArguments { pub key: Key, pub content_type: String, pub max_age: Option, + pub headers: Option>, } #[derive(Clone, Debug, CandidType, Deserialize)] From 39688bd8151c714436462ad9da457fd99f9a2082 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Sun, 10 Jul 2022 00:24:43 +0200 Subject: [PATCH 073/234] refactor: move performance_counter to ic_cdk::api module (#283) This change attempts to make performance_counter API a bit easier to find and use: 1. Move `performance_counter` from `ic_cdk::api::call` to `ic_cdk::api` because the counter has nothing to do with making calls. 2. Introduce an alias for `performance_counter(0)`, `instruction_counter()`. It's much better on the eye and doesn't force the code reader to learn about valid inputs for `performance_counter`. --- e2e-tests/canisters/api_call.rs | 2 +- src/ic-cdk/CHANGELOG.md | 4 ++++ src/ic-cdk/src/api.rs | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/e2e-tests/canisters/api_call.rs b/e2e-tests/canisters/api_call.rs index 73a3fbf9e..8267c7c45 100644 --- a/e2e-tests/canisters/api_call.rs +++ b/e2e-tests/canisters/api_call.rs @@ -2,7 +2,7 @@ use ic_cdk_macros::query; #[query] fn instruction_counter() -> u64 { - ic_cdk::api::call::performance_counter(0) + ic_cdk::api::instruction_counter() } fn main() {} diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index ad0cc74b3..eb044cced 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,8 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Added +- `instruction_counter` function as a shorthand for `performance_counter(0)`. + ### Changed - Make `CanisterStableMemory` public (#281) +- BREAKING CHANGE: move performance_counter from the `ic_cdk::api::call` to `ic_cdk::api` module. ## [0.5.2] - 2022-06-23 ### Added diff --git a/src/ic-cdk/src/api.rs b/src/ic-cdk/src/api.rs index 5867fdc1e..96773e5e5 100644 --- a/src/ic-cdk/src/api.rs +++ b/src/ic-cdk/src/api.rs @@ -98,3 +98,19 @@ pub fn data_certificate() -> Option> { } Some(buf) } + +/// Returns the number of instructions that the canister executed since the last [entry +/// point](https://internetcomputer.org/docs/current/references/ic-interface-spec/#entry-points). +#[inline] +pub fn instruction_counter() -> u64 { + performance_counter(0) +} + +/// Get the value of specified performance counter. +/// +/// Supported counter type: +/// 0 : instruction counter. The number of WebAssembly instructions the system has determined that the canister has executed. +#[inline] +pub fn performance_counter(counter_type: u32) -> u64 { + unsafe { ic0::performance_counter(counter_type as i32) as u64 } +} From 230c7349362c3c6135a1980d37ca4042ff84724b Mon Sep 17 00:00:00 2001 From: Marcin Nowak-Liebiediew Date: Tue, 12 Jul 2022 13:33:07 +0200 Subject: [PATCH 074/234] fix: candid spec to support setting multiple custom HTTP headers on asset creation (#284) --- src/ic-certified-assets/CHANGELOG.md | 4 ++++ src/ic-certified-assets/Cargo.toml | 2 +- src/ic-certified-assets/assets.did | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ic-certified-assets/CHANGELOG.md b/src/ic-certified-assets/CHANGELOG.md index d8e93749c..542c06eae 100644 --- a/src/ic-certified-assets/CHANGELOG.md +++ b/src/ic-certified-assets/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.4] - 2022-07-12 +### Fixed +- headers field in Candid spec accepts mmultiple HTTP headers + ## [0.2.3] - 2022-07-06 ### Added - Support for setting custom HTTP headers on asset creation diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml index c146a2681..aa47a4379 100644 --- a/src/ic-certified-assets/Cargo.toml +++ b/src/ic-certified-assets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-certified-assets" -version = "0.2.3" +version = "0.2.4" edition = "2021" authors = ["DFINITY Stiftung "] description = "Rust support for asset certification." diff --git a/src/ic-certified-assets/assets.did b/src/ic-certified-assets/assets.did index deaa63fce..791de3751 100644 --- a/src/ic-certified-assets/assets.did +++ b/src/ic-certified-assets/assets.did @@ -7,7 +7,7 @@ type CreateAssetArguments = record { key: Key; content_type: text; max_age: opt nat64; - headers: opt HeaderField; + headers: opt vec HeaderField; }; // Add or change content for an asset, by content encoding From 39cd49a3b2ca6736d7c3d3bf3605e567302825b7 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 15 Jul 2022 12:51:53 -0400 Subject: [PATCH 075/234] chore: Upgrade candid to v0.7.15 (#285) * chore: Upgrade candid to v0.7.15 bundled with ic-types v0.4.0 * update ic-state-machine-tests --- README.md | 2 +- e2e-tests/Cargo.toml | 2 +- examples/chess/src/chess_rs/Cargo.toml | 2 +- examples/counter/src/counter_rs/Cargo.toml | 2 +- examples/counter/src/inter2_rs/Cargo.toml | 2 +- examples/counter/src/inter_rs/Cargo.toml | 2 +- examples/profile/src/profile_inter_rs/Cargo.toml | 2 +- examples/profile/src/profile_rs/Cargo.toml | 2 +- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/Cargo.toml | 2 +- src/ic-certified-assets/Cargo.toml | 3 +-- src/ic-ledger-types/Cargo.toml | 2 +- 12 files changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8a53310f4..751d2d5e1 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ In Cargo.toml: crate-type = ["cdylib"] [dependencies] -candid = "0.7.4" # this is required if you want to use the `#[import]` macro +candid = "0.7.15" # this is required if you want to use the `#[import]` macro ic-cdk = "0.5" ic-cdk-macros = "0.5" ``` diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index e6b85ebab..f8332f79b 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -33,4 +33,4 @@ name = "api-call" path = "canisters/api_call.rs" [dev-dependencies] -ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "92e6b0ed36cdc9322a3588f46a8c8c7cc567e143" } +ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "02a4a828f2f4d3b1dcb93a84e60672a3f3fdb400" } diff --git a/examples/chess/src/chess_rs/Cargo.toml b/examples/chess/src/chess_rs/Cargo.toml index de551e63c..3a9a69be1 100644 --- a/examples/chess/src/chess_rs/Cargo.toml +++ b/examples/chess/src/chess_rs/Cargo.toml @@ -11,7 +11,7 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.7.4" +candid = "0.7.15" ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } serde = "1.0.111" diff --git a/examples/counter/src/counter_rs/Cargo.toml b/examples/counter/src/counter_rs/Cargo.toml index 4b839dd03..c88c4ac66 100644 --- a/examples/counter/src/counter_rs/Cargo.toml +++ b/examples/counter/src/counter_rs/Cargo.toml @@ -11,7 +11,7 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.7.4" +candid = "0.7.15" ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } lazy_static = "1.4.0" diff --git a/examples/counter/src/inter2_rs/Cargo.toml b/examples/counter/src/inter2_rs/Cargo.toml index 36173aaa9..d6bcf142a 100644 --- a/examples/counter/src/inter2_rs/Cargo.toml +++ b/examples/counter/src/inter2_rs/Cargo.toml @@ -11,6 +11,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.7.4" +candid = "0.7.15" ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } diff --git a/examples/counter/src/inter_rs/Cargo.toml b/examples/counter/src/inter_rs/Cargo.toml index 10277b1f7..e80f06ee0 100644 --- a/examples/counter/src/inter_rs/Cargo.toml +++ b/examples/counter/src/inter_rs/Cargo.toml @@ -11,6 +11,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.7.4" +candid = "0.7.15" ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } diff --git a/examples/profile/src/profile_inter_rs/Cargo.toml b/examples/profile/src/profile_inter_rs/Cargo.toml index 0142d06da..0b5b54c28 100644 --- a/examples/profile/src/profile_inter_rs/Cargo.toml +++ b/examples/profile/src/profile_inter_rs/Cargo.toml @@ -11,6 +11,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.7.4" +candid = "0.7.15" ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } diff --git a/examples/profile/src/profile_rs/Cargo.toml b/examples/profile/src/profile_rs/Cargo.toml index f867a3fd7..62753b197 100644 --- a/examples/profile/src/profile_rs/Cargo.toml +++ b/examples/profile/src/profile_rs/Cargo.toml @@ -11,7 +11,7 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.7.4" +candid = "0.7.15" ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } serde = "1.0.111" diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index b7b4a6e37..28a9ab2a0 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -18,7 +18,7 @@ rust-version = "1.60.0" proc-macro = true [dependencies] -candid = "0.7.4" +candid = "0.7.15" ic-cdk = { path = "../ic-cdk", version = "0.5" } syn = { version = "1.0.58", features = ["fold", "full"] } quote = "1.0" diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 9f951dc35..609a5b1e7 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -15,7 +15,7 @@ repository = "https://github.com/dfinity/cdk-rs" rust-version = "1.60.0" [dependencies] -candid = "0.7.4" +candid = "0.7.15" cfg-if = "1.0.0" serde = "1.0.110" diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml index aa47a4379..149c687e0 100644 --- a/src/ic-certified-assets/Cargo.toml +++ b/src/ic-certified-assets/Cargo.toml @@ -12,11 +12,10 @@ rust-version = "1.60.0" [dependencies] base64 = "0.13" -candid = "0.7.10" +candid = "0.7.15" hex = "0.4.3" ic-cdk = { path = "../ic-cdk", version = "0.5" } ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.5" } -ic-types = "0.3.0" ic-certified-map = { path = "../ic-certified-map", version = "0.3" } num-traits = "0.2.14" serde = "1" diff --git a/src/ic-ledger-types/Cargo.toml b/src/ic-ledger-types/Cargo.toml index 15d07d83c..efd107fc1 100644 --- a/src/ic-ledger-types/Cargo.toml +++ b/src/ic-ledger-types/Cargo.toml @@ -18,7 +18,7 @@ rust-version = "1.60.0" [dependencies] ic-cdk = { path = "../ic-cdk", version = "0.5" } -candid = "0.7.4" +candid = "0.7.15" crc32fast = "1.2.0" hex = "0.4" serde = "1" From c7b00d6f4322096712c69647d13d7c3b325b4791 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Mon, 18 Jul 2022 08:42:07 +0200 Subject: [PATCH 076/234] fix(doc): update comments for ManualReply (#286) * doc: fix comments for ManualReply This change fixes the commentary for ManualReply that mentioned non-existing `#[query(reply = false)]` syntax. The correct syntax is `#[query(manual_reply = true)]`. * update changelog --- src/ic-cdk/CHANGELOG.md | 7 +++++-- src/ic-cdk/src/api/call.rs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index eb044cced..4836bbc6e 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -7,11 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] ### Added -- `instruction_counter` function as a shorthand for `performance_counter(0)`. +- `instruction_counter` function as a shorthand for `performance_counter(0)` (#283). ### Changed - Make `CanisterStableMemory` public (#281) -- BREAKING CHANGE: move performance_counter from the `ic_cdk::api::call` to `ic_cdk::api` module. +- BREAKING CHANGE: move performance_counter from the `ic_cdk::api::call` to `ic_cdk::api` module (#283). + +### Fixed +- Outdated documentation for `ManualReply` (#286). ## [0.5.2] - 2022-06-23 ### Added diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index df5dc3ac5..d02d3df01 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -618,7 +618,7 @@ pub fn performance_counter(counter_type: u32) -> u64 { /// Pretends to have the Candid type `T`, but unconditionally errors /// when serialized. /// -/// Usable, but not required, as metadata when using `#[query(reply = false)]`, +/// Usable, but not required, as metadata when using `#[query(manual_reply = true)]`, /// so an accurate Candid file can still be generated. #[derive(Debug, Copy, Clone, Default)] pub struct ManualReply(PhantomData); From 00c7e73e13dcb881db7e45712d1ce3b77b774d4b Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 19 Jul 2022 12:57:24 -0400 Subject: [PATCH 077/234] chore: release icd-cdk v0.5.3 (#288) --- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 4 +++- src/ic-cdk/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 28a9ab2a0..2981d396a 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.5.2" +version = "0.5.3" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 4836bbc6e..4d38b3392 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.5.3] - 2022-07-19 + ### Added - `instruction_counter` function as a shorthand for `performance_counter(0)` (#283). @@ -16,7 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Outdated documentation for `ManualReply` (#286). -## [0.5.2] - 2022-06-23 +## [0.5.2] - 2022-06-23 ### Added - `arg_data_raw_size` for checking the size of the arg-data-raw before copying to a vector or deserializing (#263) - `performance_counter` for getting the value of specified performance counter (#277) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 609a5b1e7..f3e74a504 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.5.2" +version = "0.5.3" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." From 9f0a14e44dd685e6a98ebcf2b708c0890f9c5830 Mon Sep 17 00:00:00 2001 From: tim-dfn <97036153+tim-dfn@users.noreply.github.com> Date: Fri, 22 Jul 2022 17:03:10 +0200 Subject: [PATCH 078/234] derive CandidType for RejectionCode (#291) --- src/ic-cdk/src/api/call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index d02d3df01..ee3becb78 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -130,7 +130,7 @@ use rc::{InnerCell, WasmCell}; /// These can be obtained either using `reject_code()` or `reject_result()`. #[allow(missing_docs)] #[repr(i32)] -#[derive(Debug, Clone, Copy)] +#[derive(Debug, CandidType, Clone, Copy)] pub enum RejectionCode { NoError = 0, From 8a0bd0acc936dc39b8a5714b3a3c1e1ae201fc7f Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 22 Jul 2022 12:31:31 -0400 Subject: [PATCH 079/234] chore: release ic-cdk v0.5.4 (#292) --- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 11 ++++++++--- src/ic-cdk/Cargo.toml | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 2981d396a..b94c42ad1 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.5.3" +version = "0.5.4" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 4d38b3392..223de5351 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,17 +6,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.5.4] - 2022-07-22 + +### Added +- Derive `CandidType` for `RejectionCode` (#291) + ## [0.5.3] - 2022-07-19 ### Added -- `instruction_counter` function as a shorthand for `performance_counter(0)` (#283). +- `instruction_counter` function as a shorthand for `performance_counter(0)` (#283) ### Changed - Make `CanisterStableMemory` public (#281) -- BREAKING CHANGE: move performance_counter from the `ic_cdk::api::call` to `ic_cdk::api` module (#283). +- BREAKING CHANGE: move performance_counter from the `ic_cdk::api::call` to `ic_cdk::api` module (#283) ### Fixed -- Outdated documentation for `ManualReply` (#286). +- Outdated documentation for `ManualReply` (#286) ## [0.5.2] - 2022-06-23 ### Added diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index f3e74a504..f588c8ab0 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.5.3" +version = "0.5.4" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." From b7e3aba741e2c21110a996e1cea4787c542edf8c Mon Sep 17 00:00:00 2001 From: tim-dfn <97036153+tim-dfn@users.noreply.github.com> Date: Fri, 22 Jul 2022 19:10:41 +0200 Subject: [PATCH 080/234] feat: Derive Deserialize for RejectionCode (#293) * derive CandidType for RejectionCode * fix * bump up version Co-authored-by: Linwei Shang --- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 4 ++-- src/ic-cdk/Cargo.toml | 2 +- src/ic-cdk/src/api/call.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index b94c42ad1..00d05aa32 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.5.4" +version = "0.5.5" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 223de5351..41718a377 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,10 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -## [0.5.4] - 2022-07-22 +## [0.5.5] - 2022-07-22 ### Added -- Derive `CandidType` for `RejectionCode` (#291) +- Derive `CandidType` and `Deserialize` for `RejectionCode` (#291, #293) ## [0.5.3] - 2022-07-19 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index f588c8ab0..27192fade 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.5.4" +version = "0.5.5" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index ee3becb78..89ce29b77 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -2,7 +2,7 @@ use crate::api::{ic0, trap}; use crate::export::Principal; use candid::utils::{ArgumentDecoder, ArgumentEncoder}; -use candid::{decode_args, encode_args, write_args, CandidType}; +use candid::{decode_args, encode_args, write_args, CandidType, Deserialize}; use serde::ser::Error; use std::future::Future; use std::marker::PhantomData; @@ -130,7 +130,7 @@ use rc::{InnerCell, WasmCell}; /// These can be obtained either using `reject_code()` or `reject_result()`. #[allow(missing_docs)] #[repr(i32)] -#[derive(Debug, CandidType, Clone, Copy)] +#[derive(Debug, CandidType, Deserialize, Clone, Copy)] pub enum RejectionCode { NoError = 0, From b1408f81cb28b7b47009ba60e005ee10a39c7476 Mon Sep 17 00:00:00 2001 From: tim-dfn <97036153+tim-dfn@users.noreply.github.com> Date: Tue, 26 Jul 2022 18:03:21 +0200 Subject: [PATCH 081/234] feat: Implement common traits for RejectionCode (#294) * implement common types * remove serialize * changelog Co-authored-by: Linwei Shang --- src/ic-cdk/CHANGELOG.md | 3 +++ src/ic-cdk/src/api/call.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 41718a377..faaa7cd09 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Added +- Derive common traits for `RejectionCode` (#294) + ## [0.5.5] - 2022-07-22 ### Added diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 89ce29b77..888639898 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -130,7 +130,7 @@ use rc::{InnerCell, WasmCell}; /// These can be obtained either using `reject_code()` or `reject_result()`. #[allow(missing_docs)] #[repr(i32)] -#[derive(Debug, CandidType, Deserialize, Clone, Copy)] +#[derive(CandidType, Deserialize, Clone, Copy, Hash, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum RejectionCode { NoError = 0, From f5a8fb569b25499ec56e0b7b0fdf7b2671084f07 Mon Sep 17 00:00:00 2001 From: Nicolas Mattia Date: Tue, 2 Aug 2022 12:16:08 +0200 Subject: [PATCH 082/234] Update call.rs (#296) --- src/ic-cdk/src/api/call.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 888639898..1ab9fd980 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -580,7 +580,8 @@ pub fn reply_raw(buf: &[u8]) { } } -/// Returns the argument data in the current call. +/// Returns the argument data in the current call. Traps if the data cannot be +/// decoded. pub fn arg_data ArgumentDecoder<'a>>() -> R { let bytes = arg_data_raw(); From 07a3b551364f9221d9bc77b28d69c6b1297ede77 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Thu, 4 Aug 2022 18:24:56 +0200 Subject: [PATCH 083/234] feat: ManualReply::reject API (#297) * feat: ManualReply::reject API I :heart: ManualReply interface because it gives so much flexibility. The type misses on short cut: reject and produce a manual reply object. This change adds the missing shortcut. * add PR number to the changelog --- e2e-tests/canisters/api_call.rs | 6 ++++++ e2e-tests/tests/e2e.rs | 6 ++++++ src/ic-cdk/CHANGELOG.md | 1 + src/ic-cdk/src/api/call.rs | 7 +++++++ 4 files changed, 20 insertions(+) diff --git a/e2e-tests/canisters/api_call.rs b/e2e-tests/canisters/api_call.rs index 8267c7c45..bff8b6fe6 100644 --- a/e2e-tests/canisters/api_call.rs +++ b/e2e-tests/canisters/api_call.rs @@ -1,3 +1,4 @@ +use ic_cdk::api::call::ManualReply; use ic_cdk_macros::query; #[query] @@ -5,4 +6,9 @@ fn instruction_counter() -> u64 { ic_cdk::api::instruction_counter() } +#[query(manual_reply = true)] +fn manual_reject() -> ManualReply { + ManualReply::reject("manual reject") +} + fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index da5eb4745..36021798c 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -1,4 +1,5 @@ use candid::utils::{decode_args, encode_args, ArgumentDecoder, ArgumentEncoder}; +use candid::Encode; use ic_cdk_e2e_tests::cargo_build_canister; use ic_state_machine_tests::{CanisterId, ErrorCode, StateMachine, UserError, WasmResult}; use serde_bytes::ByteBuf; @@ -166,4 +167,9 @@ fn test_api_call() { let (result,): (u64,) = query_candid(&env, canister_id, "instruction_counter", ()) .expect("failed to query instruction_counter"); assert!(result > 0); + + let result = env + .query(canister_id, "manual_reject", Encode!().unwrap()) + .unwrap(); + assert_eq!(result, WasmResult::Reject("manual reject".to_string())); } diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index faaa7cd09..e9e6ac846 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Derive common traits for `RejectionCode` (#294) +- `ManualReply::reject` function (#297) ## [0.5.5] - 2022-07-22 diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 1ab9fd980..904d4be9d 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -648,6 +648,13 @@ impl ManualReply { reply((value,)); Self::empty() } + + /// Rejects the call with the specified message and returns a new + /// `ManualReply`, for a useful reply-then-return shortcut. + pub fn reject(message: impl AsRef) -> Self { + reject(message.as_ref()); + Self::empty() + } } impl CandidType for ManualReply From 826493e23ce4728f8524376754c6f0fcb1fc1617 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Sat, 6 Aug 2022 10:40:23 -0400 Subject: [PATCH 084/234] feat: methods and types for management canister (#295) * New crate ic-management * tuple * raw_rand * assert * create_canister * separate test files * update_settings * install_code (just begin) * minimal wasm * cleanup * more methods * canister_status * more * http_request (Not tested yet) * ignore test * bitcoin * remove http_request test, restructure * threshold_ecdsa * reply * provisional * provisional * restructure * e2e provisional * try e2e threshold_ecdsa * mod * mv * fix * remove crate * remove crate * fix * Fix http types * pay for create_canister * Pay for http_request * deposit cycles * rename HttpResponse * vis * remove impossible tests * Fix bitcoin * management canister example test * rm management canister e2e test * Revert change of e2e * revert * rm * fix * try fix * try * try again * dfx 0.11.1 * fix * doc main * doc main types * doc provisional * doc http_request * fmt * doc ecdsa * rename ecdsa * Response * doc bitcoin * fix test * changelog * rename_all * derive traits as many as possible * patch all examples * fix --- .github/workflows/examples.yml | 18 +- Cargo.toml | 5 +- examples/asset_storage/Cargo.toml | 3 + examples/asset_storage/tests/basic.bats | 6 +- examples/chess/Cargo.toml | 3 + examples/counter/Cargo.toml | 3 + examples/management_canister/Cargo.toml | 7 + examples/management_canister/dfx.json | 19 ++ .../management_canister/src/caller/Cargo.toml | 15 ++ .../management_canister/src/caller/caller.did | 7 + .../management_canister/src/caller/lib.rs | 197 ++++++++++++++++++ examples/management_canister/src/main.rs | 3 + examples/management_canister/tests/basic.bats | 26 +++ examples/print/Cargo.toml | 3 + examples/profile/Cargo.toml | 3 + src/ic-cdk/CHANGELOG.md | 1 + src/ic-cdk/src/api.rs | 1 + .../api/management_canister/bitcoin/mod.rs | 63 ++++++ .../api/management_canister/bitcoin/types.rs | 151 ++++++++++++++ .../src/api/management_canister/ecdsa/mod.rs | 23 ++ .../api/management_canister/ecdsa/types.rs | 77 +++++++ .../api/management_canister/http_request.rs | 127 +++++++++++ .../src/api/management_canister/main/mod.rs | 100 +++++++++ .../src/api/management_canister/main/types.rs | 131 ++++++++++++ src/ic-cdk/src/api/management_canister/mod.rs | 17 ++ .../api/management_canister/provisional.rs | 59 ++++++ 26 files changed, 1063 insertions(+), 5 deletions(-) create mode 100644 examples/management_canister/Cargo.toml create mode 100644 examples/management_canister/dfx.json create mode 100644 examples/management_canister/src/caller/Cargo.toml create mode 100644 examples/management_canister/src/caller/caller.did create mode 100644 examples/management_canister/src/caller/lib.rs create mode 100644 examples/management_canister/src/main.rs create mode 100644 examples/management_canister/tests/basic.bats create mode 100644 src/ic-cdk/src/api/management_canister/bitcoin/mod.rs create mode 100644 src/ic-cdk/src/api/management_canister/bitcoin/types.rs create mode 100644 src/ic-cdk/src/api/management_canister/ecdsa/mod.rs create mode 100644 src/ic-cdk/src/api/management_canister/ecdsa/types.rs create mode 100644 src/ic-cdk/src/api/management_canister/http_request.rs create mode 100644 src/ic-cdk/src/api/management_canister/main/mod.rs create mode 100644 src/ic-cdk/src/api/management_canister/main/types.rs create mode 100644 src/ic-cdk/src/api/management_canister/mod.rs create mode 100644 src/ic-cdk/src/api/management_canister/provisional.rs diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index c9d5b3aec..2c93b21d3 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -17,7 +17,7 @@ jobs: - build: linux-stable os: ubuntu-latest rust: 1.60.0 - dfx: 0.9.3 + dfx: 0.11.1 steps: - uses: actions/checkout@v2 @@ -47,10 +47,26 @@ jobs: with: bats-version: 1.2.1 + - name: Install bitcoin + run: | + CWD=$(pwd) + cd "$(mktemp -d)" + BITCOIN_CORE_VERSION=22.0 + BITCOIN_CORE_FILENAME="bitcoin-$BITCOIN_CORE_VERSION-x86_64-linux-gnu.tar.gz" + BITCOIN_CORE_TARBALL_SHA="59ebd25dd82a51638b7a6bb914586201e67db67b919b2a1ff08925a7936d1b16" + wget -nv "https://bitcoin.org/bin/bitcoin-core-$BITCOIN_CORE_VERSION/$BITCOIN_CORE_FILENAME" + echo "$BITCOIN_CORE_TARBALL_SHA $BITCOIN_CORE_FILENAME" | shasum -c + tar xzf "$BITCOIN_CORE_FILENAME" + cd "bitcoin-$BITCOIN_CORE_VERSION/bin" + sudo install -m 0755 -o root -g root -t /usr/local/bin * + cd "$CWD" + - name: Run Tests shell: bash run: | echo CWD: $(pwd) + echo bitcoind: $(which bitcoind) + echo bitcoin-cli: $(which bitcoin-cli) export PATH=$PATH:$HOME/bin bats -r examples env: diff --git a/Cargo.toml b/Cargo.toml index e506fb2eb..affc98df1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,7 @@ inherits = "release" debug = false panic = "abort" lto = true -opt-level = 'z' \ No newline at end of file +opt-level = 'z' + +[patch.crates-io] +candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/examples/asset_storage/Cargo.toml b/examples/asset_storage/Cargo.toml index 995b8a2fa..e0cdcae57 100644 --- a/examples/asset_storage/Cargo.toml +++ b/examples/asset_storage/Cargo.toml @@ -6,3 +6,6 @@ members = [ [profile.release] lto = true opt-level = 'z' + +[patch.crates-io] +candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/examples/asset_storage/tests/basic.bats b/examples/asset_storage/tests/basic.bats index c00a6e9f1..08df3a0bd 100644 --- a/examples/asset_storage/tests/basic.bats +++ b/examples/asset_storage/tests/basic.bats @@ -7,9 +7,9 @@ setup() { cp dfx.json dfx.json.bk cat <<<$(jq .networks.local.bind=\"127.0.0.1:${webserver_port}\" dfx.json) >dfx.json - run dfx identity new alice - run dfx identity new bob - run dfx identity new charlie + run dfx identity new alice --disable-encryption + run dfx identity new bob --disable-encryption + run dfx identity new charlie --disable-encryption } # executed after each test diff --git a/examples/chess/Cargo.toml b/examples/chess/Cargo.toml index e97684672..6c8c7c4f1 100644 --- a/examples/chess/Cargo.toml +++ b/examples/chess/Cargo.toml @@ -6,3 +6,6 @@ members = [ [profile.release] lto = true opt-level = 'z' + +[patch.crates-io] +candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/examples/counter/Cargo.toml b/examples/counter/Cargo.toml index 12ee45194..e36f4a63d 100644 --- a/examples/counter/Cargo.toml +++ b/examples/counter/Cargo.toml @@ -4,3 +4,6 @@ members = [ "src/inter_rs", "src/inter2_rs", ] + +[patch.crates-io] +candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/examples/management_canister/Cargo.toml b/examples/management_canister/Cargo.toml new file mode 100644 index 000000000..7cdc69ed7 --- /dev/null +++ b/examples/management_canister/Cargo.toml @@ -0,0 +1,7 @@ +[workspace] +members = [ + "src/caller", +] + +[patch.crates-io] +candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/examples/management_canister/dfx.json b/examples/management_canister/dfx.json new file mode 100644 index 000000000..bdcaab5f6 --- /dev/null +++ b/examples/management_canister/dfx.json @@ -0,0 +1,19 @@ +{ + "version": 1, + "canisters": { + "caller": { + "type": "custom", + "candid": "src/caller/caller.did", + "wasm": "target/wasm32-unknown-unknown/release/caller-opt.wasm", + "build": "sh ../build.sh management_canister caller" + } + }, + "defaults": { + "canister_http": { + "enabled": true + }, + "bitcoin": { + "enabled": true + } + } +} \ No newline at end of file diff --git a/examples/management_canister/src/caller/Cargo.toml b/examples/management_canister/src/caller/Cargo.toml new file mode 100644 index 000000000..89a08e6f5 --- /dev/null +++ b/examples/management_canister/src/caller/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "caller" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +path = "lib.rs" +crate-type = ["cdylib"] + +[dependencies] +ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } +sha2 = "0.10" diff --git a/examples/management_canister/src/caller/caller.did b/examples/management_canister/src/caller/caller.did new file mode 100644 index 000000000..5a0431007 --- /dev/null +++ b/examples/management_canister/src/caller/caller.did @@ -0,0 +1,7 @@ +service : { + "execute_main_methods" : () -> (); + "execute_provisional_methods" : () -> (); + "http_request_example" : () -> (); + "execute_ecdsa_methods" : () -> (); + "execute_bitcoin_methods" : () -> (); +} \ No newline at end of file diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs new file mode 100644 index 000000000..049c481d3 --- /dev/null +++ b/examples/management_canister/src/caller/lib.rs @@ -0,0 +1,197 @@ +use ic_cdk_macros::*; + +mod main { + use super::*; + use ic_cdk::api::management_canister::main::*; + #[update] + async fn execute_main_methods() { + let arg = CreateCanisterArgument { + settings: Some(CanisterSettings { + controllers: Some(vec![ic_cdk::caller()]), + compute_allocation: Some(50.into()), + memory_allocation: Some(10000.into()), + freezing_threshold: Some(10000.into()), + }), + }; + let canister_id = create_canister(arg).await.unwrap().0.canister_id; + + let arg = UpdateSettingsArgument { + canister_id, + settings: CanisterSettings::default(), + }; + update_settings(arg).await.unwrap(); + + let arg = InstallCodeArgument { + mode: CanisterInstallMode::Install, + canister_id, + // A minimal valid wasm module + // wat2wasm "(module)" + wasm_module: b"\x00asm\x01\x00\x00\x00".to_vec(), + arg: vec![], + }; + install_code(arg).await.unwrap(); + let arg = CanisterIdRecord { canister_id }; + uninstall_code(arg).await.unwrap(); + start_canister(arg).await.unwrap(); + stop_canister(arg).await.unwrap(); + let response = canister_status(arg).await.unwrap().0; + assert_eq!(response.status, CanisterStatusType::Stopped); + deposit_cycles(arg, 1_000_000_000_000u128).await.unwrap(); + delete_canister(arg).await.unwrap(); + let response = raw_rand().await.unwrap().0; + assert_eq!(response.len(), 32); + } +} + +mod provisional { + use super::*; + use ic_cdk::api::management_canister::provisional::*; + + #[update] + async fn execute_provisional_methods() { + let settings = CanisterSettings { + controllers: Some(vec![ic_cdk::caller()]), + compute_allocation: Some(50.into()), + memory_allocation: Some(10000.into()), + freezing_threshold: Some(10000.into()), + }; + let arg = ProvisionalCreateCanisterWithCyclesArgument { + amount: Some(1_000_000_000.into()), + settings: Some(settings), + }; + let canister_id = provisional_create_canister_with_cycles(arg) + .await + .unwrap() + .0 + .canister_id; + + let arg = ProvisionalTopUpCanisterArgument { + canister_id, + amount: 1_000_000_000.into(), + }; + provisional_top_up_canister(arg).await.unwrap(); + } +} + +mod http_request { + use super::*; + use ic_cdk::api::management_canister::http_request::*; + + #[update] + async fn http_request_example() { + let url = "https://example.com".to_string(); + let arg = CanisterHttpRequestArgument { + url, + max_response_bytes: Some(3000), + http_method: HttpMethod::GET, + headers: vec![], + body: None, + transform_method_name: Some("transform".to_string()), + }; + let response = http_request(arg).await.unwrap().0; + assert_eq!(response.status, 200); + assert_eq!( + response.headers.get(0), + Some(&HttpHeader { + name: "custom-header".to_string(), + value: "test".to_string(), + }) + ); + } + + // transform function must be a *query* method of the canister + #[query] + async fn transform(arg: HttpResponse) -> HttpResponse { + HttpResponse { + headers: vec![HttpHeader { + name: "custom-header".to_string(), + value: "test".to_string(), + }], + ..arg + } + } +} + +mod ecdsa { + use super::*; + use ic_cdk::api::management_canister::ecdsa::*; + use sha2::Digest; + + #[update] + async fn execute_ecdsa_methods() { + let key_id = EcdsaKeyId { + curve: EcdsaCurve::Secp256k1, + name: "dfx_test_key".to_string(), + }; + let derivation_path = vec![]; + let arg = EcdsaPublicKeyArgument { + canister_id: None, + derivation_path: derivation_path.clone(), + key_id: key_id.clone(), + }; + let EcdsaPublicKeyResponse { + public_key, + chain_code, + } = ecdsa_public_key(arg).await.unwrap().0; + assert_eq!(public_key.len(), 33); + assert_eq!(chain_code.len(), 32); + + let message = "hello world"; + let message_hash = sha2::Sha256::digest(message).to_vec(); + let arg = SignWithEcdsaArgument { + message_hash, + derivation_path, + key_id, + }; + let SignWithEcdsaResponse { signature } = sign_with_ecdsa(arg).await.unwrap().0; + assert_eq!(signature.len(), 64); + } +} + +mod bitcoin { + use super::*; + use ic_cdk::api::{call::RejectionCode, management_canister::bitcoin::*}; + + #[update] + async fn execute_bitcoin_methods() { + let address = "bcrt1qu58aj62urda83c00eylc6w34yl2s6e5rkzqet7".to_string(); + + let network = BitcoinNetwork::Regtest; + let arg = GetBalanceRequest { + address: address.clone(), + network, + min_confirmations: Some(3), + }; + let _balance = bitcoin_get_balance(arg).await.unwrap().0; + + let arg = GetUtxosRequest { + address: address.clone(), + network, + filter: Some(UtxoFilter::MinConfirmations(6)), + }; + let _response = bitcoin_get_utxos(arg).await.unwrap().0; + + // TODO: turn on following test when new dfx has replica support it. + + // let arg = GetUtxosRequest { + // address: address.clone(), + // network, + // filter: Some(UtxoFilter::Page(vec![])), + // }; + // let _response = bitcoin_get_utxos(arg).await.unwrap().0; + + let arg = GetCurrentFeePercentilesRequest { network }; + let _percentiles = bitcoin_get_current_fee_percentiles(arg).await.unwrap().0; + + let arg = SendTransactionRequest { + transaction: vec![], + network, + }; + let response = bitcoin_send_transaction(arg).await; + assert!(response.is_err()); + if let Err((rejection_code, rejection_reason)) = response { + assert_eq!(rejection_code, RejectionCode::CanisterReject); + assert_eq!(&rejection_reason, "bitcoin_send_transaction failed: Can't deserialize transaction because it's malformed."); + }; + } +} diff --git a/examples/management_canister/src/main.rs b/examples/management_canister/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/examples/management_canister/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/examples/management_canister/tests/basic.bats b/examples/management_canister/tests/basic.bats new file mode 100644 index 000000000..3e47c6642 --- /dev/null +++ b/examples/management_canister/tests/basic.bats @@ -0,0 +1,26 @@ +# Executed before each test. +setup() { + cd examples/management_canister + bitcoind -regtest -daemonwait + # Make sure the directory is clean. + dfx start --clean --background --host "127.0.0.1:0" + local webserver_port=$(cat .dfx/webserver-port) + cp dfx.json dfx.json.bk + cat <<<$(jq .networks.local.bind=\"127.0.0.1:${webserver_port}\" dfx.json) >dfx.json +} + +# executed after each test +teardown() { + dfx stop + bitcoin-cli -regtest stop + mv dfx.json.bk dfx.json +} + +@test "All management canister methods succeed" { + dfx deploy + run dfx canister call caller execute_main_methods + run dfx canister call caller execute_provisional_methods + run dfx canister call caller http_request_example + run dfx canister call caller execute_threshold_ecdsa_methods + run dfx canister call caller execute_bitcoin_methods +} diff --git a/examples/print/Cargo.toml b/examples/print/Cargo.toml index 74a0decf6..16cb6cc60 100644 --- a/examples/print/Cargo.toml +++ b/examples/print/Cargo.toml @@ -2,3 +2,6 @@ members = [ "src/print_rs", ] + +[patch.crates-io] +candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/examples/profile/Cargo.toml b/examples/profile/Cargo.toml index 11917b831..f4e27d526 100644 --- a/examples/profile/Cargo.toml +++ b/examples/profile/Cargo.toml @@ -3,3 +3,6 @@ members = [ "src/profile_rs", "src/profile_inter_rs", ] + +[patch.crates-io] +candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index e9e6ac846..1f62544b1 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] ### Added +- New `ic_cdk::api::management_canister` module for calling the IC management canister (#295) - Derive common traits for `RejectionCode` (#294) - `ManualReply::reject` function (#297) diff --git a/src/ic-cdk/src/api.rs b/src/ic-cdk/src/api.rs index 96773e5e5..eb45edf88 100644 --- a/src/ic-cdk/src/api.rs +++ b/src/ic-cdk/src/api.rs @@ -3,6 +3,7 @@ use crate::export::Principal; use std::convert::TryFrom; pub mod call; +pub mod management_canister; pub mod stable; mod ic0; diff --git a/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs b/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs new file mode 100644 index 000000000..025941220 --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs @@ -0,0 +1,63 @@ +//! The IC Bitcoin API. + +use crate::api::call::{call_with_payment128, CallResult}; +use candid::Principal; + +mod types; +pub use types::*; + +// The fees for the various bitcoin endpoints. +// TODO: where is the public doc of these parameters? +const GET_BALANCE_CYCLES: u128 = 100_000_000; +const GET_UTXOS_CYCLES: u128 = 100_000_000; +const GET_CURRENT_FEE_PERCENTILES_CYCLES: u128 = 100_000_000; +const SEND_TRANSACTION_BASE_CYCLES: u128 = 5_000_000_000; +const SEND_TRANSACTION_PER_BYTE_CYCLES: u128 = 20_000_000; + +/// See [IC method `bitcoin_get_balance`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_balance) +pub async fn bitcoin_get_balance(arg: GetBalanceRequest) -> CallResult<(Satoshi,)> { + call_with_payment128( + Principal::management_canister(), + "bitcoin_get_balance", + (arg,), + GET_BALANCE_CYCLES, + ) + .await +} + +/// See [IC method `bitcoin_get_utxos`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_utxos) +pub async fn bitcoin_get_utxos(arg: GetUtxosRequest) -> CallResult<(GetUtxosResponse,)> { + call_with_payment128( + Principal::management_canister(), + "bitcoin_get_utxos", + (arg,), + GET_UTXOS_CYCLES, + ) + .await +} + +/// See [IC method `bitcoin_send_transaction`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_send_transaction) +pub async fn bitcoin_send_transaction(arg: SendTransactionRequest) -> CallResult<()> { + let cycles = SEND_TRANSACTION_BASE_CYCLES + + (arg.transaction.len() as u128) * SEND_TRANSACTION_PER_BYTE_CYCLES; + call_with_payment128( + Principal::management_canister(), + "bitcoin_send_transaction", + (arg,), + cycles, + ) + .await +} + +/// See [IC method `bitcoin_get_current_fee_percentiles`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_current_fee_percentiles) +pub async fn bitcoin_get_current_fee_percentiles( + arg: GetCurrentFeePercentilesRequest, +) -> CallResult<(Vec,)> { + call_with_payment128( + Principal::management_canister(), + "bitcoin_get_current_fee_percentiles", + (arg,), + GET_CURRENT_FEE_PERCENTILES_CYCLES, + ) + .await +} diff --git a/src/ic-cdk/src/api/management_canister/bitcoin/types.rs b/src/ic-cdk/src/api/management_canister/bitcoin/types.rs new file mode 100644 index 000000000..10b826584 --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/bitcoin/types.rs @@ -0,0 +1,151 @@ +use candid::CandidType; +use serde::{Deserialize, Serialize}; + +/// 10^8 Satoshi = 1 Bitcoin. +pub type Satoshi = u64; + +/// Bitcoin Network. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, +)] +pub enum BitcoinNetwork { + // TODO: The variants are Capitalized while they are lowercase in the spec + /// Mainnet. + Mainnet, + /// Testnet. + Testnet, + // TODO: the spec doesn't have this type of network + /// Regtest. + Regtest, +} + +impl Default for BitcoinNetwork { + fn default() -> Self { + Self::Regtest + } +} + +/// Bitcoin Address. +pub type BitcoinAddress = String; + +/// Block Hash. +pub type BlockHash = Vec; + +/// Element in the Response of [bitcoin_get_current_fee_percentiles](super::bitcoin_get_current_fee_percentiles). +pub type MillisatoshiPerByte = u64; + +/// Identifier of [Utxo]. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct Outpoint { + /// Transaction Identifier. + pub txid: Vec, + /// A implicit index number. + pub vout: u32, +} + +/// Unspent transaction output (UTXO). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct Utxo { + /// See [Outpoint]. + pub outpoint: Outpoint, + /// Value in the units of satoshi. + pub value: Satoshi, + /// Height in the chain. + pub height: u32, +} + +/// Filter for requesting UTXOs. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub enum UtxoFilter { + // TODO: In the spec, variants are in snake case + /// Minimum number of confirmations. There is an upper bound of 144. Typically set to a value around 6 in practice. + MinConfirmations(u32), + /// Page reference. + /// + /// DON'T construct it from scratch. + /// Only get it from the `next_page` field of [GetUtxosResponse]. + Page(Vec), +} + +/// Argument type of [bitcoin_get_balance](super::bitcoin_get_balance). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct GetBalanceRequest { + /// See [BitcoinAddress]. + pub address: BitcoinAddress, + /// See [BitcoinNetwork]. + pub network: BitcoinNetwork, + /// Minimum number of confirmations. There is an upper bound of 144. Typically set to a value around 6 in practice. + pub min_confirmations: Option, +} + +/// Argument type of [bitcoin_get_utxos](super::bitcoin_get_utxos). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct GetUtxosRequest { + /// See [BitcoinAddress]. + pub address: BitcoinAddress, + /// See [BitcoinNetwork]. + pub network: BitcoinNetwork, + /// See [UtxoFilter]. + pub filter: Option, +} + +/// Response type of [bitcoin_get_utxos](super::bitcoin_get_utxos). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct GetUtxosResponse { + /// List of UTXOs. + pub utxos: Vec, + /// Hash of the tip block. + pub tip_block_hash: BlockHash, + /// Height of the tip height. + pub tip_height: u32, + /// Page reference when the response needs to be paginated. + /// + /// To be used in [UtxoFilter::Page]. + pub next_page: Option>, +} + +/// Argument type of [bitcoin_send_transaction](super::bitcoin_send_transaction). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct SendTransactionRequest { + /// The serialized transaction data. + /// + /// Several checks are performed. + /// See [IC method `bitcoin_send_transaction`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_send_transaction). + pub transaction: Vec, + /// See [BitcoinNetwork]. + pub network: BitcoinNetwork, +} + +/// Argument type of [bitcoin_get_current_fee_percentiles](super::bitcoin_get_current_fee_percentiles). +#[derive( + CandidType, + Serialize, + Deserialize, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Clone, + Copy, + Default, +)] +pub struct GetCurrentFeePercentilesRequest { + /// See [BitcoinNetwork]. + pub network: BitcoinNetwork, +} diff --git a/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs b/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs new file mode 100644 index 000000000..cb444ba80 --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs @@ -0,0 +1,23 @@ +//! The ECDSA API. + +use crate::api::call::{call, CallResult}; +use candid::Principal; + +mod types; +pub use types::*; + +/// Return a SEC1 encoded ECDSA public key for the given canister using the given derivation path. +/// +/// See [IC method `ecdsa_public_key`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-ecdsa_public_key). +pub async fn ecdsa_public_key( + arg: EcdsaPublicKeyArgument, +) -> CallResult<(EcdsaPublicKeyResponse,)> { + call(Principal::management_canister(), "ecdsa_public_key", (arg,)).await +} + +/// Return a new ECDSA signature of the given message_hash that can be separately verified against a derived ECDSA public key. +/// +/// See [IC method `sign_with_ecdsa`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-sign_with_ecdsa). +pub async fn sign_with_ecdsa(arg: SignWithEcdsaArgument) -> CallResult<(SignWithEcdsaResponse,)> { + call(Principal::management_canister(), "sign_with_ecdsa", (arg,)).await +} diff --git a/src/ic-cdk/src/api/management_canister/ecdsa/types.rs b/src/ic-cdk/src/api/management_canister/ecdsa/types.rs new file mode 100644 index 000000000..395e3f5f4 --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/ecdsa/types.rs @@ -0,0 +1,77 @@ +use candid::CandidType; +use serde::{Deserialize, Serialize}; + +use super::super::main::CanisterId; + +/// Argument type of [ecdsa_public_key](super::ecdsa_public_key). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct EcdsaPublicKeyArgument { + /// Canister id, default to the canister id of the caller if None. + pub canister_id: Option, + /// A vector of variable length byte strings. + pub derivation_path: Vec>, + /// See [EcdsaKeyId]. + pub key_id: EcdsaKeyId, +} + +/// Response Type of [ecdsa_public_key](super::ecdsa_public_key). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct EcdsaPublicKeyResponse { + /// An ECDSA public key encoded in SEC1 compressed form. + pub public_key: Vec, + /// Can be used to deterministically derive child keys of the public_key. + pub chain_code: Vec, +} + +/// Argument type of [sign_with_ecdsa](super::sign_with_ecdsa). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct SignWithEcdsaArgument { + /// Hash of the message with length of 32 bytes. + pub message_hash: Vec, + /// A vector of variable length byte strings. + pub derivation_path: Vec>, + /// See [EcdsaKeyId]. + pub key_id: EcdsaKeyId, +} + +/// Response type of [sign_with_ecdsa](super::sign_with_ecdsa). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct SignWithEcdsaResponse { + /// Encoded as the concatenation of the SEC1 encodings of the two values r and s. + pub signature: Vec, +} + +/// ECDSA KeyId. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct EcdsaKeyId { + /// See [EcdsaCurve]. + pub curve: EcdsaCurve, + /// Name. + pub name: String, +} + +/// ECDSA Curve. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, +)] +pub enum EcdsaCurve { + /// secp256k1 + #[serde(rename = "secp256k1")] + Secp256k1, +} + +impl Default for EcdsaCurve { + fn default() -> Self { + Self::Secp256k1 + } +} diff --git a/src/ic-cdk/src/api/management_canister/http_request.rs b/src/ic-cdk/src/api/management_canister/http_request.rs new file mode 100644 index 000000000..bd7882bce --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/http_request.rs @@ -0,0 +1,127 @@ +//! Canister HTTP request. + +use crate::api::call::{call_with_payment128, CallResult}; +use candid::{CandidType, Principal}; +use serde::{Deserialize, Serialize}; + +/// HTTP header. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct HttpHeader { + /// Name + pub name: String, + /// Value + pub value: String, +} + +/// HTTP method. +/// +/// Currently support following methods. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, +)] +pub enum HttpMethod { + /// GET + GET, + /// POST + POST, + /// HEAD + HEAD, +} + +/// Argument type of [http_request]. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct CanisterHttpRequestArgument { + /// The requested URL. + pub url: String, + /// The maximal size of the response in bytes. If None, 2MiB will be the limit. + pub max_response_bytes: Option, + // TODO: Different name in the Spec. + /// The method of HTTP request. + pub http_method: HttpMethod, + /// List of HTTP request headers and their corresponding values. + pub headers: Vec, + /// Optionally provide request body. + pub body: Option>, + // TODO: Here is a discrepancy between System API and the implementation. + /// Name of the transform function which is `func (http_response) -> (http_response) query`. + pub transform_method_name: Option, +} + +/// The returned HTTP response. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct HttpResponse { + // TODO: Different type in the Spec. + /// The response status (e.g., 200, 404). + pub status: u64, + /// List of HTTP response headers and their corresponding values. + pub headers: Vec, + /// The response’s body. + pub body: Vec, +} + +/// Make an HTTP request to a given URL and return the HTTP response, possibly after a transformation. +/// +/// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. +/// See source code for the exact function. +/// +/// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). +pub async fn http_request(arg: CanisterHttpRequestArgument) -> CallResult<(HttpResponse,)> { + let cycles = http_request_required_cycles(&arg); + call_with_payment128( + Principal::management_canister(), + "http_request", + (arg,), + cycles, + ) + .await +} + +fn http_request_required_cycles(arg: &CanisterHttpRequestArgument) -> u128 { + let max_response_bytes = match arg.max_response_bytes { + Some(ref n) => *n as u128, + None => 2 * 1024 * 1024u128, // default 2MiB + }; + let arg_raw = candid::utils::encode_args((arg,)).expect("Failed to encode arguments."); + // TODO: this formula should be documented somewhere + // 12 is "http_request".len(). + 400_000_000u128 + 100_000u128 * (arg_raw.len() as u128 + 12 + max_response_bytes) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn required_cycles_some_max() { + let url = "https://example.com".to_string(); + let arg = CanisterHttpRequestArgument { + url, + max_response_bytes: Some(3000), + http_method: HttpMethod::GET, + headers: vec![], + body: None, + transform_method_name: None, + }; + assert_eq!(http_request_required_cycles(&arg), 713100000u128); + } + + #[test] + fn required_cycles_none_max() { + let url = "https://example.com".to_string(); + let arg = CanisterHttpRequestArgument { + url, + max_response_bytes: None, + http_method: HttpMethod::GET, + headers: vec![], + body: None, + transform_method_name: None, + }; + assert_eq!(http_request_required_cycles(&arg), 210127500000u128); + } +} diff --git a/src/ic-cdk/src/api/management_canister/main/mod.rs b/src/ic-cdk/src/api/management_canister/main/mod.rs new file mode 100644 index 000000000..39da27d24 --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/main/mod.rs @@ -0,0 +1,100 @@ +//! The main functionalities in [the IC management canister][1]. +//! +//! Most of the functions are for managing canister lifecycle. +//! [raw_rand] is also included in this module. +//! +//! [1]: https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-management-canister + +use crate::api::call::{call, call_with_payment128, CallResult}; +use candid::Principal; + +mod types; +pub use types::*; + +// https://internetcomputer.org/docs/current/developer-docs/deploy/computation-and-storage-costs +const CREATE_CANISTER_CYCLES: u128 = 1_000_000_000_000u128; + +/// Register a new canister and get its canister id. +/// +/// See [IC method `create_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-create_canister). +pub async fn create_canister(arg: CreateCanisterArgument) -> CallResult<(CanisterIdRecord,)> { + call_with_payment128( + Principal::management_canister(), + "create_canister", + (arg,), + CREATE_CANISTER_CYCLES, + ) + .await +} + +/// Update the settings of a canister. +/// +/// See [IC method `update_settings`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-update_settings). +pub async fn update_settings(arg: UpdateSettingsArgument) -> CallResult<()> { + call(Principal::management_canister(), "update_settings", (arg,)).await +} + +/// Install code into a canister. +/// +/// See [IC method `install_code`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-install_code). +pub async fn install_code(arg: InstallCodeArgument) -> CallResult<()> { + call(Principal::management_canister(), "install_code", (arg,)).await +} + +/// Remove a canister's code and state, making the canister empty again. +/// +/// See [IC method `uninstall_code`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-uninstall_code) +pub async fn uninstall_code(arg: CanisterIdRecord) -> CallResult<()> { + call(Principal::management_canister(), "uninstall_code", (arg,)).await +} + +/// Start a canister if the canister status was `stopped` or `stopping`. +/// +/// See [IC method `start_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-start_canister) +pub async fn start_canister(arg: CanisterIdRecord) -> CallResult<()> { + call(Principal::management_canister(), "start_canister", (arg,)).await +} + +/// Stop a canister. +/// +/// See [IC method `stop_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-stop_canister) +pub async fn stop_canister(arg: CanisterIdRecord) -> CallResult<()> { + call(Principal::management_canister(), "stop_canister", (arg,)).await +} + +/// Get status information about the canister. +/// +/// See [IC method `canister_status`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-canister_status) +pub async fn canister_status(arg: CanisterIdRecord) -> CallResult<(CanisterStatusResponse,)> { + call(Principal::management_canister(), "canister_status", (arg,)).await +} + +/// Delete a canister from the IC. +/// +/// See [IC method `delete_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-delete_canister) +pub async fn delete_canister(arg: CanisterIdRecord) -> CallResult<()> { + call(Principal::management_canister(), "delete_canister", (arg,)).await +} + +/// Deposit cycles into the specified canister. +/// +/// Note that, beyond the argument as specified in the interface description, +/// there is a second parameter `cycles` which is the amount of cycles to be deposited. +/// +/// See [IC method `deposit_cycles`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-deposit_cycles) +pub async fn deposit_cycles(arg: CanisterIdRecord, cycles: u128) -> CallResult<()> { + call_with_payment128( + Principal::management_canister(), + "deposit_cycles", + (arg,), + cycles, + ) + .await +} + +/// Get 32 pseudo-random bytes. +/// +/// See [IC method `raw_rand`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-raw_rand) +pub async fn raw_rand() -> CallResult<(Vec,)> { + call(Principal::management_canister(), "raw_rand", ()).await +} diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs new file mode 100644 index 000000000..adf54702e --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -0,0 +1,131 @@ +use candid::{CandidType, Nat, Principal}; +use serde::{Deserialize, Serialize}; + +/// Canister ID is Principal. +pub type CanisterId = Principal; + +/// Canister settings. +/// +/// See [`settings`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-create_canister). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct CanisterSettings { + /// A list of principals. Must be between 0 and 10 in size. + pub controllers: Option>, + /// Must be a number between 0 and 100, inclusively. + pub compute_allocation: Option, + /// Must be a number between 0 and 2^48^ (i.e 256TB), inclusively. + pub memory_allocation: Option, + /// Must be a number between 0 and 2^64^-1, inclusively, and indicates a length of time in seconds. + pub freezing_threshold: Option, +} + +/// Argument type of [create_canister](super::create_canister). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct CreateCanisterArgument { + /// See [CanisterSettings]. + pub settings: Option, +} + +/// Argument type of [update_settings](super::update_settings). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct UpdateSettingsArgument { + /// Principle of the canister. + pub canister_id: CanisterId, + /// See [CanisterSettings]. + pub settings: CanisterSettings, +} + +/// The mode with which a canister is installed. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, +)] +#[serde(rename_all = "lowercase")] +pub enum CanisterInstallMode { + /// A fresh install of a new canister. + Install, + /// Reinstalling a canister that was already installed. + Reinstall, + /// Upgrade an existing canister. + Upgrade, +} + +/// WASM module. +pub type WasmModule = Vec; + +/// Argument type of [install_code](super::install_code). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct InstallCodeArgument { + /// See [CanisterInstallMode]. + pub mode: CanisterInstallMode, + /// Principle of the canister. + pub canister_id: CanisterId, + /// Code to be installed. + pub wasm_module: WasmModule, + /// The argument to be passed to `canister_init` or `canister_post_upgrade`. + pub arg: Vec, +} + +/// A wrapper of canister id. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, +)] +pub struct CanisterIdRecord { + /// Principle of the canister. + pub canister_id: CanisterId, +} + +/// Status of a canister. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, +)] +#[serde(rename_all = "lowercase")] +pub enum CanisterStatusType { + /// The canister is running. + Running, + /// The canister is stopping. + Stopping, + /// The canister is stopped. + Stopped, +} + +/// Like [CanisterSettings]. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct DefiniteCanisterSettings { + /// Controllers of the canister. + pub controllers: Vec, + /// Compute allocation. + pub compute_allocation: Nat, + /// Memory allocation. + pub memory_allocation: Nat, + /// Freezing threshold. + pub freezing_threshold: Nat, +} + +/// Argument type of [canister_status](super::canister_status). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct CanisterStatusResponse { + /// See [CanisterStatusType]. + pub status: CanisterStatusType, + /// See [DefiniteCanisterSettings]. + pub settings: DefiniteCanisterSettings, + /// A SHA256 hash of the module installed on the canister. This is null if the canister is empty. + pub module_hash: Option>, + /// The memory size taken by the canister. + pub memory_size: Nat, + /// The cycle balance of the canister. + pub cycles: Nat, + /// Amount of cycles burned per day. + pub idle_cycles_burned_per_day: Nat, +} diff --git a/src/ic-cdk/src/api/management_canister/mod.rs b/src/ic-cdk/src/api/management_canister/mod.rs new file mode 100644 index 000000000..77217cf2f --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/mod.rs @@ -0,0 +1,17 @@ +//! Functions and types for calling [the IC management canister][1]. +//! +//! This module is a direct translation from the [interface decription][2]. +//! +//! The functions and types defined in this module serves these purposes: +//! * Make it easy to construct correct request data. +//! * For those calls require cycles payments, they are handled behind-the-scenes. +//! * Handle the response ergonomically. +//! +//! [1]: https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-management-canister +//! [2]: https://internetcomputer.org/assets/files/ic-a45d11feb0ba0494055083f9d2d21ddf.did + +pub mod bitcoin; +pub mod ecdsa; +pub mod http_request; +pub mod main; +pub mod provisional; diff --git a/src/ic-cdk/src/api/management_canister/provisional.rs b/src/ic-cdk/src/api/management_canister/provisional.rs new file mode 100644 index 000000000..ce449d77f --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/provisional.rs @@ -0,0 +1,59 @@ +//! Provisional functions only available in local development instances. + +use crate::api::call::{call, CallResult}; +use candid::{CandidType, Nat, Principal}; +use serde::{Deserialize, Serialize}; + +pub use super::main::{CanisterId, CanisterIdRecord, CanisterSettings}; + +/// Argument type of [provisional_create_canister_with_cycles]. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct ProvisionalCreateCanisterWithCyclesArgument { + /// The created canister will have this amount of cycles. + pub amount: Option, + /// See [CanisterSettings]. + pub settings: Option, +} + +/// Argument type of [provisional_top_up_canister]. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct ProvisionalTopUpCanisterArgument { + /// Canister ID. + pub canister_id: CanisterId, + /// Amount of cycles to be added. + pub amount: Nat, +} + +/// Create a new canister with specified amout of cycles balance. +/// +/// This method is only available in local development instances. +/// +/// See [IC method `provisional_create_canister_with_cycles`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-provisional_create_canister_with_cycles). +pub async fn provisional_create_canister_with_cycles( + arg: ProvisionalCreateCanisterWithCyclesArgument, +) -> CallResult<(CanisterIdRecord,)> { + call( + Principal::management_canister(), + "provisional_create_canister_with_cycles", + (arg,), + ) + .await +} + +/// Add cycles to a canister. +/// +/// This method is only available in local development instances. +/// +/// See [IC method `provisional_top_up_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-provisional_top_up_canister). +pub async fn provisional_top_up_canister(arg: ProvisionalTopUpCanisterArgument) -> CallResult<()> { + call( + Principal::management_canister(), + "provisional_top_up_canister", + (arg,), + ) + .await +} From 6f67a9380f98f0453be8516163f9595a6a750459 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 9 Aug 2022 15:04:22 -0400 Subject: [PATCH 085/234] chore: improve CI (#299) * fix examples fmt/clippy * speed up examples * fix * fmt * use env * trailing slash * rm unused features * rm workflows * ci workflow * ci:required * cache * fix aggregate * cache key with hash * not cache for ic-cdk-optimizer Its cache size is too big, causing other cache be evicted. * cache key on rust-toolchain --- .github/workflows/ci.yml | 163 ++++++++++++++++++ .github/workflows/e2e.yml | 63 ------- .github/workflows/examples.yml | 71 ++++---- .github/workflows/fmt.yml | 46 ----- .github/workflows/lint.yml | 43 ----- .github/workflows/test.yml | 85 --------- .../asset_storage/src/asset_storage_rs/lib.rs | 6 +- examples/chess/src/chess_rs/lib.rs | 11 +- examples/counter/src/counter_rs/lib.rs | 4 +- examples/counter/src/inter2_rs/lib.rs | 4 +- examples/counter/src/inter_rs/lib.rs | 4 +- src/ic-cdk/Cargo.toml | 3 - 12 files changed, 209 insertions(+), 294 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/e2e.yml delete mode 100644 .github/workflows/fmt.yml delete mode 100644 .github/workflows/lint.yml delete mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..5ba2f65e8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,163 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + +env: + rust-version: 1.60.0 + +jobs: + build: + name: cargo build + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-build-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + restore-keys: | + ${{ runner.os }}-build- + ${{ runner.os }}- + - name: Install Rust + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ env.rust-version }} + target: wasm32-unknown-unknown + - name: Run builds + run: | + cargo build --workspace --exclude ic-cdk-optimizer --exclude ic-cdk-e2e-tests --target wasm32-unknown-unknown + cargo build --workspace --exclude ic-cdk-optimizer --exclude ic-cdk-e2e-tests --target wasm32-unknown-unknown --release + + build-ic-cdk-optimizer: + name: Build ic-cdk-optimizer + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Rust + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ env.rust-version }} + - name: Run builds + run: | + cargo build -p ic-cdk-optimizer + + test: + name: cargo test + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-test-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + restore-keys: | + ${{ runner.os }}-test- + ${{ runner.os }}- + - name: Install Rust + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ env.rust-version }} + - name: Run tests + run: | + cargo test --all-targets + + fmt: + name: cargo fmt + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-fmt-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + restore-keys: | + ${{ runner.os }}-fmt- + ${{ runner.os }}- + - name: Install Rust + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ env.rust-version }} + components: rustfmt + - name: Check formatting + run: | + cargo fmt --all -- --check + + clippy: + name: cargo clippy + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-clippy-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + restore-keys: | + ${{ runner.os }}-clippy- + ${{ runner.os }}- + - name: Install Rust + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ env.rust-version }} + components: clippy + - name: Run clippy + run: | + cargo clippy --tests --benches -- -D clippy::all + + aggregate: + name: ci:required + if: ${{ always() }} + needs: [build, build-ic-cdk-optimizer, test, fmt, clippy] + runs-on: ubuntu-latest + steps: + - name: check build result + if: ${{ needs.build.result != 'success' }} + run: exit 1 + - name: check build-ic-cdk-optimizer result + if: ${{ needs.build-ic-cdk-optimizer.result != 'success' }} + run: exit 1 + - name: check test result + if: ${{ needs.test.result != 'success' }} + run: exit 1 + - name: check fmt result + if: ${{ needs.fmt.result != 'success' }} + run: exit 1 + - name: check clippy result + if: ${{ needs.clippy.result != 'success' }} + run: exit 1 diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml deleted file mode 100644 index a10db3fda..000000000 --- a/.github/workflows/e2e.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: End-to-end Test - -on: - push: - branches: - - main - pull_request: - -jobs: - test: - runs-on: ${{ matrix.os }} - strategy: - matrix: - build: [ linux-stable ] - include: - - build: linux-stable - os: ubuntu-latest - rust: 1.60.0 - - build: macos-stable - os: macos-latest - rust: 1.60.0 - - steps: - - uses: actions/checkout@v2 - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-1 - - - name: Install Rust - run: | - rustup update ${{ matrix.rust }} --no-self-update - rustup default ${{ matrix.rust }} - - - name: E2E tests - run: | - cargo test -p ic-cdk-e2e-tests - env: - RUST_BACKTRACE: 1 - - - name: Purge for OSX - if: matrix.os == 'macos-latest' - run: | - # There is a bug with BSD tar on macOS where the first 8MB of the file are - # sometimes all NUL bytes. See https://github.com/actions/cache/issues/403 - # and https://github.com/rust-lang/cargo/issues/8603 for some more - # information. An alternative solution here is to install GNU tar, but - # flushing the disk cache seems to work, too. - sudo /usr/sbin/purge - - aggregate: - name: e2e:required - if: ${{ always() }} - needs: test - runs-on: ubuntu-latest - steps: - - name: check step result directly - if: ${{ needs.test.result != 'success' }} - run: exit 1 diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 2c93b21d3..49729c79e 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -1,4 +1,3 @@ - name: Examples on: @@ -7,40 +6,49 @@ on: - main pull_request: +env: + rust-version: 1.60.0 + dfx-version: 0.11.1 + jobs: test: - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - build: [ linux-stable ] - include: - - build: linux-stable - os: ubuntu-latest - rust: 1.60.0 - dfx: 0.11.1 + project-name: + [asset_storage, chess, counter, management_canister, print, profile] steps: - - uses: actions/checkout@v2 + - name: Checkout repository + uses: actions/checkout@v3 - - uses: actions/cache@v2 + - name: Cache + uses: actions/cache@v3 with: path: | - ~/.cargo/registry - ~/.cargo/git - **/target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-1 + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + examples/${{ matrix.project-name }}/target/ + key: ${{ runner.os }}-${{ matrix.project-name }}-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.project-name }}- + ${{ runner.os }}- - name: Install Rust - run: | - rustup update ${{ matrix.rust }} --no-self-update - rustup default ${{ matrix.rust }} - rustup target add wasm32-unknown-unknown + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ env.rust-version }} + target: wasm32-unknown-unknown + components: rustfmt - name: Install DFX run: | - export DFX_VERSION=${{ matrix.dfx }} - echo Install DFX Version: $DFX_VERSION - yes | sh -ci "$(curl -fsSL https://sdk.dfinity.org/install.sh)" + export DFX_VERSION=${{env.dfx-version }} + echo Install DFX v$DFX_VERSION + yes | sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)" - name: Setup BATS uses: mig4/setup-bats@v1.0.2 @@ -48,6 +56,7 @@ jobs: bats-version: 1.2.1 - name: Install bitcoin + if: ${{ matrix.project-name == 'management_canister' }} run: | CWD=$(pwd) cd "$(mktemp -d)" @@ -64,23 +73,15 @@ jobs: - name: Run Tests shell: bash run: | - echo CWD: $(pwd) - echo bitcoind: $(which bitcoind) - echo bitcoin-cli: $(which bitcoin-cli) - export PATH=$PATH:$HOME/bin - bats -r examples + bats -r examples/${{ matrix.project-name }} env: RUST_BACKTRACE: 1 - - name: Purge for OSX - if: matrix.os == 'macos-latest' + - name: cargo fmt # no clippy because #[import] makes it fail run: | - # There is a bug with BSD tar on macOS where the first 8MB of the file are - # sometimes all NUL bytes. See https://github.com/actions/cache/issues/403 - # and https://github.com/rust-lang/cargo/issues/8603 for some more - # information. An alternative solution here is to install GNU tar, but - # flushing the disk cache seems to work, too. - sudo /usr/sbin/purge + pushd examples/${{ matrix.project-name }} + cargo fmt --check + popd aggregate: name: examples:required @@ -88,6 +89,6 @@ jobs: needs: test runs-on: ubuntu-latest steps: - - name: check step result directly + - name: Check step result directly if: ${{ needs.test.result != 'success' }} run: exit 1 diff --git a/.github/workflows/fmt.yml b/.github/workflows/fmt.yml deleted file mode 100644 index 0b9361382..000000000 --- a/.github/workflows/fmt.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: Format - -on: [pull_request] - -jobs: - test: - name: fmt - runs-on: ubuntu-latest - strategy: - matrix: - rust: [ 1.60.0 ] - - steps: - - uses: actions/checkout@v2 - - - name: Cache Cargo - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ matrix.build }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ matrix.build }}-cargo- - - - name: Install Rust - run: | - rustup update ${{ matrix.rust }} --no-self-update - rustup default ${{ matrix.rust }} - rustup component add rustfmt - - - name: Run Cargo Fmt - run: cargo fmt --all -- --check - env: - RUST_BACKTRACE: 1 - - aggregate: - name: fmt:required - if: ${{ always() }} - needs: test - runs-on: ubuntu-latest - steps: - - name: check step result directly - if: ${{ needs.test.result != 'success' }} - run: exit 1 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 2516e8724..000000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Lint - -on: [pull_request] - -jobs: - test: - name: lint - runs-on: ubuntu-latest - strategy: - matrix: - rust: [ 1.60.0 ] - - steps: - - uses: actions/checkout@v2 - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - - name: Install Rust - run: | - rustup update ${{ matrix.rust }} --no-self-update - rustup default ${{ matrix.rust }} - rustup component add clippy - - - name: Run Lint - run: cargo clippy --tests --benches -- -D clippy::all - env: - RUST_BACKTRACE: 1 - - aggregate: - name: lint:required - if: ${{ always() }} - needs: test - runs-on: ubuntu-latest - steps: - - name: check step result directly - if: ${{ needs.test.result != 'success' }} - run: exit 1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 6deae052e..000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,85 +0,0 @@ -name: Tests - -on: - push: - branches: - - main - pull_request: - -jobs: - test: - runs-on: ${{ matrix.os }} - strategy: - matrix: - build: [ linux-stable ] - include: - - build: linux-stable - os: ubuntu-latest - rust: 1.60.0 - - build: macos-stable - os: macos-latest - rust: 1.60.0 - - build: windows-stable - os: windows-latest - rust: 1.60.0 - - steps: - - uses: actions/checkout@v2 - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-1 - - - name: Install Rust - run: | - rustup update ${{ matrix.rust }} --no-self-update - rustup default ${{ matrix.rust }} - - - name: Install dependencies (windows only) - if: matrix.os == 'windows-latest' - shell: bash - run: | - vcpkg integrate install - vcpkg install openssl:x64-windows-static-md - echo "::set-env OPENSSL_DIR 'C:\Tools\vcpkg\installed\x64-windows-static-md'" - echo "::set-env OPENSSL_STATIC Yes" - env: - VCPKG_ROOT: 'C:\vcpkg' - - - name: Run Tests - shell: bash - run: | - # Test all features and no features for each package except e2e-tests. - # We run e2e tests in a separate workflow. - for p in $(cargo metadata --no-deps --format-version 1 | jq -r .packages[].manifest_path | grep -v e2e-tests); do - pushd $(dirname $p) - cargo test --all-targets --all-features - cargo test --all-targets --no-default-features - popd - done - env: - RUST_BACKTRACE: 1 - - - name: Purge for OSX - if: matrix.os == 'macos-latest' - run: | - # There is a bug with BSD tar on macOS where the first 8MB of the file are - # sometimes all NUL bytes. See https://github.com/actions/cache/issues/403 - # and https://github.com/rust-lang/cargo/issues/8603 for some more - # information. An alternative solution here is to install GNU tar, but - # flushing the disk cache seems to work, too. - sudo /usr/sbin/purge - - aggregate: - name: test:required - if: ${{ always() }} - needs: test - runs-on: ubuntu-latest - steps: - - name: check step result directly - if: ${{ needs.test.result != 'success' }} - run: exit 1 diff --git a/examples/asset_storage/src/asset_storage_rs/lib.rs b/examples/asset_storage/src/asset_storage_rs/lib.rs index 6df723e63..2e31e272c 100644 --- a/examples/asset_storage/src/asset_storage_rs/lib.rs +++ b/examples/asset_storage/src/asset_storage_rs/lib.rs @@ -1,8 +1,4 @@ -use ic_cdk::{ - api::call::ManualReply, - export::Principal, - storage, -}; +use ic_cdk::{api::call::ManualReply, export::Principal, storage}; use ic_cdk_macros::*; use std::cell::RefCell; use std::collections::{BTreeMap, BTreeSet}; diff --git a/examples/chess/src/chess_rs/lib.rs b/examples/chess/src/chess_rs/lib.rs index e2ef86d45..961d7606d 100644 --- a/examples/chess/src/chess_rs/lib.rs +++ b/examples/chess/src/chess_rs/lib.rs @@ -21,7 +21,7 @@ thread_local! { } #[update] -fn new(name: String, white: bool) -> () { +fn new(name: String, white: bool) { STORE.with(|game_store| { game_store.borrow_mut().insert( name.clone(), @@ -55,7 +55,7 @@ fn uci_move(name: String, m: String) -> bool { } #[update(name = "aiMove")] -fn ai_move(name: String) -> () { +fn ai_move(name: String) { STORE.with(|game_store| { let mut game_store = game_store.borrow_mut(); let game = game_store @@ -71,10 +71,5 @@ fn ai_move(name: String) -> () { #[query(name = "getFen")] fn get_fen(name: String) -> Option { - STORE.with(|game_store| { - game_store - .borrow() - .get(&name) - .and_then(|game| Some(game.board.fen())) - }) + STORE.with(|game_store| game_store.borrow().get(&name).map(|game| game.board.fen())) } diff --git a/examples/counter/src/counter_rs/lib.rs b/examples/counter/src/counter_rs/lib.rs index 57c0c31d3..54571abe5 100644 --- a/examples/counter/src/counter_rs/lib.rs +++ b/examples/counter/src/counter_rs/lib.rs @@ -16,7 +16,7 @@ fn init() { } #[update] -fn inc() -> () { +fn inc() { ic_cdk::println!("{:?}", OWNER.with(|owner| owner.get())); COUNTER.with(|counter| *counter.borrow_mut() += 1u64); } @@ -27,6 +27,6 @@ fn read() -> ManualReply { } #[update] -fn write(input: candid::Nat) -> () { +fn write(input: candid::Nat) { COUNTER.with(|counter| *counter.borrow_mut() = input); } diff --git a/examples/counter/src/inter2_rs/lib.rs b/examples/counter/src/inter2_rs/lib.rs index 8daae069b..664b9212b 100644 --- a/examples/counter/src/inter2_rs/lib.rs +++ b/examples/counter/src/inter2_rs/lib.rs @@ -10,11 +10,11 @@ async fn read() -> candid::Nat { } #[update] -async fn inc() -> () { +async fn inc() { CounterCanister::inc().await } #[update] -async fn write(input: candid::Nat) -> () { +async fn write(input: candid::Nat) { CounterCanister::write(input).await } diff --git a/examples/counter/src/inter_rs/lib.rs b/examples/counter/src/inter_rs/lib.rs index fd407bf33..bc400cc5a 100644 --- a/examples/counter/src/inter_rs/lib.rs +++ b/examples/counter/src/inter_rs/lib.rs @@ -10,11 +10,11 @@ async fn read() -> candid::Nat { } #[update] -async fn inc() -> () { +async fn inc() { CounterCanister::inc().await } #[update] -async fn write(input: candid::Nat) -> () { +async fn write(input: candid::Nat) { CounterCanister::write(input).await } diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 27192fade..9727e0c87 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -21,6 +21,3 @@ serde = "1.0.110" [dev-dependencies] rstest = "0.12.0" - -[features] -experimental = [] From b61bd49bff40761fc0b8fd1e9d85c2368f57c4fa Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 9 Aug 2022 18:08:27 -0400 Subject: [PATCH 086/234] chore: remove patch for candid (#300) --- Cargo.toml | 3 --- examples/asset_storage/Cargo.toml | 3 --- examples/chess/Cargo.toml | 3 --- examples/counter/Cargo.toml | 3 --- examples/management_canister/Cargo.toml | 3 --- examples/print/Cargo.toml | 3 --- examples/profile/Cargo.toml | 3 --- 7 files changed, 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index affc98df1..e2f25c5bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,3 @@ debug = false panic = "abort" lto = true opt-level = 'z' - -[patch.crates-io] -candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/examples/asset_storage/Cargo.toml b/examples/asset_storage/Cargo.toml index e0cdcae57..995b8a2fa 100644 --- a/examples/asset_storage/Cargo.toml +++ b/examples/asset_storage/Cargo.toml @@ -6,6 +6,3 @@ members = [ [profile.release] lto = true opt-level = 'z' - -[patch.crates-io] -candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/examples/chess/Cargo.toml b/examples/chess/Cargo.toml index 6c8c7c4f1..e97684672 100644 --- a/examples/chess/Cargo.toml +++ b/examples/chess/Cargo.toml @@ -6,6 +6,3 @@ members = [ [profile.release] lto = true opt-level = 'z' - -[patch.crates-io] -candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/examples/counter/Cargo.toml b/examples/counter/Cargo.toml index e36f4a63d..12ee45194 100644 --- a/examples/counter/Cargo.toml +++ b/examples/counter/Cargo.toml @@ -4,6 +4,3 @@ members = [ "src/inter_rs", "src/inter2_rs", ] - -[patch.crates-io] -candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/examples/management_canister/Cargo.toml b/examples/management_canister/Cargo.toml index 7cdc69ed7..c3cc6137b 100644 --- a/examples/management_canister/Cargo.toml +++ b/examples/management_canister/Cargo.toml @@ -2,6 +2,3 @@ members = [ "src/caller", ] - -[patch.crates-io] -candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/examples/print/Cargo.toml b/examples/print/Cargo.toml index 16cb6cc60..74a0decf6 100644 --- a/examples/print/Cargo.toml +++ b/examples/print/Cargo.toml @@ -2,6 +2,3 @@ members = [ "src/print_rs", ] - -[patch.crates-io] -candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} diff --git a/examples/profile/Cargo.toml b/examples/profile/Cargo.toml index f4e27d526..11917b831 100644 --- a/examples/profile/Cargo.toml +++ b/examples/profile/Cargo.toml @@ -3,6 +3,3 @@ members = [ "src/profile_rs", "src/profile_inter_rs", ] - -[patch.crates-io] -candid = { git = "https://github.com/dfinity/candid.git", rev = "73a8af2096093129274b23347be0c012e2362655"} From 637f69c5eee90f90c2175203b89d1841a3276ef7 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Wed, 10 Aug 2022 16:23:50 +0200 Subject: [PATCH 087/234] fix: do not trap in call() if decoder fails (#301) * fix: do not trap in call() if decoder fails This change maps decoding failure in the call() function to CanisterError reject code. This way canisters have a chance to handle decoding failures gracefully. * update docs & changelog * factor out decoder error handling into a function --- e2e-tests/canisters/async.rs | 20 ++++++++++++++++++++ e2e-tests/tests/e2e.rs | 5 +++++ src/ic-cdk/CHANGELOG.md | 4 ++++ src/ic-cdk/src/api/call.rs | 22 ++++++++++++++++++---- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/e2e-tests/canisters/async.rs b/e2e-tests/canisters/async.rs index 36b9dcc68..33a886dc0 100644 --- a/e2e-tests/canisters/async.rs +++ b/e2e-tests/canisters/async.rs @@ -53,4 +53,24 @@ fn notify(whom: Principal, method: String) { }); } +#[query] +fn greet(name: String) -> String { + format!("Hello, {}", name) +} + +#[update] +async fn invalid_reply_payload_does_not_trap() -> String { + // We're decoding an integer instead of a string, decoding must fail. + let result: Result<(u64,), _> = + ic_cdk::call(ic_cdk::api::id(), "greet", ("World".to_string(),)).await; + + match result { + Ok((_n,)) => ic_cdk::api::trap("expected the decoding to fail"), + Err((err_code, _)) => format!( + "handled decoding error gracefully with code {}", + err_code as i32 + ), + } +} + fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 36021798c..9fc6556b2 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -117,6 +117,11 @@ fn test_panic_after_async_frees_resources() { assert_eq!(i, n, "expected the invocation count to be {}, got {}", i, n); } + + let (message,): (String,) = + call_candid(&env, canister_id, "invalid_reply_payload_does_not_trap", ()) + .expect("call failed"); + assert_eq!(&message, "handled decoding error gracefully with code 5"); } #[test] diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 1f62544b1..f69e04f82 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Derive common traits for `RejectionCode` (#294) - `ManualReply::reject` function (#297) +### Fixed + +- Failure to decode the reply in `ic_cdk::call` does not trap anymore (#301). + ## [0.5.5] - 2022-07-22 ### Added diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 904d4be9d..d71662057 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -394,7 +394,21 @@ fn call_raw_internal( CallFuture { state } } -/// Performs an asynchronous call to another canister via ic0. +fn decoder_error_to_reject(err: candid::error::Error) -> (RejectionCode, String) { + ( + RejectionCode::CanisterError, + format!( + "failed to decode canister response as {}: {}", + std::any::type_name::(), + err + ), + ) +} + +/// Performs an asynchronous call to another canister using the [System API](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-call). +/// +/// If the reply payload is not a valid encoding of the expected type [T], +/// the call results in [RejectionCode::CanisterError] error. pub fn call ArgumentDecoder<'a>>( id: Principal, method: &str, @@ -404,7 +418,7 @@ pub fn call ArgumentDecoder<'a>>( let fut = call_raw(id, method, &args_raw, 0); async { let bytes = fut.await?; - decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) + decode_args(&bytes).map_err(decoder_error_to_reject::) } } @@ -419,7 +433,7 @@ pub fn call_with_payment ArgumentDecoder<'a>>( let fut = call_raw(id, method, &args_raw, cycles); async { let bytes = fut.await?; - decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) + decode_args(&bytes).map_err(decoder_error_to_reject::) } } @@ -434,7 +448,7 @@ pub fn call_with_payment128 ArgumentDecoder<'a>>( let fut = call_raw128(id, method, &args_raw, cycles); async { let bytes = fut.await?; - decode_args(&bytes).map_err(|err| trap(&format!("{:?}", err))) + decode_args(&bytes).map_err(decoder_error_to_reject::) } } From c22cbd40db3ef6d8fa97833586fddc9c21d3312e Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 10 Aug 2022 10:51:35 -0400 Subject: [PATCH 088/234] chore: release cdk v0.5.6 (#302) --- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 4 +++- src/ic-cdk/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 00d05aa32..86e638e07 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.5.5" +version = "0.5.6" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index f69e04f82..c8946fd2d 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.5.6] - 2022-08-10 + ### Added - New `ic_cdk::api::management_canister` module for calling the IC management canister (#295) - Derive common traits for `RejectionCode` (#294) @@ -13,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Failure to decode the reply in `ic_cdk::call` does not trap anymore (#301). +- Failure to decode the reply in `ic_cdk::call` does not trap anymore (#301) ## [0.5.5] - 2022-07-22 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 9727e0c87..b665914c0 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.5.5" +version = "0.5.6" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." From ff4e4ee3c37b47f66f0908ecba537bd06fda7616 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 10 Aug 2022 12:03:40 -0400 Subject: [PATCH 089/234] chore: fix badges (#303) --- README.md | 4 ++-- src/ic-cdk-macros/README.md | 2 +- src/ic-cdk/README.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 751d2d5e1..c67b04d37 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Crates.io](https://img.shields.io/crates/v/ic-cdk.svg)](https://crates.io/crates/ic-cdk) [![License](https://img.shields.io/crates/l/ic-cdk.svg)](https://github.com/dfinity/cdk-rs/blob/main/src/ic-cdk/LICENSE) [![Downloads](https://img.shields.io/crates/d/ic-cdk.svg)](https://crates.io/crates/ic-cdk) -[![Test Status](https://github.com/dfinity/cdk-rs/actions/workflows/test.yml/badge.svg)](https://github.com/dfinity/cdk-rs/actions) +[![CI](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml) **Rust CDK provides tools for building Canisters on Internet Computer (IC).** @@ -43,7 +43,7 @@ In Cargo.toml: crate-type = ["cdylib"] [dependencies] -candid = "0.7.15" # this is required if you want to use the `#[import]` macro +candid = "0.7.16" # this is required if you want to use the `#[import]` macro ic-cdk = "0.5" ic-cdk-macros = "0.5" ``` diff --git a/src/ic-cdk-macros/README.md b/src/ic-cdk-macros/README.md index 26f9c0deb..03ec86ee3 100644 --- a/src/ic-cdk-macros/README.md +++ b/src/ic-cdk-macros/README.md @@ -6,6 +6,6 @@ [![Crates.io](https://img.shields.io/crates/v/ic-cdk-macros.svg)](https://crates.io/crates/ic-cdk-macros) [![License](https://img.shields.io/crates/l/ic-cdk-macros.svg)](https://github.com/dfinity/cdk-rs/blob/main/src/ic-cdk-macros/LICENSE) [![Downloads](https://img.shields.io/crates/d/ic-cdk-macros.svg)](https://crates.io/crates/ic-cdk-macros) -[![Test Status](https://github.com/dfinity/cdk-rs/actions/workflows/test.yml/badge.svg)](https://github.com/dfinity/cdk-rs/actions) +[![CI](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml) This crate provide attribute macros, with which you can annotate regular rust functions to be public interfaces of a canister. diff --git a/src/ic-cdk/README.md b/src/ic-cdk/README.md index 46fa16764..e2687ee9d 100644 --- a/src/ic-cdk/README.md +++ b/src/ic-cdk/README.md @@ -6,4 +6,4 @@ [![Crates.io](https://img.shields.io/crates/v/ic-cdk.svg)](https://crates.io/crates/ic-cdk) [![License](https://img.shields.io/crates/l/ic-cdk.svg)](https://github.com/dfinity/cdk-rs/blob/main/src/ic-cdk/LICENSE) [![Downloads](https://img.shields.io/crates/d/ic-cdk.svg)](https://crates.io/crates/ic-cdk) -[![Test Status](https://github.com/dfinity/cdk-rs/actions/workflows/test.yml/badge.svg)](https://github.com/dfinity/cdk-rs/actions) +[![CI](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml) From fcecc76c6b5445bd02376c3f6475af6d78cbc264 Mon Sep 17 00:00:00 2001 From: Marcin Nowak-Liebiediew Date: Mon, 22 Aug 2022 17:31:32 +0200 Subject: [PATCH 090/234] fix(ic-certified-assets): disable etags and redirects (#305) * disable etags and redirects Co-authored-by: Severin Siffert --- src/ic-certified-assets/src/state_machine.rs | 43 +----- src/ic-certified-assets/src/tests.rs | 130 ------------------- 2 files changed, 2 insertions(+), 171 deletions(-) diff --git a/src/ic-certified-assets/src/state_machine.rs b/src/ic-certified-assets/src/state_machine.rs index e754bcc44..c7303d568 100644 --- a/src/ic-certified-assets/src/state_machine.rs +++ b/src/ic-certified-assets/src/state_machine.rs @@ -473,41 +473,14 @@ impl State { callback: Func, ) -> HttpResponse { let mut encodings = vec![]; - let mut etags = Vec::new(); + // waiting for https://dfinity.atlassian.net/browse/BOUN-446 + let etags = Vec::new(); for (name, value) in req.headers.iter() { if name.eq_ignore_ascii_case("Accept-Encoding") { for v in value.split(',') { encodings.push(v.trim().to_string()); } } - if name.eq_ignore_ascii_case("Host") { - if let Some(replacement_url) = redirect_to_url(value, &req.url) { - return HttpResponse { - status_code: 308, - headers: vec![("Location".to_string(), replacement_url)], - body: RcBytes::from(ByteBuf::default()), - streaming_strategy: None, - }; - } - } - if name.eq_ignore_ascii_case("If-None-Match") { - match decode_etag_seq(value) { - Ok(decoded_etags) => { - etags = decoded_etags; - } - Err(err) => { - return HttpResponse { - status_code: 400, - headers: vec![], - body: RcBytes::from(ByteBuf::from(format!( - "Invalid {} header value: {}", - name, err - ))), - streaming_strategy: None, - }; - } - } - } } encodings.push("identity".to_string()); @@ -825,15 +798,3 @@ fn build_404(certificate_header: HeaderField) -> HttpResponse { streaming_strategy: None, } } - -fn redirect_to_url(host: &str, url: &str) -> Option { - if let Some(host) = host.split(':').next() { - let host = host.trim(); - if host == "raw.ic0.app" { - return Some(format!("https://ic0.app{}", url)); - } else if let Some(base) = host.strip_suffix(".raw.ic0.app") { - return Some(format!("https://{}.ic0.app{}", base, url)); - } - } - None -} diff --git a/src/ic-certified-assets/src/tests.rs b/src/ic-certified-assets/src/tests.rs index c86f533d4..1ca7155b5 100644 --- a/src/ic-certified-assets/src/tests.rs +++ b/src/ic-certified-assets/src/tests.rs @@ -8,7 +8,6 @@ use crate::types::{ use crate::url_decode::{url_decode, UrlDecodeError}; use candid::Principal; use serde_bytes::ByteBuf; -use sha2::Digest; fn some_principal() -> Principal { Principal::from_text("ryjl3-tyaaa-aaaaa-aaaba-cai").unwrap() @@ -337,82 +336,6 @@ fn uses_streaming_for_multichunk_assets() { ); } -#[test] -fn supports_etag_caching() { - let mut state = State::default(); - let time_now = 100_000_000_000; - - const BODY: &[u8] = b""; - let hash: [u8; 32] = sha2::Sha256::digest(BODY).into(); - let etag = hex::encode(hash); - - create_assets( - &mut state, - time_now, - vec![AssetBuilder::new("/contents.html", "text/html").with_encoding("identity", vec![BODY])], - ); - - let response = state.http_request( - RequestBuilder::get("/contents.html") - .with_header("Accept-Encoding", "gzip,identity") - .build(), - &[], - unused_callback(), - ); - - assert_eq!(response.status_code, 200); - assert_eq!(response.body.as_ref(), BODY); - assert_eq!( - lookup_header(&response, "ETag"), - Some(format!("\"{}\"", etag).as_str()), - "No matching ETag header in response: {:#?}, expected ETag {}", - response, - etag - ); - assert!( - lookup_header(&response, "IC-Certificate").is_some(), - "No IC-Certificate header in response: {:#?}", - response - ); - - let response = state.http_request( - RequestBuilder::get("/contents.html") - .with_header("Accept-Encoding", "gzip,identity") - .with_header("If-None-Match", format!("\"{}\"", etag)) - .build(), - &[], - unused_callback(), - ); - - assert_eq!(response.status_code, 304); - assert_eq!(response.body.as_ref(), &[] as &[u8]); -} - -#[test] -fn returns_400_on_invalid_etag() { - let mut state = State::default(); - let time_now = 100_000_000_000; - - const BODY: &[u8] = b""; - - create_assets( - &mut state, - time_now, - vec![AssetBuilder::new("/contents.html", "text/html").with_encoding("identity", vec![BODY])], - ); - - let response = state.http_request( - RequestBuilder::get("/contents.html") - .with_header("Accept-Encoding", "gzip,identity") - .with_header("If-None-Match", "cafe") - .build(), - &[], - unused_callback(), - ); - - assert_eq!(response.status_code, 400); -} - #[test] fn supports_max_age_headers() { let mut state = State::default(); @@ -465,59 +388,6 @@ fn supports_max_age_headers() { ); } -#[test] -fn redirects_cleanly() { - fn fake(host: &str) -> HttpRequest { - RequestBuilder::get("/asset.blob") - .with_header("Host", host) - .build() - } - fn assert_308(resp: &HttpResponse, expected: &str) { - assert_eq!(resp.status_code, 308); - assert!(resp - .headers - .iter() - .any(|(key, value)| key == "Location" && value == expected)); - } - - let state = State::default(); - let fake_cert = [0xca, 0xfe]; - - assert_308( - &state.http_request(fake("aaaaa-aa.raw.ic0.app"), &fake_cert, unused_callback()), - "https://aaaaa-aa.ic0.app/asset.blob", - ); - assert_308( - &state.http_request( - fake("my.http.files.raw.ic0.app"), - &fake_cert, - unused_callback(), - ), - "https://my.http.files.ic0.app/asset.blob", - ); - assert_308( - &state.http_request( - fake("raw.ic0.app.raw.ic0.app"), - &fake_cert, - unused_callback(), - ), - "https://raw.ic0.app.ic0.app/asset.blob", - ); - assert_308( - &state.http_request(fake("raw.ic0.app"), &fake_cert, unused_callback()), // for ?canisterId= - "https://ic0.app/asset.blob", - ); - let no_redirect = state - .http_request(fake("raw.ic0.app.ic0.app"), &fake_cert, unused_callback()) - .status_code; - assert!(!matches!(no_redirect, 308)); - - let no_redirect2 = state - .http_request(fake("straw.ic0.app"), &fake_cert, unused_callback()) - .status_code; - assert!(!matches!(no_redirect2, 308)); -} - #[test] fn check_url_decode() { assert_eq!( From c87bb33925ee3764e662e83dcb7268e357dfd182 Mon Sep 17 00:00:00 2001 From: Marcin Nowak-Liebiediew Date: Mon, 22 Aug 2022 19:17:40 +0200 Subject: [PATCH 091/234] chore: release `ic-certified-assets` `0.2.5` (#306) * Update Cargo.toml * Update changelog --- src/ic-certified-assets/CHANGELOG.md | 6 ++++++ src/ic-certified-assets/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ic-certified-assets/CHANGELOG.md b/src/ic-certified-assets/CHANGELOG.md index 542c06eae..63f1a0fa0 100644 --- a/src/ic-certified-assets/CHANGELOG.md +++ b/src/ic-certified-assets/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.5] - 2022-08-22 +### Removed +- Support for asset caching based on [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) +- Automatic redirection of all traffic from `.raw.ic0.app` domain to `.ic0.app` + ## [0.2.4] - 2022-07-12 ### Fixed - headers field in Candid spec accepts mmultiple HTTP headers @@ -24,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Support for asset caching based on [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) - Support for asset caching based on [max-age](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) +- Automatic redirection of all traffic from `.raw.ic0.app` domain to `.ic0.app` ## [0.1.0] - 2022-02-02 ### Added diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml index 149c687e0..adff117b8 100644 --- a/src/ic-certified-assets/Cargo.toml +++ b/src/ic-certified-assets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-certified-assets" -version = "0.2.4" +version = "0.2.5" edition = "2021" authors = ["DFINITY Stiftung "] description = "Rust support for asset certification." From 84a90654b70d090dcb89329600b5b6efaa1800ef Mon Sep 17 00:00:00 2001 From: Ryan Vandersmith Date: Mon, 29 Aug 2022 14:24:20 -0600 Subject: [PATCH 092/234] fix: tutorial links in readme (#307) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c67b04d37..cc72e2ee7 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ You may be looking for: - [Documentation Site of the Internet Computer](https://smartcontracts.org/) -- [Tutorials of Rust CDK](https://smartcontracts.org/docs/rust-guide/rust-intro.html) +- [Tutorials of Rust CDK](https://internetcomputer.org/docs/current/developer-docs/build/cdks/cdk-rs-dfinity/) - [Examples](https://github.com/dfinity/cdk-rs/tree/main/examples) - [`dfx` for managing IC projects](https://github.com/dfinity/sdk) @@ -57,4 +57,4 @@ fn print() { } ``` -Check [tutorial](https://sdk.dfinity.org/docs/rust-guide/rust-quickstart.html) for a detailed guidance. +Check [tutorial](https://internetcomputer.org/docs/current/developer-docs/build/cdks/cdk-rs-dfinity/rust-quickstart) for a detailed guidance. From 32434e51dd9c459bbb8c469b7e174ba9e082c0ee Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 29 Aug 2022 17:32:22 -0400 Subject: [PATCH 093/234] chore: prefix decode_etag_seq with _ (#308) * chore: remove unused function and tests * Revert "chore: remove unused function and tests" This reverts commit 26ecabff6192635ee45849ddaf71c7c2b326d5b1. * prefix with underscore --- src/ic-certified-assets/src/state_machine.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ic-certified-assets/src/state_machine.rs b/src/ic-certified-assets/src/state_machine.rs index c7303d568..dc7e8bbe6 100644 --- a/src/ic-certified-assets/src/state_machine.rs +++ b/src/ic-certified-assets/src/state_machine.rs @@ -564,7 +564,8 @@ impl From for State { } } -fn decode_etag_seq(value: &str) -> Result, String> { +// TODO: remove the prefix underscore when add etag support back +fn _decode_etag_seq(value: &str) -> Result, String> { // Hex-encoded 32-byte hash + 2 quotes const EXPECTED_ETAG_LEN: usize = 66; let mut etags = Vec::with_capacity(1); @@ -607,7 +608,7 @@ fn test_decode_seq() { vec![[0u8; 32], [17u8; 32]], ), ] { - let decoded = decode_etag_seq(value) + let decoded = _decode_etag_seq(value) .unwrap_or_else(|e| panic!("failed to parse good ETag value {}: {}", value, e)); assert_eq!(decoded, expected); } @@ -618,7 +619,7 @@ fn test_decode_seq() { r#""0000000000000000000000000000000000000000000000000000000000000000" "1111111111111111111111111111111111111111111111111111111111111111""#, r#"0000000000000000000000000000000000000000000000000000000000000000 1111111111111111111111111111111111111111111111111111111111111111"#, ] { - let result = decode_etag_seq(value); + let result = _decode_etag_seq(value); assert!( result.is_err(), "should have failed to parse invalid ETag value {}, got: {:?}", From 1cf6f2901a33008215afc3b38bfd67834218ed7d Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 30 Aug 2022 12:13:52 -0400 Subject: [PATCH 094/234] chore: remove ic-certified-assets and leave a notice (#309) * delete * notice --- Cargo.toml | 1 - src/ic-certified-assets/CHANGELOG.md | 36 - src/ic-certified-assets/Cargo.toml | 24 - src/ic-certified-assets/LICENSE | 201 ----- src/ic-certified-assets/README.md | 55 +- src/ic-certified-assets/assets.did | 142 ---- src/ic-certified-assets/src/lib.rs | 232 ------ src/ic-certified-assets/src/rc_bytes.rs | 54 -- src/ic-certified-assets/src/state_machine.rs | 801 ------------------- src/ic-certified-assets/src/tests.rs | 478 ----------- src/ic-certified-assets/src/types.rs | 144 ---- src/ic-certified-assets/src/url_decode.rs | 63 -- 12 files changed, 2 insertions(+), 2229 deletions(-) delete mode 100644 src/ic-certified-assets/CHANGELOG.md delete mode 100644 src/ic-certified-assets/Cargo.toml delete mode 100644 src/ic-certified-assets/LICENSE delete mode 100644 src/ic-certified-assets/assets.did delete mode 100644 src/ic-certified-assets/src/lib.rs delete mode 100644 src/ic-certified-assets/src/rc_bytes.rs delete mode 100644 src/ic-certified-assets/src/state_machine.rs delete mode 100644 src/ic-certified-assets/src/tests.rs delete mode 100644 src/ic-certified-assets/src/types.rs delete mode 100644 src/ic-certified-assets/src/url_decode.rs diff --git a/Cargo.toml b/Cargo.toml index e2f25c5bf..68e34c46e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,6 @@ members = [ "src/ic-cdk", "src/ic-cdk-macros", "src/ic-cdk-optimizer", - "src/ic-certified-assets", "src/ic-certified-map", "src/ic-ledger-types", "e2e-tests", diff --git a/src/ic-certified-assets/CHANGELOG.md b/src/ic-certified-assets/CHANGELOG.md deleted file mode 100644 index 63f1a0fa0..000000000 --- a/src/ic-certified-assets/CHANGELOG.md +++ /dev/null @@ -1,36 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [0.2.5] - 2022-08-22 -### Removed -- Support for asset caching based on [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) -- Automatic redirection of all traffic from `.raw.ic0.app` domain to `.ic0.app` - -## [0.2.4] - 2022-07-12 -### Fixed -- headers field in Candid spec accepts mmultiple HTTP headers - -## [0.2.3] - 2022-07-06 -### Added -- Support for setting custom HTTP headers on asset creation - -## [0.2.2] - 2022-05-12 -### Fixed -- Parse and produce ETag headers with quotes around the hash - -## [0.2.1] - 2022-05-12 -### Fixed -- Make StableState public again - -## [0.2.0] - 2022-05-11 -### Added -- Support for asset caching based on [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) -- Support for asset caching based on [max-age](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) -- Automatic redirection of all traffic from `.raw.ic0.app` domain to `.ic0.app` - -## [0.1.0] - 2022-02-02 -### Added -- First release diff --git a/src/ic-certified-assets/Cargo.toml b/src/ic-certified-assets/Cargo.toml deleted file mode 100644 index adff117b8..000000000 --- a/src/ic-certified-assets/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "ic-certified-assets" -version = "0.2.5" -edition = "2021" -authors = ["DFINITY Stiftung "] -description = "Rust support for asset certification." -license = "Apache-2.0" -keywords = ["internet-computer", "dfinity"] -categories = ["wasm", "filesystem", "data-structures"] -repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.60.0" - -[dependencies] -base64 = "0.13" -candid = "0.7.15" -hex = "0.4.3" -ic-cdk = { path = "../ic-cdk", version = "0.5" } -ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.5" } -ic-certified-map = { path = "../ic-certified-map", version = "0.3" } -num-traits = "0.2.14" -serde = "1" -serde_bytes = "0.11" -serde_cbor = "0.11" -sha2 = "0.9.1" diff --git a/src/ic-certified-assets/LICENSE b/src/ic-certified-assets/LICENSE deleted file mode 100644 index b27ba1fe8..000000000 --- a/src/ic-certified-assets/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2020 DFINITY LLC. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/src/ic-certified-assets/README.md b/src/ic-certified-assets/README.md index 9478c816e..3f01e05a5 100644 --- a/src/ic-certified-assets/README.md +++ b/src/ic-certified-assets/README.md @@ -1,54 +1,3 @@ -# Certified Assets Library +# Notice -Rust support for asset certification. - -Certified assets can also be served from any Rust canister by including this library. - -## Adding to a canister - -``` -[dependencies] -ic-certified-assets = "0.2.2" -``` - -The assets are preserved over upgrades by including the corresponding functions in the `init/pre_upgrade/upgrade` -hooks which can be mixed with the other state from the canister: - -``` -#[derive(Clone, Debug, CandidType, Deserialize)] -struct StableState { - my_state: MyState, - assets: crate::assets::StableState, -} - -#[init] -fn init() { - crate::assets::init(); -} - -#[pre_upgrade] -fn pre_upgrade() { - let stable_state = STATE.with(|s| StableState { - my_state: s.my_state, - assets: crate::assets::pre_upgrade(), - }); - ic_cdk::storage::stable_save((stable_state,)).expect("failed to save stable state"); -} - -#[post_upgrade] -fn post_upgrade() { - let (StableState { assets, my_state },): (StableState,) = - ic_cdk::storage::stable_restore().expect("failed to restore stable state"); - crate::assets::post_upgrade(assets); - STATE.with(|s| { - s.my_state = my_state; - }; -} -``` - -## Uploading assets - -``` -cd assets -icx-asset --pem ~/.config/dfx/identity/default/identity.pem --replica https://ic0.app sync . -``` +The `ic-certified-assets` crate has been moved to the [sdk](https://github.com/dfinity/sdk) repo. diff --git a/src/ic-certified-assets/assets.did b/src/ic-certified-assets/assets.did deleted file mode 100644 index 791de3751..000000000 --- a/src/ic-certified-assets/assets.did +++ /dev/null @@ -1,142 +0,0 @@ -type BatchId = nat; -type ChunkId = nat; -type Key = text; -type Time = int; - -type CreateAssetArguments = record { - key: Key; - content_type: text; - max_age: opt nat64; - headers: opt vec HeaderField; -}; - -// Add or change content for an asset, by content encoding -type SetAssetContentArguments = record { - key: Key; - content_encoding: text; - chunk_ids: vec ChunkId; - sha256: opt blob; -}; - -// Remove content for an asset, by content encoding -type UnsetAssetContentArguments = record { - key: Key; - content_encoding: text; -}; - -// Delete an asset -type DeleteAssetArguments = record { - key: Key; -}; - -// Reset everything -type ClearArguments = record {}; - -type BatchOperationKind = variant { - CreateAsset: CreateAssetArguments; - SetAssetContent: SetAssetContentArguments; - - UnsetAssetContent: UnsetAssetContentArguments; - DeleteAsset: DeleteAssetArguments; - - Clear: ClearArguments; -}; - -type HeaderField = record { text; text; }; - -type HttpRequest = record { - method: text; - url: text; - headers: vec HeaderField; - body: blob; -}; - -type HttpResponse = record { - status_code: nat16; - headers: vec HeaderField; - body: blob; - streaming_strategy: opt StreamingStrategy; -}; - -type StreamingCallbackHttpResponse = record { - body: blob; - token: opt StreamingCallbackToken; -}; - -type StreamingCallbackToken = record { - key: Key; - content_encoding: text; - index: nat; - sha256: opt blob; -}; - -type StreamingStrategy = variant { - Callback: record { - callback: func (StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query; - token: StreamingCallbackToken; - }; -}; - -service: { - - get: (record { - key: Key; - accept_encodings: vec text; - }) -> (record { - content: blob; // may be the entirety of the content, or just chunk index 0 - content_type: text; - content_encoding: text; - sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments - total_length: nat; // all chunks except last have size == content.size() - }) query; - - // if get() returned chunks > 1, call this to retrieve them. - // chunks may or may not be split up at the same boundaries as presented to create_chunk(). - get_chunk: (record { - key: Key; - content_encoding: text; - index: nat; - sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments - }) -> (record { content: blob }) query; - - list : (record {}) -> (vec record { - key: Key; - content_type: text; - encodings: vec record { - content_encoding: text; - sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments - length: nat; // Size of this encoding's blob. Calculated when uploading assets. - modified: Time; - }; - }) query; - - create_batch : (record {}) -> (record { batch_id: BatchId }); - - create_chunk: (record { batch_id: BatchId; content: blob }) -> (record { chunk_id: ChunkId }); - - // Perform all operations successfully, or reject - commit_batch: (record { batch_id: BatchId; operations: vec BatchOperationKind }) -> (); - - create_asset: (CreateAssetArguments) -> (); - set_asset_content: (SetAssetContentArguments) -> (); - unset_asset_content: (UnsetAssetContentArguments) -> (); - - delete_asset: (DeleteAssetArguments) -> (); - - clear: (ClearArguments) -> (); - - // Single call to create an asset with content for a single content encoding that - // fits within the message ingress limit. - store: (record { - key: Key; - content_type: text; - content_encoding: text; - content: blob; - sha256: opt blob - }) -> (); - - http_request: (request: HttpRequest) -> (HttpResponse) query; - http_request_streaming_callback: (token: StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query; - - authorize: (principal) -> (); -} diff --git a/src/ic-certified-assets/src/lib.rs b/src/ic-certified-assets/src/lib.rs deleted file mode 100644 index ab6cc3a1c..000000000 --- a/src/ic-certified-assets/src/lib.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! This module declares canister methods expected by the assets canister client. -pub mod rc_bytes; -pub mod state_machine; -pub mod types; -mod url_decode; - -#[cfg(test)] -mod tests; - -pub use crate::state_machine::StableState; -use crate::{ - rc_bytes::RcBytes, - state_machine::{AssetDetails, EncodedAsset, State}, - types::*, -}; -use candid::{candid_method, Principal}; -use ic_cdk::api::{caller, data_certificate, set_certified_data, time, trap}; -use ic_cdk_macros::{query, update}; -use std::cell::RefCell; - -thread_local! { - static STATE: RefCell = RefCell::new(State::default()); -} - -#[update] -#[candid_method(update)] -fn authorize(other: Principal) { - let caller = caller(); - STATE.with(|s| { - if let Err(msg) = s.borrow_mut().authorize(&caller, other) { - trap(&msg); - } - }) -} - -#[query] -#[candid_method(query)] -fn retrieve(key: Key) -> RcBytes { - STATE.with(|s| match s.borrow().retrieve(&key) { - Ok(bytes) => bytes, - Err(msg) => trap(&msg), - }) -} - -#[update(guard = "is_authorized")] -#[candid_method(update)] -fn store(arg: StoreArg) { - STATE.with(move |s| { - if let Err(msg) = s.borrow_mut().store(arg, time()) { - trap(&msg); - } - set_certified_data(&s.borrow().root_hash()); - }); -} - -#[update(guard = "is_authorized")] -#[candid_method(update)] -fn create_batch() -> CreateBatchResponse { - STATE.with(|s| CreateBatchResponse { - batch_id: s.borrow_mut().create_batch(time()), - }) -} - -#[update(guard = "is_authorized")] -#[candid_method(update)] -fn create_chunk(arg: CreateChunkArg) -> CreateChunkResponse { - STATE.with(|s| match s.borrow_mut().create_chunk(arg, time()) { - Ok(chunk_id) => CreateChunkResponse { chunk_id }, - Err(msg) => trap(&msg), - }) -} - -#[update(guard = "is_authorized")] -#[candid_method(update)] -fn create_asset(arg: CreateAssetArguments) { - STATE.with(|s| { - if let Err(msg) = s.borrow_mut().create_asset(arg) { - trap(&msg); - } - set_certified_data(&s.borrow().root_hash()); - }) -} - -#[update(guard = "is_authorized")] -#[candid_method(update)] -fn set_asset_content(arg: SetAssetContentArguments) { - STATE.with(|s| { - if let Err(msg) = s.borrow_mut().set_asset_content(arg, time()) { - trap(&msg); - } - set_certified_data(&s.borrow().root_hash()); - }) -} - -#[update(guard = "is_authorized")] -#[candid_method(update)] -fn unset_asset_content(arg: UnsetAssetContentArguments) { - STATE.with(|s| { - if let Err(msg) = s.borrow_mut().unset_asset_content(arg) { - trap(&msg); - } - set_certified_data(&s.borrow().root_hash()); - }) -} - -#[update(guard = "is_authorized")] -#[candid_method(update)] -fn delete_asset(arg: DeleteAssetArguments) { - STATE.with(|s| { - s.borrow_mut().delete_asset(arg); - set_certified_data(&s.borrow().root_hash()); - }); -} - -#[update(guard = "is_authorized")] -#[candid_method(update)] -fn clear() { - STATE.with(|s| { - s.borrow_mut().clear(); - set_certified_data(&s.borrow().root_hash()); - }); -} - -#[update(guard = "is_authorized")] -#[candid_method(update)] -fn commit_batch(arg: CommitBatchArguments) { - STATE.with(|s| { - if let Err(msg) = s.borrow_mut().commit_batch(arg, time()) { - trap(&msg); - } - set_certified_data(&s.borrow().root_hash()); - }); -} - -#[query] -#[candid_method(query)] -fn get(arg: GetArg) -> EncodedAsset { - STATE.with(|s| match s.borrow().get(arg) { - Ok(asset) => asset, - Err(msg) => trap(&msg), - }) -} - -#[query] -#[candid_method(query)] -fn get_chunk(arg: GetChunkArg) -> GetChunkResponse { - STATE.with(|s| match s.borrow().get_chunk(arg) { - Ok(content) => GetChunkResponse { content }, - Err(msg) => trap(&msg), - }) -} - -#[query] -#[candid_method(query)] -fn list() -> Vec { - STATE.with(|s| s.borrow().list_assets()) -} - -#[query] -#[candid_method(query)] -fn http_request(req: HttpRequest) -> HttpResponse { - let certificate = data_certificate().unwrap_or_else(|| trap("no data certificate available")); - - STATE.with(|s| { - s.borrow().http_request( - req, - &certificate, - candid::Func { - method: "http_request_streaming_callback".to_string(), - principal: ic_cdk::id(), - }, - ) - }) -} - -#[query] -#[candid_method(query)] -fn http_request_streaming_callback(token: StreamingCallbackToken) -> StreamingCallbackHttpResponse { - STATE.with(|s| { - s.borrow() - .http_request_streaming_callback(token) - .unwrap_or_else(|msg| trap(&msg)) - }) -} - -fn is_authorized() -> Result<(), String> { - STATE.with(|s| { - s.borrow() - .is_authorized(&caller()) - .then(|| ()) - .ok_or_else(|| "Caller is not authorized".to_string()) - }) -} - -pub fn init() { - STATE.with(|s| { - let mut s = s.borrow_mut(); - s.clear(); - s.authorize_unconditionally(caller()); - }); -} - -pub fn pre_upgrade() -> StableState { - STATE.with(|s| s.take().into()) -} - -pub fn post_upgrade(stable_state: StableState) { - STATE.with(|s| { - *s.borrow_mut() = State::from(stable_state); - set_certified_data(&s.borrow().root_hash()); - }); -} - -#[test] -fn candid_interface_compatibility() { - use candid::utils::{service_compatible, CandidSource}; - use std::path::PathBuf; - - candid::export_service!(); - let new_interface = __export_service(); - - let old_interface = - PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("assets.did"); - - println!("Exported interface: {}", new_interface); - - service_compatible( - CandidSource::Text(&new_interface), - CandidSource::File(old_interface.as_path()), - ) - .expect("The assets canister interface is not compatible with the assets.did file"); -} diff --git a/src/ic-certified-assets/src/rc_bytes.rs b/src/ic-certified-assets/src/rc_bytes.rs deleted file mode 100644 index e2dbd5335..000000000 --- a/src/ic-certified-assets/src/rc_bytes.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! This module contains an implementation of [RcBytes], a reference-counted byte array. -use ic_cdk::export::candid::{ - types::{internal::Type, Serializer}, - CandidType, Deserialize, -}; -use serde::de::Deserializer; -use serde_bytes::ByteBuf; -use std::convert::AsRef; -use std::ops::Deref; -use std::rc::Rc; - -#[derive(Clone, Debug, Default)] -pub struct RcBytes(Rc); - -impl CandidType for RcBytes { - fn _ty() -> Type { - Type::Vec(Box::new(Type::Nat8)) - } - - fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> - where - S: Serializer, - { - serializer.serialize_blob(&*self.0) - } -} - -impl<'de> Deserialize<'de> for RcBytes { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - ByteBuf::deserialize(deserializer).map(Self::from) - } -} - -impl From for RcBytes { - fn from(b: ByteBuf) -> Self { - Self(Rc::new(b)) - } -} - -impl AsRef<[u8]> for RcBytes { - fn as_ref(&self) -> &[u8] { - &*self.0 - } -} - -impl Deref for RcBytes { - type Target = [u8]; - fn deref(&self) -> &[u8] { - &*self.0 - } -} diff --git a/src/ic-certified-assets/src/state_machine.rs b/src/ic-certified-assets/src/state_machine.rs deleted file mode 100644 index dc7e8bbe6..000000000 --- a/src/ic-certified-assets/src/state_machine.rs +++ /dev/null @@ -1,801 +0,0 @@ -//! This module contains a pure implementation of the certified assets state machine. - -// NB. This module should not depend on ic_cdk, it contains only pure state transition functions. -// All the environment (time, certificates, etc.) is passed to the state transition functions -// as formal arguments. This approach makes it very easy to test the state machine. - -use crate::{rc_bytes::RcBytes, types::*, url_decode::url_decode}; -use candid::{CandidType, Deserialize, Func, Int, Nat, Principal}; -use ic_certified_map::{AsHashTree, Hash, HashTree, RbTree}; -use num_traits::ToPrimitive; -use serde::Serialize; -use serde_bytes::ByteBuf; -use sha2::Digest; -use std::collections::HashMap; -use std::convert::TryInto; - -/// The amount of time a batch is kept alive. Modifying the batch -/// delays the expiry further. -pub const BATCH_EXPIRY_NANOS: u64 = 300_000_000_000; - -/// The order in which we pick encodings for certification. -const ENCODING_CERTIFICATION_ORDER: &[&str] = &["identity", "gzip", "compress", "deflate", "br"]; - -/// The file to serve if the requested file wasn't found. -const INDEX_FILE: &str = "/index.html"; - -type AssetHashes = RbTree; -type Timestamp = Int; - -#[derive(Default, Clone, Debug, CandidType, Deserialize)] -pub struct AssetEncoding { - pub modified: Timestamp, - pub content_chunks: Vec, - pub total_length: usize, - pub certified: bool, - pub sha256: [u8; 32], -} - -#[derive(Default, Clone, Debug, CandidType, Deserialize)] -pub struct Asset { - pub content_type: String, - pub encodings: HashMap, - pub max_age: Option, - pub headers: Option>, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct EncodedAsset { - pub content: RcBytes, - pub content_type: String, - pub content_encoding: String, - pub total_length: Nat, - pub sha256: Option, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct AssetDetails { - pub key: String, - pub content_type: String, - pub encodings: Vec, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct AssetEncodingDetails { - pub content_encoding: String, - pub sha256: Option, - pub length: Nat, - pub modified: Timestamp, -} - -pub struct Chunk { - pub batch_id: BatchId, - pub content: RcBytes, -} - -pub struct Batch { - pub expires_at: Timestamp, -} - -#[derive(Default)] -pub struct State { - assets: HashMap, - - chunks: HashMap, - next_chunk_id: ChunkId, - - batches: HashMap, - next_batch_id: BatchId, - - authorized: Vec, - - asset_hashes: AssetHashes, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct StableState { - authorized: Vec, - stable_assets: HashMap, -} - -impl State { - pub fn authorize_unconditionally(&mut self, principal: Principal) { - if !self.is_authorized(&principal) { - self.authorized.push(principal); - } - } - - pub fn authorize(&mut self, caller: &Principal, other: Principal) -> Result<(), String> { - if !self.is_authorized(caller) { - return Err("the caller is not authorized".to_string()); - } - self.authorize_unconditionally(other); - Ok(()) - } - - pub fn root_hash(&self) -> Hash { - use ic_certified_map::labeled_hash; - labeled_hash(b"http_assets", &self.asset_hashes.root_hash()) - } - - pub fn create_asset(&mut self, arg: CreateAssetArguments) -> Result<(), String> { - if let Some(asset) = self.assets.get(&arg.key) { - if asset.content_type != arg.content_type { - return Err("create_asset: content type mismatch".to_string()); - } - } else { - self.assets.insert( - arg.key, - Asset { - content_type: arg.content_type, - encodings: HashMap::new(), - max_age: arg.max_age, - headers: arg.headers, - }, - ); - } - Ok(()) - } - - pub fn set_asset_content( - &mut self, - arg: SetAssetContentArguments, - now: u64, - ) -> Result<(), String> { - if arg.chunk_ids.is_empty() { - return Err("encoding must have at least one chunk".to_string()); - } - - let asset = self - .assets - .get_mut(&arg.key) - .ok_or_else(|| "asset not found".to_string())?; - - let now = Int::from(now); - - let mut content_chunks = vec![]; - for chunk_id in arg.chunk_ids.iter() { - let chunk = self.chunks.remove(chunk_id).expect("chunk not found"); - content_chunks.push(chunk.content); - } - - let sha256: [u8; 32] = match arg.sha256 { - Some(bytes) => bytes - .into_vec() - .try_into() - .map_err(|_| "invalid SHA-256".to_string())?, - None => { - let mut hasher = sha2::Sha256::new(); - for chunk in content_chunks.iter() { - hasher.update(chunk); - } - hasher.finalize().into() - } - }; - - let total_length: usize = content_chunks.iter().map(|c| c.len()).sum(); - let enc = AssetEncoding { - modified: now, - content_chunks, - certified: false, - total_length, - sha256, - }; - asset.encodings.insert(arg.content_encoding, enc); - - on_asset_change(&mut self.asset_hashes, &arg.key, asset); - - Ok(()) - } - - pub fn unset_asset_content(&mut self, arg: UnsetAssetContentArguments) -> Result<(), String> { - let asset = self - .assets - .get_mut(&arg.key) - .ok_or_else(|| "asset not found".to_string())?; - - if asset.encodings.remove(&arg.content_encoding).is_some() { - on_asset_change(&mut self.asset_hashes, &arg.key, asset); - } - - Ok(()) - } - - pub fn delete_asset(&mut self, arg: DeleteAssetArguments) { - self.assets.remove(&arg.key); - self.asset_hashes.delete(arg.key.as_bytes()); - } - - pub fn clear(&mut self) { - self.assets.clear(); - self.batches.clear(); - self.chunks.clear(); - self.next_batch_id = Nat::from(1); - self.next_chunk_id = Nat::from(1); - } - - pub fn is_authorized(&self, principal: &Principal) -> bool { - self.authorized.contains(principal) - } - - pub fn retrieve(&self, key: &Key) -> Result { - let asset = self - .assets - .get(key) - .ok_or_else(|| "asset not found".to_string())?; - - let id_enc = asset - .encodings - .get("identity") - .ok_or_else(|| "no identity encoding".to_string())?; - - if id_enc.content_chunks.len() > 1 { - return Err("Asset too large. Use get() and get_chunk() instead.".to_string()); - } - - Ok(id_enc.content_chunks[0].clone()) - } - - pub fn store(&mut self, arg: StoreArg, time: u64) -> Result<(), String> { - let asset = self.assets.entry(arg.key.clone()).or_default(); - asset.content_type = arg.content_type; - - let hash = sha2::Sha256::digest(&arg.content).into(); - if let Some(provided_hash) = arg.sha256 { - if hash != provided_hash.as_ref() { - return Err("sha256 mismatch".to_string()); - } - } - - let encoding = asset.encodings.entry(arg.content_encoding).or_default(); - encoding.total_length = arg.content.len(); - encoding.content_chunks = vec![RcBytes::from(arg.content)]; - encoding.modified = Int::from(time); - encoding.sha256 = hash; - - on_asset_change(&mut self.asset_hashes, &arg.key, asset); - Ok(()) - } - - pub fn create_batch(&mut self, now: u64) -> BatchId { - let batch_id = self.next_batch_id.clone(); - self.next_batch_id += 1; - - self.batches.insert( - batch_id.clone(), - Batch { - expires_at: Int::from(now + BATCH_EXPIRY_NANOS), - }, - ); - self.chunks.retain(|_, c| { - self.batches - .get(&c.batch_id) - .map(|b| b.expires_at > now) - .unwrap_or(false) - }); - self.batches.retain(|_, b| b.expires_at > now); - - batch_id - } - - pub fn create_chunk(&mut self, arg: CreateChunkArg, now: u64) -> Result { - let mut batch = self - .batches - .get_mut(&arg.batch_id) - .ok_or_else(|| "batch not found".to_string())?; - - batch.expires_at = Int::from(now + BATCH_EXPIRY_NANOS); - - let chunk_id = self.next_chunk_id.clone(); - self.next_chunk_id += 1; - - self.chunks.insert( - chunk_id.clone(), - Chunk { - batch_id: arg.batch_id, - content: RcBytes::from(arg.content), - }, - ); - - Ok(chunk_id) - } - - pub fn commit_batch(&mut self, arg: CommitBatchArguments, now: u64) -> Result<(), String> { - let batch_id = arg.batch_id; - for op in arg.operations { - match op { - BatchOperation::CreateAsset(arg) => self.create_asset(arg)?, - BatchOperation::SetAssetContent(arg) => self.set_asset_content(arg, now)?, - BatchOperation::UnsetAssetContent(arg) => self.unset_asset_content(arg)?, - BatchOperation::DeleteAsset(arg) => self.delete_asset(arg), - BatchOperation::Clear(_) => self.clear(), - } - } - self.batches.remove(&batch_id); - Ok(()) - } - - pub fn list_assets(&self) -> Vec { - self.assets - .iter() - .map(|(key, asset)| { - let mut encodings: Vec<_> = asset - .encodings - .iter() - .map(|(enc_name, enc)| AssetEncodingDetails { - content_encoding: enc_name.clone(), - sha256: Some(ByteBuf::from(enc.sha256)), - length: Nat::from(enc.total_length), - modified: enc.modified.clone(), - }) - .collect(); - encodings.sort_by(|l, r| l.content_encoding.cmp(&r.content_encoding)); - - AssetDetails { - key: key.clone(), - content_type: asset.content_type.clone(), - encodings, - } - }) - .collect::>() - } - - pub fn get(&self, arg: GetArg) -> Result { - let asset = self - .assets - .get(&arg.key) - .ok_or_else(|| "asset not found".to_string())?; - - for enc in arg.accept_encodings.iter() { - if let Some(asset_enc) = asset.encodings.get(enc) { - return Ok(EncodedAsset { - content: asset_enc.content_chunks[0].clone(), - content_type: asset.content_type.clone(), - content_encoding: enc.clone(), - total_length: Nat::from(asset_enc.total_length as u64), - sha256: Some(ByteBuf::from(asset_enc.sha256)), - }); - } - } - Err("no such encoding".to_string()) - } - - pub fn get_chunk(&self, arg: GetChunkArg) -> Result { - let asset = self - .assets - .get(&arg.key) - .ok_or_else(|| "asset not found".to_string())?; - - let enc = asset - .encodings - .get(&arg.content_encoding) - .ok_or_else(|| "no such encoding".to_string())?; - - if let Some(expected_hash) = arg.sha256 { - if expected_hash != enc.sha256 { - return Err("sha256 mismatch".to_string()); - } - } - if arg.index >= enc.content_chunks.len() { - return Err("chunk index out of bounds".to_string()); - } - let index: usize = arg.index.0.to_usize().unwrap(); - - Ok(enc.content_chunks[index].clone()) - } - - fn build_http_response( - &self, - certificate: &[u8], - path: &str, - encodings: Vec, - index: usize, - callback: Func, - etags: Vec, - ) -> HttpResponse { - let index_redirect_certificate = if self.asset_hashes.get(path.as_bytes()).is_none() - && self.asset_hashes.get(INDEX_FILE.as_bytes()).is_some() - { - let absence_proof = self.asset_hashes.witness(path.as_bytes()); - let index_proof = self.asset_hashes.witness(INDEX_FILE.as_bytes()); - let combined_proof = merge_hash_trees(absence_proof, index_proof); - Some(witness_to_header(combined_proof, certificate)) - } else { - None - }; - - if let Some(certificate_header) = index_redirect_certificate { - if let Some(asset) = self.assets.get(INDEX_FILE) { - for enc_name in encodings.iter() { - if let Some(enc) = asset.encodings.get(enc_name) { - if enc.certified { - return build_ok( - asset, - enc_name, - enc, - INDEX_FILE, - index, - Some(certificate_header), - callback, - etags, - ); - } - } - } - } - } - - let certificate_header = - witness_to_header(self.asset_hashes.witness(path.as_bytes()), certificate); - - if let Some(asset) = self.assets.get(path) { - for enc_name in encodings.iter() { - if let Some(enc) = asset.encodings.get(enc_name) { - if enc.certified { - return build_ok( - asset, - enc_name, - enc, - path, - index, - Some(certificate_header), - callback, - etags, - ); - } else { - // Find if identity is certified, if it's not. - if let Some(id_enc) = asset.encodings.get("identity") { - if id_enc.certified { - return build_ok( - asset, - enc_name, - enc, - path, - index, - Some(certificate_header), - callback, - etags, - ); - } - } - } - } - } - } - - build_404(certificate_header) - } - - pub fn http_request( - &self, - req: HttpRequest, - certificate: &[u8], - callback: Func, - ) -> HttpResponse { - let mut encodings = vec![]; - // waiting for https://dfinity.atlassian.net/browse/BOUN-446 - let etags = Vec::new(); - for (name, value) in req.headers.iter() { - if name.eq_ignore_ascii_case("Accept-Encoding") { - for v in value.split(',') { - encodings.push(v.trim().to_string()); - } - } - } - encodings.push("identity".to_string()); - - let path = match req.url.find('?') { - Some(i) => &req.url[..i], - None => &req.url[..], - }; - - match url_decode(path) { - Ok(path) => self.build_http_response(certificate, &path, encodings, 0, callback, etags), - Err(err) => HttpResponse { - status_code: 400, - headers: vec![], - body: RcBytes::from(ByteBuf::from(format!( - "failed to decode path '{}': {}", - path, err - ))), - streaming_strategy: None, - }, - } - } - - pub fn http_request_streaming_callback( - &self, - StreamingCallbackToken { - key, - content_encoding, - index, - sha256, - }: StreamingCallbackToken, - ) -> Result { - let asset = self - .assets - .get(&key) - .ok_or_else(|| "Invalid token on streaming: key not found.".to_string())?; - let enc = asset - .encodings - .get(&content_encoding) - .ok_or_else(|| "Invalid token on streaming: encoding not found.".to_string())?; - - if let Some(expected_hash) = sha256 { - if expected_hash != enc.sha256 { - return Err("sha256 mismatch".to_string()); - } - } - - // MAX is good enough. This means a chunk would be above 64-bits, which is impossible... - let chunk_index = index.0.to_usize().unwrap_or(usize::MAX); - - Ok(StreamingCallbackHttpResponse { - body: enc.content_chunks[chunk_index].clone(), - token: create_token(asset, &content_encoding, enc, &key, chunk_index), - }) - } -} - -impl From for StableState { - fn from(state: State) -> Self { - Self { - authorized: state.authorized, - stable_assets: state.assets, - } - } -} - -impl From for State { - fn from(stable_state: StableState) -> Self { - let mut state = Self { - authorized: stable_state.authorized, - assets: stable_state.stable_assets, - ..Self::default() - }; - - for (asset_name, asset) in state.assets.iter_mut() { - for enc in asset.encodings.values_mut() { - enc.certified = false; - } - on_asset_change(&mut state.asset_hashes, asset_name, asset); - } - state - } -} - -// TODO: remove the prefix underscore when add etag support back -fn _decode_etag_seq(value: &str) -> Result, String> { - // Hex-encoded 32-byte hash + 2 quotes - const EXPECTED_ETAG_LEN: usize = 66; - let mut etags = Vec::with_capacity(1); - for etag in value.split(',') { - let etag = etag.trim(); - if etag.len() != EXPECTED_ETAG_LEN { - return Err(format!( - "invalid length of component {}: expected {}, got {}", - etag, - EXPECTED_ETAG_LEN, - etag.len() - )); - } - if !etag.starts_with('"') { - return Err(format!("missing first quote of component {}", etag)); - } - if !etag.ends_with('"') { - return Err(format!("missing final quote of component {}", etag)); - } - let mut hash = Hash::default(); - match hex::decode_to_slice(&etag[1..EXPECTED_ETAG_LEN - 1], &mut hash) { - Ok(()) => { - etags.push(hash); - } - Err(e) => return Err(format!("invalid hex of component {}: {}", etag, e)), - } - } - Ok(etags) -} - -#[test] -fn test_decode_seq() { - for (value, expected) in [ - ( - r#""0000000000000000000000000000000000000000000000000000000000000000""#, - vec![[0u8; 32]], - ), - ( - r#""0000000000000000000000000000000000000000000000000000000000000000", "1111111111111111111111111111111111111111111111111111111111111111""#, - vec![[0u8; 32], [17u8; 32]], - ), - ] { - let decoded = _decode_etag_seq(value) - .unwrap_or_else(|e| panic!("failed to parse good ETag value {}: {}", value, e)); - assert_eq!(decoded, expected); - } - - for value in [ - r#""00000000000000000000000000000000""#, - r#"0000000000000000000000000000000000000000000000000000000000000000"#, - r#""0000000000000000000000000000000000000000000000000000000000000000" "1111111111111111111111111111111111111111111111111111111111111111""#, - r#"0000000000000000000000000000000000000000000000000000000000000000 1111111111111111111111111111111111111111111111111111111111111111"#, - ] { - let result = _decode_etag_seq(value); - assert!( - result.is_err(), - "should have failed to parse invalid ETag value {}, got: {:?}", - value, - result - ); - } -} - -fn on_asset_change(asset_hashes: &mut AssetHashes, key: &str, asset: &mut Asset) { - // If the most preferred encoding is present and certified, - // there is nothing to do. - for enc_name in ENCODING_CERTIFICATION_ORDER.iter() { - if let Some(enc) = asset.encodings.get(*enc_name) { - if enc.certified { - return; - } else { - break; - } - } - } - - if asset.encodings.is_empty() { - asset_hashes.delete(key.as_bytes()); - return; - } - - // An encoding with a higher priority was added, let's certify it - // instead. - - for enc in asset.encodings.values_mut() { - enc.certified = false; - } - - for enc_name in ENCODING_CERTIFICATION_ORDER.iter() { - if let Some(enc) = asset.encodings.get_mut(*enc_name) { - asset_hashes.insert(key.to_string(), enc.sha256); - enc.certified = true; - return; - } - } - - // No known encodings found. Just pick the first one. The exact - // order is hard to predict because we use a hash map. Should - // almost never happen anyway. - if let Some(enc) = asset.encodings.values_mut().next() { - asset_hashes.insert(key.to_string(), enc.sha256); - enc.certified = true; - } -} - -fn witness_to_header(witness: HashTree, certificate: &[u8]) -> HeaderField { - use ic_certified_map::labeled; - - let hash_tree = labeled(b"http_assets", witness); - let mut serializer = serde_cbor::ser::Serializer::new(vec![]); - serializer.self_describe().unwrap(); - hash_tree.serialize(&mut serializer).unwrap(); - - ( - "IC-Certificate".to_string(), - String::from("certificate=:") - + &base64::encode(certificate) - + ":, tree=:" - + &base64::encode(&serializer.into_inner()) - + ":", - ) -} - -fn merge_hash_trees<'a>(lhs: HashTree<'a>, rhs: HashTree<'a>) -> HashTree<'a> { - use HashTree::{Empty, Fork, Labeled, Leaf, Pruned}; - - match (lhs, rhs) { - (Pruned(l), Pruned(r)) => { - if l != r { - panic!("merge_hash_trees: inconsistent hashes"); - } - Pruned(l) - } - (Pruned(_), r) => r, - (l, Pruned(_)) => l, - (Fork(l), Fork(r)) => Fork(Box::new(( - merge_hash_trees(l.0, r.0), - merge_hash_trees(l.1, r.1), - ))), - (Labeled(l_label, l), Labeled(r_label, r)) => { - if l_label != r_label { - panic!("merge_hash_trees: inconsistent hash tree labels"); - } - Labeled(l_label, Box::new(merge_hash_trees(*l, *r))) - } - (Empty, Empty) => Empty, - (Leaf(l), Leaf(r)) => { - if l != r { - panic!("merge_hash_trees: inconsistent leaves"); - } - Leaf(l) - } - (_l, _r) => { - panic!("merge_hash_trees: inconsistent tree structure"); - } - } -} - -fn create_token( - _asset: &Asset, - enc_name: &str, - enc: &AssetEncoding, - key: &str, - chunk_index: usize, -) -> Option { - if chunk_index + 1 >= enc.content_chunks.len() { - None - } else { - Some(StreamingCallbackToken { - key: key.to_string(), - content_encoding: enc_name.to_string(), - index: Nat::from(chunk_index + 1), - sha256: Some(ByteBuf::from(enc.sha256)), - }) - } -} - -#[allow(clippy::too_many_arguments)] -fn build_ok( - asset: &Asset, - enc_name: &str, - enc: &AssetEncoding, - key: &str, - chunk_index: usize, - certificate_header: Option, - callback: Func, - etags: Vec, -) -> HttpResponse { - let mut headers = vec![("Content-Type".to_string(), asset.content_type.to_string())]; - if enc_name != "identity" { - headers.push(("Content-Encoding".to_string(), enc_name.to_string())); - } - if let Some(head) = certificate_header { - headers.push(head); - } - if let Some(max_age) = asset.max_age { - headers.push(("Cache-Control".to_string(), format!("max-age={}", max_age))); - } - if let Some(arg_headers) = asset.headers.as_ref() { - for (k, v) in arg_headers { - headers.push((k.to_owned(), v.to_owned())); - } - } - - let streaming_strategy = create_token(asset, enc_name, enc, key, chunk_index) - .map(|token| StreamingStrategy::Callback { callback, token }); - - let (status_code, body) = if etags.contains(&enc.sha256) { - (304, RcBytes::default()) - } else { - headers.push(( - "ETag".to_string(), - format!("\"{}\"", hex::encode(enc.sha256)), - )); - (200, enc.content_chunks[chunk_index].clone()) - }; - - HttpResponse { - status_code, - headers, - body, - streaming_strategy, - } -} - -fn build_404(certificate_header: HeaderField) -> HttpResponse { - HttpResponse { - status_code: 404, - headers: vec![certificate_header], - body: RcBytes::from(ByteBuf::from("not found")), - streaming_strategy: None, - } -} diff --git a/src/ic-certified-assets/src/tests.rs b/src/ic-certified-assets/src/tests.rs deleted file mode 100644 index 1ca7155b5..000000000 --- a/src/ic-certified-assets/src/tests.rs +++ /dev/null @@ -1,478 +0,0 @@ -use std::collections::HashMap; - -use crate::state_machine::{StableState, State, BATCH_EXPIRY_NANOS}; -use crate::types::{ - BatchId, BatchOperation, CommitBatchArguments, CreateAssetArguments, CreateChunkArg, - HttpRequest, HttpResponse, SetAssetContentArguments, StreamingStrategy, -}; -use crate::url_decode::{url_decode, UrlDecodeError}; -use candid::Principal; -use serde_bytes::ByteBuf; - -fn some_principal() -> Principal { - Principal::from_text("ryjl3-tyaaa-aaaaa-aaaba-cai").unwrap() -} - -fn unused_callback() -> candid::Func { - candid::Func { - method: "unused".to_string(), - principal: some_principal(), - } -} - -struct AssetBuilder { - name: String, - content_type: String, - max_age: Option, - encodings: Vec<(String, Vec)>, - headers: Option>, -} - -impl AssetBuilder { - fn new(name: impl AsRef, content_type: impl AsRef) -> Self { - Self { - name: name.as_ref().to_string(), - content_type: content_type.as_ref().to_string(), - max_age: None, - encodings: vec![], - headers: None, - } - } - - fn with_max_age(mut self, max_age: u64) -> Self { - self.max_age = Some(max_age); - self - } - - fn with_encoding(mut self, name: impl AsRef, chunks: Vec>) -> Self { - self.encodings.push(( - name.as_ref().to_string(), - chunks - .into_iter() - .map(|c| ByteBuf::from(c.as_ref().to_vec())) - .collect(), - )); - self - } - - fn with_header(mut self, header_key: &str, header_value: &str) -> Self { - let hm = self.headers.get_or_insert(HashMap::new()); - hm.insert(header_key.to_string(), header_value.to_string()); - self - } -} - -struct RequestBuilder { - resource: String, - method: String, - headers: Vec<(String, String)>, - body: ByteBuf, -} - -impl RequestBuilder { - fn get(resource: impl AsRef) -> Self { - Self { - resource: resource.as_ref().to_string(), - method: "GET".to_string(), - headers: vec![], - body: ByteBuf::new(), - } - } - - fn with_header(mut self, name: impl AsRef, value: impl AsRef) -> Self { - self.headers - .push((name.as_ref().to_string(), value.as_ref().to_string())); - self - } - - fn build(self) -> HttpRequest { - HttpRequest { - method: self.method, - url: self.resource, - headers: self.headers, - body: self.body, - } - } -} - -fn create_assets(state: &mut State, time_now: u64, assets: Vec) -> BatchId { - let batch_id = state.create_batch(time_now); - - let mut operations = vec![]; - - for asset in assets { - operations.push(BatchOperation::CreateAsset(CreateAssetArguments { - key: asset.name.clone(), - content_type: asset.content_type, - max_age: asset.max_age, - headers: asset.headers, - })); - - for (enc, chunks) in asset.encodings { - let mut chunk_ids = vec![]; - for chunk in chunks { - chunk_ids.push( - state - .create_chunk( - CreateChunkArg { - batch_id: batch_id.clone(), - content: chunk, - }, - time_now, - ) - .unwrap(), - ); - } - - operations.push(BatchOperation::SetAssetContent({ - SetAssetContentArguments { - key: asset.name.clone(), - content_encoding: enc, - chunk_ids, - sha256: None, - } - })); - } - } - - state - .commit_batch( - CommitBatchArguments { - batch_id: batch_id.clone(), - operations, - }, - time_now, - ) - .unwrap(); - - batch_id -} - -fn lookup_header<'a>(response: &'a HttpResponse, header: &str) -> Option<&'a str> { - response - .headers - .iter() - .find_map(|(h, v)| h.eq_ignore_ascii_case(header).then(|| v.as_str())) -} - -#[test] -fn can_create_assets_using_batch_api() { - let mut state = State::default(); - let time_now = 100_000_000_000; - - const BODY: &[u8] = b""; - - let batch_id = create_assets( - &mut state, - time_now, - vec![AssetBuilder::new("/contents.html", "text/html").with_encoding("identity", vec![BODY])], - ); - - let response = state.http_request( - RequestBuilder::get("/contents.html") - .with_header("Accept-Encoding", "gzip,identity") - .build(), - &[], - unused_callback(), - ); - - assert_eq!(response.status_code, 200); - assert_eq!(response.body.as_ref(), BODY); - - // Try to update a completed batch. - let error_msg = state - .create_chunk( - CreateChunkArg { - batch_id, - content: ByteBuf::new(), - }, - time_now, - ) - .unwrap_err(); - - let expected = "batch not found"; - assert!( - error_msg.contains(expected), - "expected '{}' error, got: {}", - expected, - error_msg - ); -} - -#[test] -fn batches_are_dropped_after_timeout() { - let mut state = State::default(); - let time_now = 100_000_000_000; - - let batch_1 = state.create_batch(time_now); - - const BODY: &[u8] = b""; - - let _chunk_1 = state - .create_chunk( - CreateChunkArg { - batch_id: batch_1.clone(), - content: ByteBuf::from(BODY.to_vec()), - }, - time_now, - ) - .unwrap(); - - let time_now = time_now + BATCH_EXPIRY_NANOS + 1; - let _batch_2 = state.create_batch(time_now); - - match state.create_chunk( - CreateChunkArg { - batch_id: batch_1, - content: ByteBuf::from(BODY.to_vec()), - }, - time_now, - ) { - Err(err) if err.contains("batch not found") => (), - other => panic!("expected 'batch not found' error, got: {:?}", other), - } -} - -#[test] -fn returns_index_file_for_missing_assets() { - let mut state = State::default(); - let time_now = 100_000_000_000; - - const INDEX_BODY: &[u8] = b"Index"; - const OTHER_BODY: &[u8] = b"Other"; - - create_assets( - &mut state, - time_now, - vec![ - AssetBuilder::new("/index.html", "text/html") - .with_encoding("identity", vec![INDEX_BODY]), - AssetBuilder::new("/other.html", "text/html") - .with_encoding("identity", vec![OTHER_BODY]), - ], - ); - - let response = state.http_request( - RequestBuilder::get("/missing.html") - .with_header("Accept-Encoding", "gzip,identity") - .build(), - &[], - unused_callback(), - ); - - assert_eq!(response.status_code, 200); - assert_eq!(response.body.as_ref(), INDEX_BODY); -} - -#[test] -fn preserves_state_on_stable_roundtrip() { - let mut state = State::default(); - let time_now = 100_000_000_000; - - const INDEX_BODY: &[u8] = b"Index"; - - create_assets( - &mut state, - time_now, - vec![AssetBuilder::new("/index.html", "text/html") - .with_encoding("identity", vec![INDEX_BODY])], - ); - - let stable_state: StableState = state.into(); - let state: State = stable_state.into(); - - let response = state.http_request( - RequestBuilder::get("/index.html") - .with_header("Accept-Encoding", "gzip,identity") - .build(), - &[], - unused_callback(), - ); - assert_eq!(response.status_code, 200); - assert_eq!(response.body.as_ref(), INDEX_BODY); -} - -#[test] -fn uses_streaming_for_multichunk_assets() { - let mut state = State::default(); - let time_now = 100_000_000_000; - - const INDEX_BODY_CHUNK_1: &[u8] = b""; - const INDEX_BODY_CHUNK_2: &[u8] = b"Index"; - - create_assets( - &mut state, - time_now, - vec![AssetBuilder::new("/index.html", "text/html") - .with_encoding("identity", vec![INDEX_BODY_CHUNK_1, INDEX_BODY_CHUNK_2])], - ); - - let streaming_callback = candid::Func { - method: "stream".to_string(), - principal: some_principal(), - }; - let response = state.http_request( - RequestBuilder::get("/index.html") - .with_header("Accept-Encoding", "gzip,identity") - .build(), - &[], - streaming_callback.clone(), - ); - - assert_eq!(response.status_code, 200); - assert_eq!(response.body.as_ref(), INDEX_BODY_CHUNK_1); - - let StreamingStrategy::Callback { callback, token } = response - .streaming_strategy - .expect("missing streaming strategy"); - assert_eq!(callback, streaming_callback); - - let streaming_response = state.http_request_streaming_callback(token).unwrap(); - assert_eq!(streaming_response.body.as_ref(), INDEX_BODY_CHUNK_2); - assert!( - streaming_response.token.is_none(), - "Unexpected streaming response: {:?}", - streaming_response - ); -} - -#[test] -fn supports_max_age_headers() { - let mut state = State::default(); - let time_now = 100_000_000_000; - - const BODY: &[u8] = b""; - - create_assets( - &mut state, - time_now, - vec![ - AssetBuilder::new("/contents.html", "text/html").with_encoding("identity", vec![BODY]), - AssetBuilder::new("/max-age.html", "text/html") - .with_max_age(604800) - .with_encoding("identity", vec![BODY]), - ], - ); - - let response = state.http_request( - RequestBuilder::get("/contents.html") - .with_header("Accept-Encoding", "gzip,identity") - .build(), - &[], - unused_callback(), - ); - - assert_eq!(response.status_code, 200); - assert_eq!(response.body.as_ref(), BODY); - assert!( - lookup_header(&response, "Cache-Control").is_none(), - "Unexpected Cache-Control header in response: {:#?}", - response, - ); - - let response = state.http_request( - RequestBuilder::get("/max-age.html") - .with_header("Accept-Encoding", "gzip,identity") - .build(), - &[], - unused_callback(), - ); - - assert_eq!(response.status_code, 200); - assert_eq!(response.body.as_ref(), BODY); - assert_eq!( - lookup_header(&response, "Cache-Control"), - Some("max-age=604800"), - "No matching Cache-Control header in response: {:#?}", - response, - ); -} - -#[test] -fn check_url_decode() { - assert_eq!( - url_decode("/%"), - Err(UrlDecodeError::InvalidPercentEncoding) - ); - assert_eq!(url_decode("/%%"), Ok("/%".to_string())); - assert_eq!(url_decode("/%20a"), Ok("/ a".to_string())); - assert_eq!( - url_decode("/%%+a%20+%@"), - Err(UrlDecodeError::InvalidPercentEncoding) - ); - assert_eq!( - url_decode("/has%percent.txt"), - Err(UrlDecodeError::InvalidPercentEncoding) - ); - assert_eq!(url_decode("/%e6"), Ok("/æ".to_string())); -} - -#[test] -fn supports_custom_http_headers() { - let mut state = State::default(); - let time_now = 100_000_000_000; - - const BODY: &[u8] = b""; - - create_assets( - &mut state, - time_now, - vec![ - AssetBuilder::new("/contents.html", "text/html") - .with_encoding("identity", vec![BODY]) - .with_header("Access-Control-Allow-Origin", "*"), - AssetBuilder::new("/max-age.html", "text/html") - .with_max_age(604800) - .with_encoding("identity", vec![BODY]) - .with_header("X-Content-Type-Options", "nosniff"), - ], - ); - - let response = state.http_request( - RequestBuilder::get("/contents.html") - .with_header("Accept-Encoding", "gzip,identity") - .build(), - &[], - unused_callback(), - ); - - assert_eq!(response.status_code, 200); - assert_eq!(response.body.as_ref(), BODY); - assert!( - lookup_header(&response, "Access-Control-Allow-Origin").is_some(), - "Missing Access-Control-Allow-Origin header in response: {:#?}", - response, - ); - assert!( - lookup_header(&response, "Access-Control-Allow-Origin") == Some("*"), - "Incorrect value for Access-Control-Allow-Origin header in response: {:#?}", - response, - ); - - let response = state.http_request( - RequestBuilder::get("/max-age.html") - .with_header("Accept-Encoding", "gzip,identity") - .build(), - &[], - unused_callback(), - ); - - assert_eq!(response.status_code, 200); - assert_eq!(response.body.as_ref(), BODY); - assert_eq!( - lookup_header(&response, "Cache-Control"), - Some("max-age=604800"), - "No matching Cache-Control header in response: {:#?}", - response, - ); - assert!( - lookup_header(&response, "X-Content-Type-Options").is_some(), - "Missing X-Content-Type-Options header in response: {:#?}", - response, - ); - assert!( - lookup_header(&response, "X-Content-Type-Options") == Some("nosniff"), - "Incorrect value for X-Content-Type-Options header in response: {:#?}", - response, - ); -} diff --git a/src/ic-certified-assets/src/types.rs b/src/ic-certified-assets/src/types.rs deleted file mode 100644 index d62cf803c..000000000 --- a/src/ic-certified-assets/src/types.rs +++ /dev/null @@ -1,144 +0,0 @@ -//! This module defines types shared by the certified assets state machine and the canister -//! endpoints. -use std::collections::HashMap; - -use crate::rc_bytes::RcBytes; -use candid::{CandidType, Deserialize, Func, Nat}; -use serde_bytes::ByteBuf; - -pub type BatchId = Nat; -pub type ChunkId = Nat; -pub type Key = String; - -// IDL Types - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct CreateAssetArguments { - pub key: Key, - pub content_type: String, - pub max_age: Option, - pub headers: Option>, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct SetAssetContentArguments { - pub key: Key, - pub content_encoding: String, - pub chunk_ids: Vec, - pub sha256: Option, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct UnsetAssetContentArguments { - pub key: Key, - pub content_encoding: String, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct DeleteAssetArguments { - pub key: Key, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct ClearArguments {} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub enum BatchOperation { - CreateAsset(CreateAssetArguments), - SetAssetContent(SetAssetContentArguments), - UnsetAssetContent(UnsetAssetContentArguments), - DeleteAsset(DeleteAssetArguments), - Clear(ClearArguments), -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct CommitBatchArguments { - pub batch_id: BatchId, - pub operations: Vec, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct StoreArg { - pub key: Key, - pub content_type: String, - pub content_encoding: String, - pub content: ByteBuf, - pub sha256: Option, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct GetArg { - pub key: Key, - pub accept_encodings: Vec, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct GetChunkArg { - pub key: Key, - pub content_encoding: String, - pub index: Nat, - pub sha256: Option, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct GetChunkResponse { - pub content: RcBytes, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct CreateBatchResponse { - pub batch_id: BatchId, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct CreateChunkArg { - pub batch_id: BatchId, - pub content: ByteBuf, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct CreateChunkResponse { - pub chunk_id: ChunkId, -} -// HTTP interface - -pub type HeaderField = (String, String); - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct HttpRequest { - pub method: String, - pub url: String, - pub headers: Vec<(String, String)>, - pub body: ByteBuf, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct HttpResponse { - pub status_code: u16, - pub headers: Vec, - pub body: RcBytes, - pub streaming_strategy: Option, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct StreamingCallbackToken { - pub key: String, - pub content_encoding: String, - pub index: Nat, - // We don't care about the sha, we just want to be backward compatible. - pub sha256: Option, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub enum StreamingStrategy { - Callback { - callback: Func, - token: StreamingCallbackToken, - }, -} - -#[derive(Clone, Debug, CandidType, Deserialize)] -pub struct StreamingCallbackHttpResponse { - pub body: RcBytes, - pub token: Option, -} diff --git a/src/ic-certified-assets/src/url_decode.rs b/src/ic-certified-assets/src/url_decode.rs deleted file mode 100644 index e7c6c9ca0..000000000 --- a/src/ic-certified-assets/src/url_decode.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::fmt; - -/// An iterator-like structure that decode a URL. -struct UrlDecode<'a> { - bytes: std::slice::Iter<'a, u8>, -} - -fn convert_percent(iter: &mut std::slice::Iter) -> Option { - let mut cloned_iter = iter.clone(); - let result = match cloned_iter.next()? { - b'%' => b'%', - h => { - let h = char::from(*h).to_digit(16)?; - let l = char::from(*cloned_iter.next()?).to_digit(16)?; - h as u8 * 0x10 + l as u8 - } - }; - // Update this if we make it this far, otherwise "reset" the iterator. - *iter = cloned_iter; - Some(result) -} - -#[derive(Debug, PartialEq)] -pub enum UrlDecodeError { - InvalidPercentEncoding, -} - -impl fmt::Display for UrlDecodeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::InvalidPercentEncoding => write!(f, "invalid percent encoding"), - } - } -} - -impl<'a> Iterator for UrlDecode<'a> { - type Item = Result; - - fn next(&mut self) -> Option { - let b = self.bytes.next()?; - match b { - b'%' => Some( - convert_percent(&mut self.bytes) - .map(char::from) - .ok_or(UrlDecodeError::InvalidPercentEncoding), - ), - b'+' => Some(Ok(' ')), - x => Some(Ok(char::from(*x))), - } - } - - fn size_hint(&self) -> (usize, Option) { - let bytes = self.bytes.len(); - (bytes / 3, Some(bytes)) - } -} - -pub fn url_decode(url: &str) -> Result { - UrlDecode { - bytes: url.as_bytes().iter(), - } - .collect() -} From 7900be5c9e5621ef6c0a7448b3c4d8a6b1bdeb0f Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 16 Sep 2022 07:42:03 -0400 Subject: [PATCH 095/234] chore: deprecate optimizer (#313) --- .github/workflows/ci.yml | 27 +++------------------------ .github/workflows/examples.yml | 4 ++++ Cargo.toml | 1 - examples/build.sh | 4 ++-- src/ic-cdk-optimizer/CHANGELOG.md | 4 +++- src/ic-cdk-optimizer/Cargo.toml | 4 +++- src/ic-cdk-optimizer/README.md | 10 +++++++--- 7 files changed, 22 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ba2f65e8..534759602 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,26 +36,8 @@ jobs: target: wasm32-unknown-unknown - name: Run builds run: | - cargo build --workspace --exclude ic-cdk-optimizer --exclude ic-cdk-e2e-tests --target wasm32-unknown-unknown - cargo build --workspace --exclude ic-cdk-optimizer --exclude ic-cdk-e2e-tests --target wasm32-unknown-unknown --release - - build-ic-cdk-optimizer: - name: Build ic-cdk-optimizer - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - name: Install Rust - uses: dtolnay/rust-toolchain@v1 - with: - toolchain: ${{ env.rust-version }} - - name: Run builds - run: | - cargo build -p ic-cdk-optimizer + cargo build --workspace --exclude ic-cdk-e2e-tests --target wasm32-unknown-unknown + cargo build --workspace --exclude ic-cdk-e2e-tests --target wasm32-unknown-unknown --release test: name: cargo test @@ -143,15 +125,12 @@ jobs: aggregate: name: ci:required if: ${{ always() }} - needs: [build, build-ic-cdk-optimizer, test, fmt, clippy] + needs: [build, test, fmt, clippy] runs-on: ubuntu-latest steps: - name: check build result if: ${{ needs.build.result != 'success' }} run: exit 1 - - name: check build-ic-cdk-optimizer result - if: ${{ needs.build-ic-cdk-optimizer.result != 'success' }} - run: exit 1 - name: check test result if: ${{ needs.test.result != 'success' }} run: exit 1 diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 49729c79e..b38dfa192 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -44,6 +44,10 @@ jobs: target: wasm32-unknown-unknown components: rustfmt + - name: Install ic-wasm + run: | + cargo install ic-wasm + - name: Install DFX run: | export DFX_VERSION=${{env.dfx-version }} diff --git a/Cargo.toml b/Cargo.toml index 68e34c46e..115a59ca8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,6 @@ members = [ "src/ic-cdk", "src/ic-cdk-macros", - "src/ic-cdk-optimizer", "src/ic-certified-map", "src/ic-ledger-types", "e2e-tests", diff --git a/examples/build.sh b/examples/build.sh index 98a89b12a..e49c6fb6d 100755 --- a/examples/build.sh +++ b/examples/build.sh @@ -12,6 +12,6 @@ cargo build --manifest-path="$example_root/Cargo.toml" \ --release \ --package "$package" -cargo run --manifest-path="$root/Cargo.toml" --bin ic-cdk-optimizer -- \ +ic-wasm "$example_root/target/wasm32-unknown-unknown/release/$package.wasm" \ -o "$example_root/target/wasm32-unknown-unknown/release/$package-opt.wasm" \ - "$example_root/target/wasm32-unknown-unknown/release/$package.wasm" + shrink diff --git a/src/ic-cdk-optimizer/CHANGELOG.md b/src/ic-cdk-optimizer/CHANGELOG.md index 15c6a3f77..f6a8a7113 100644 --- a/src/ic-cdk-optimizer/CHANGELOG.md +++ b/src/ic-cdk-optimizer/CHANGELOG.md @@ -4,7 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.3.5] - 2022-09-15 +This is the final release of this deprecated tool. + ### Added - Specifying `-` as the input or output argument refers to stdin or stdout respectively (#230) diff --git a/src/ic-cdk-optimizer/Cargo.toml b/src/ic-cdk-optimizer/Cargo.toml index 9c368b735..f77a44b44 100644 --- a/src/ic-cdk-optimizer/Cargo.toml +++ b/src/ic-cdk-optimizer/Cargo.toml @@ -1,6 +1,8 @@ +[workspace] + [package] name = "ic-cdk-optimizer" -version = "0.3.4" +version = "0.3.5" authors = ["DFINITY Stiftung "] edition = "2021" description = "WASM Optimizer for the IC CDK (experimental)." diff --git a/src/ic-cdk-optimizer/README.md b/src/ic-cdk-optimizer/README.md index f316f1659..76678e926 100644 --- a/src/ic-cdk-optimizer/README.md +++ b/src/ic-cdk-optimizer/README.md @@ -1,4 +1,8 @@ -# ic-cdk-optimizer -Optimizer library to reduce the size of CDK WASMs. +# Deprecated +This tool is deprecated since Sep 2022. The last release of it was [v0.3.5](https://github.com/dfinity/cdk-rs/releases/tag/0.3.5). -Documentation TBD + +Use ic-wasm shrink instead to reduce size of WASM modules for Internet Computer. Check [ic-wasm](https://github.com/dfinity/ic-wasm) repo here. + +## ic-cdk-optimizer +Optimizer to reduce the size of CDK WASMs. From fea87965c21d7e67c334ce42a48d1b8a98ee8533 Mon Sep 17 00:00:00 2001 From: Frederik Rothenberger Date: Fri, 16 Sep 2022 17:51:37 +0200 Subject: [PATCH 096/234] chore: update outdated sha2 dependency of ic-certified-map (#314) * Update outdated sha2 dependency of ic-certified-map * fix CI * fix again Co-authored-by: Linwei Shang --- .github/workflows/examples.yml | 5 ++++- src/ic-certified-map/CHANGELOG.md | 4 ++++ src/ic-certified-map/Cargo.toml | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index b38dfa192..5d082cba2 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -45,8 +45,11 @@ jobs: components: rustfmt - name: Install ic-wasm + # might already in cache run: | - cargo install ic-wasm + if ! [ -x "$(command -v ic-wasm)" ]; then + cargo install ic-wasm + fi - name: Install DFX run: | diff --git a/src/ic-certified-map/CHANGELOG.md b/src/ic-certified-map/CHANGELOG.md index 48a02aede..4782c12d7 100644 --- a/src/ic-certified-map/CHANGELOG.md +++ b/src/ic-certified-map/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.1] - 2022-09-16 +### Changed +- Updated `sha2` dependency. + ## [0.3.0] - 2022-01-13 ### Added - `RbTree::iter()` method. diff --git a/src/ic-certified-map/Cargo.toml b/src/ic-certified-map/Cargo.toml index 6d0dec7c4..dd3273ab7 100644 --- a/src/ic-certified-map/Cargo.toml +++ b/src/ic-certified-map/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-certified-map" -version = "0.3.0" +version = "0.3.1" edition = "2021" authors = ["DFINITY Stiftung "] description = "Merkleized map data structure." @@ -17,7 +17,7 @@ rust-version = "1.60.0" [dependencies] serde = "1" serde_bytes = "0.11" -sha2 = "0.9" +sha2 = "0.10" [dev-dependencies] hex = "0.4" From 49c3ce1c9e2ebcbc58924499fbc18324b15290d2 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 19 Sep 2022 10:52:55 -0400 Subject: [PATCH 097/234] chore(ci): cancel previous CI run after new push (#315) --- .github/workflows/ci.yml | 4 ++++ .github/workflows/conventional-commits.yml | 5 +++++ .github/workflows/examples.yml | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 534759602..7f1c2d4e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,10 @@ on: - main pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: rust-version: 1.60.0 diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml index 34fd7c68d..f07b90291 100644 --- a/.github/workflows/conventional-commits.yml +++ b/.github/workflows/conventional-commits.yml @@ -1,4 +1,5 @@ name: Check PR title + on: pull_request_target: types: @@ -7,6 +8,10 @@ on: - edited - synchronize +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: check: runs-on: ubuntu-latest diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 5d082cba2..afc4653f6 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -6,6 +6,10 @@ on: - main pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: rust-version: 1.60.0 dfx-version: 0.11.1 From 4efff8e0060c9abefd839d53a2f894763549d93a Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 22 Sep 2022 09:36:24 -0400 Subject: [PATCH 098/234] refactor: move crates into library/ or legacy/ (#316) * mv to mod.rs * doc * mv ledger-types * mv certified-map * mv legacy * readme * fmt --- Cargo.toml | 4 ++-- README.md | 13 +++++++------ {src => legacy}/ic-cdk-optimizer/.gitignore | 0 {src => legacy}/ic-cdk-optimizer/CHANGELOG.md | 0 {src => legacy}/ic-cdk-optimizer/Cargo.toml | 0 {src => legacy}/ic-cdk-optimizer/LICENSE | 0 {src => legacy}/ic-cdk-optimizer/README.md | 0 {src => legacy}/ic-cdk-optimizer/src/main.rs | 0 {src => legacy}/ic-cdk-optimizer/src/passes.rs | 0 .../ic-cdk-optimizer/src/passes/binaryen.rs | 0 {src => legacy}/ic-certified-assets/README.md | 0 {src => library}/ic-certified-map/CHANGELOG.md | 0 {src => library}/ic-certified-map/Cargo.toml | 0 {src => library}/ic-certified-map/LICENSE | 0 {src => library}/ic-certified-map/README.md | 0 {src => library}/ic-certified-map/src/hashtree.rs | 0 .../ic-certified-map/src/hashtree/test.rs | 0 {src => library}/ic-certified-map/src/lib.rs | 0 {src => library}/ic-certified-map/src/rbtree.rs | 0 .../ic-certified-map/src/rbtree/test.rs | 0 {src => library}/ic-ledger-types/CHANGELOG.md | 0 {src => library}/ic-ledger-types/Cargo.toml | 2 +- {src => library}/ic-ledger-types/LICENSE | 0 {src => library}/ic-ledger-types/README.md | 0 {src => library}/ic-ledger-types/src/lib.rs | 0 src/ic-cdk/src/{api.rs => api/mod.rs} | 0 src/ic-cdk/src/api/{stable.rs => stable/mod.rs} | 7 +++++++ 27 files changed, 17 insertions(+), 9 deletions(-) rename {src => legacy}/ic-cdk-optimizer/.gitignore (100%) rename {src => legacy}/ic-cdk-optimizer/CHANGELOG.md (100%) rename {src => legacy}/ic-cdk-optimizer/Cargo.toml (100%) rename {src => legacy}/ic-cdk-optimizer/LICENSE (100%) rename {src => legacy}/ic-cdk-optimizer/README.md (100%) rename {src => legacy}/ic-cdk-optimizer/src/main.rs (100%) rename {src => legacy}/ic-cdk-optimizer/src/passes.rs (100%) rename {src => legacy}/ic-cdk-optimizer/src/passes/binaryen.rs (100%) rename {src => legacy}/ic-certified-assets/README.md (100%) rename {src => library}/ic-certified-map/CHANGELOG.md (100%) rename {src => library}/ic-certified-map/Cargo.toml (100%) rename {src => library}/ic-certified-map/LICENSE (100%) rename {src => library}/ic-certified-map/README.md (100%) rename {src => library}/ic-certified-map/src/hashtree.rs (100%) rename {src => library}/ic-certified-map/src/hashtree/test.rs (100%) rename {src => library}/ic-certified-map/src/lib.rs (100%) rename {src => library}/ic-certified-map/src/rbtree.rs (100%) rename {src => library}/ic-certified-map/src/rbtree/test.rs (100%) rename {src => library}/ic-ledger-types/CHANGELOG.md (100%) rename {src => library}/ic-ledger-types/Cargo.toml (93%) rename {src => library}/ic-ledger-types/LICENSE (100%) rename {src => library}/ic-ledger-types/README.md (100%) rename {src => library}/ic-ledger-types/src/lib.rs (100%) rename src/ic-cdk/src/{api.rs => api/mod.rs} (100%) rename src/ic-cdk/src/api/{stable.rs => stable/mod.rs} (97%) diff --git a/Cargo.toml b/Cargo.toml index 115a59ca8..6315db62a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,8 +2,8 @@ members = [ "src/ic-cdk", "src/ic-cdk-macros", - "src/ic-certified-map", - "src/ic-ledger-types", + "library/ic-certified-map", + "library/ic-ledger-types", "e2e-tests", ] diff --git a/README.md b/README.md index cc72e2ee7..defbd7b19 100644 --- a/README.md +++ b/README.md @@ -22,17 +22,18 @@ you may want to check [agent-rs](https://github.com/dfinity/agent-rs). A `canister` is a WebAssembly (wasm) module that can run on the Internet Computer. -To be a `canister`, a wasm module should communicate with the execution environment using [Canister interfaces (System API)](https://sdk.dfinity.org/docs/interface-spec/index.html#system-api). +To be a `canister`, a wasm module should communicate with the execution environment using [Canister interfaces (System API)](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api). This repo provides libraries and tools to facilitate developing canisters in Rust. -- [`ic-cdk`](https://github.com/dfinity/cdk-rs/tree/main/src/ic-cdk): +- [`ic-cdk`](src/ic-cdk): Bindings of the System API. -- [`ic-cdk-macros`](https://github.com/dfinity/cdk-rs/tree/main/src/ic-cdk-macros): +- [`ic-cdk-macros`](src/ic-cdk-macros): Annotate functions with attribute macros to make them exposed public interfaces. -- [`ic-cdk-optimizer`](https://github.com/dfinity/cdk-rs/tree/main/src/ic-cdk-optimizer): -A binary tool to reduing size of the compiled wasm module. -- [`ic-certified-map`](https://github.com/dfinity/cdk-rs/tree/main/src/ic-certified-map): An implementation of map which support *certified queries*. +- [`ic-certified-map`](library/ic-certified-map): +An implementation of map which support *certified queries*. +- [`ic-ledger-types`](library/ic-ledger-types): +Type definitions to communicate with the ICP ledger canister. ## Rust CDK in Action diff --git a/src/ic-cdk-optimizer/.gitignore b/legacy/ic-cdk-optimizer/.gitignore similarity index 100% rename from src/ic-cdk-optimizer/.gitignore rename to legacy/ic-cdk-optimizer/.gitignore diff --git a/src/ic-cdk-optimizer/CHANGELOG.md b/legacy/ic-cdk-optimizer/CHANGELOG.md similarity index 100% rename from src/ic-cdk-optimizer/CHANGELOG.md rename to legacy/ic-cdk-optimizer/CHANGELOG.md diff --git a/src/ic-cdk-optimizer/Cargo.toml b/legacy/ic-cdk-optimizer/Cargo.toml similarity index 100% rename from src/ic-cdk-optimizer/Cargo.toml rename to legacy/ic-cdk-optimizer/Cargo.toml diff --git a/src/ic-cdk-optimizer/LICENSE b/legacy/ic-cdk-optimizer/LICENSE similarity index 100% rename from src/ic-cdk-optimizer/LICENSE rename to legacy/ic-cdk-optimizer/LICENSE diff --git a/src/ic-cdk-optimizer/README.md b/legacy/ic-cdk-optimizer/README.md similarity index 100% rename from src/ic-cdk-optimizer/README.md rename to legacy/ic-cdk-optimizer/README.md diff --git a/src/ic-cdk-optimizer/src/main.rs b/legacy/ic-cdk-optimizer/src/main.rs similarity index 100% rename from src/ic-cdk-optimizer/src/main.rs rename to legacy/ic-cdk-optimizer/src/main.rs diff --git a/src/ic-cdk-optimizer/src/passes.rs b/legacy/ic-cdk-optimizer/src/passes.rs similarity index 100% rename from src/ic-cdk-optimizer/src/passes.rs rename to legacy/ic-cdk-optimizer/src/passes.rs diff --git a/src/ic-cdk-optimizer/src/passes/binaryen.rs b/legacy/ic-cdk-optimizer/src/passes/binaryen.rs similarity index 100% rename from src/ic-cdk-optimizer/src/passes/binaryen.rs rename to legacy/ic-cdk-optimizer/src/passes/binaryen.rs diff --git a/src/ic-certified-assets/README.md b/legacy/ic-certified-assets/README.md similarity index 100% rename from src/ic-certified-assets/README.md rename to legacy/ic-certified-assets/README.md diff --git a/src/ic-certified-map/CHANGELOG.md b/library/ic-certified-map/CHANGELOG.md similarity index 100% rename from src/ic-certified-map/CHANGELOG.md rename to library/ic-certified-map/CHANGELOG.md diff --git a/src/ic-certified-map/Cargo.toml b/library/ic-certified-map/Cargo.toml similarity index 100% rename from src/ic-certified-map/Cargo.toml rename to library/ic-certified-map/Cargo.toml diff --git a/src/ic-certified-map/LICENSE b/library/ic-certified-map/LICENSE similarity index 100% rename from src/ic-certified-map/LICENSE rename to library/ic-certified-map/LICENSE diff --git a/src/ic-certified-map/README.md b/library/ic-certified-map/README.md similarity index 100% rename from src/ic-certified-map/README.md rename to library/ic-certified-map/README.md diff --git a/src/ic-certified-map/src/hashtree.rs b/library/ic-certified-map/src/hashtree.rs similarity index 100% rename from src/ic-certified-map/src/hashtree.rs rename to library/ic-certified-map/src/hashtree.rs diff --git a/src/ic-certified-map/src/hashtree/test.rs b/library/ic-certified-map/src/hashtree/test.rs similarity index 100% rename from src/ic-certified-map/src/hashtree/test.rs rename to library/ic-certified-map/src/hashtree/test.rs diff --git a/src/ic-certified-map/src/lib.rs b/library/ic-certified-map/src/lib.rs similarity index 100% rename from src/ic-certified-map/src/lib.rs rename to library/ic-certified-map/src/lib.rs diff --git a/src/ic-certified-map/src/rbtree.rs b/library/ic-certified-map/src/rbtree.rs similarity index 100% rename from src/ic-certified-map/src/rbtree.rs rename to library/ic-certified-map/src/rbtree.rs diff --git a/src/ic-certified-map/src/rbtree/test.rs b/library/ic-certified-map/src/rbtree/test.rs similarity index 100% rename from src/ic-certified-map/src/rbtree/test.rs rename to library/ic-certified-map/src/rbtree/test.rs diff --git a/src/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md similarity index 100% rename from src/ic-ledger-types/CHANGELOG.md rename to library/ic-ledger-types/CHANGELOG.md diff --git a/src/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml similarity index 93% rename from src/ic-ledger-types/Cargo.toml rename to library/ic-ledger-types/Cargo.toml index efd107fc1..39608e35f 100644 --- a/src/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -17,7 +17,7 @@ rust-version = "1.60.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ic-cdk = { path = "../ic-cdk", version = "0.5" } +ic-cdk = { path = "../../src/ic-cdk", version = "0.5" } candid = "0.7.15" crc32fast = "1.2.0" hex = "0.4" diff --git a/src/ic-ledger-types/LICENSE b/library/ic-ledger-types/LICENSE similarity index 100% rename from src/ic-ledger-types/LICENSE rename to library/ic-ledger-types/LICENSE diff --git a/src/ic-ledger-types/README.md b/library/ic-ledger-types/README.md similarity index 100% rename from src/ic-ledger-types/README.md rename to library/ic-ledger-types/README.md diff --git a/src/ic-ledger-types/src/lib.rs b/library/ic-ledger-types/src/lib.rs similarity index 100% rename from src/ic-ledger-types/src/lib.rs rename to library/ic-ledger-types/src/lib.rs diff --git a/src/ic-cdk/src/api.rs b/src/ic-cdk/src/api/mod.rs similarity index 100% rename from src/ic-cdk/src/api.rs rename to src/ic-cdk/src/api/mod.rs diff --git a/src/ic-cdk/src/api/stable.rs b/src/ic-cdk/src/api/stable/mod.rs similarity index 97% rename from src/ic-cdk/src/api/stable.rs rename to src/ic-cdk/src/api/stable/mod.rs index 3c291491a..741fc866f 100644 --- a/src/ic-cdk/src/api/stable.rs +++ b/src/ic-cdk/src/api/stable/mod.rs @@ -276,6 +276,13 @@ impl StableReader { } /// Reads data from the stable memory location specified by an offset. + /// + /// Note: + /// The stable memory size is cached on creation of the StableReader. + /// Therefore, in following scenario, it will get an `OutOfBounds` error: + /// 1. Create a StableReader + /// 2. Write some data to the stable memory which causes it grow + /// 3. call `read()` to read the newly written bytes pub fn read(&mut self, buf: &mut [u8]) -> Result { let capacity_bytes = self.capacity as usize * WASM_PAGE_SIZE_IN_BYTES; let read_buf = if buf.len() + self.offset > capacity_bytes { From fd396aba683bd6397d25c6d9f40de4cde9454e0d Mon Sep 17 00:00:00 2001 From: QJ Yu <79867586+qj-yu@users.noreply.github.com> Date: Mon, 26 Sep 2022 18:43:53 -0700 Subject: [PATCH 099/234] fix: Update http_request transform type. (#312) * Update http_request transform type. * update changelog * fix tests * import candid * fix management_canister and test * simplify examples * changelog * ctor * from_transform_function * fix doc Co-authored-by: Linwei Shang --- .github/workflows/examples.yml | 2 +- examples/asset_storage/tests/basic.bats | 6 +- examples/chess/tests/basic.bats | 6 +- examples/counter/tests/basic.bats | 6 +- .../management_canister/src/caller/lib.rs | 35 +++--- examples/management_canister/tests/basic.bats | 8 +- examples/profile/tests/basic.bats | 6 +- src/ic-cdk/CHANGELOG.md | 4 +- src/ic-cdk/src/api/call.rs | 2 +- .../api/management_canister/bitcoin/types.rs | 10 +- .../api/management_canister/http_request.rs | 100 +++++++++++++++--- .../src/api/management_canister/main/types.rs | 10 +- 12 files changed, 128 insertions(+), 67 deletions(-) diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index afc4653f6..90fc5481d 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -12,7 +12,7 @@ concurrency: env: rust-version: 1.60.0 - dfx-version: 0.11.1 + dfx-version: 0.12.0-beta.3 jobs: test: diff --git a/examples/asset_storage/tests/basic.bats b/examples/asset_storage/tests/basic.bats index 08df3a0bd..72c64f553 100644 --- a/examples/asset_storage/tests/basic.bats +++ b/examples/asset_storage/tests/basic.bats @@ -2,10 +2,7 @@ setup() { cd examples/asset_storage # Make sure the directory is clean. - dfx start --clean --background --host "127.0.0.1:0" - local webserver_port=$(cat .dfx/webserver-port) - cp dfx.json dfx.json.bk - cat <<<$(jq .networks.local.bind=\"127.0.0.1:${webserver_port}\" dfx.json) >dfx.json + dfx start --clean --background run dfx identity new alice --disable-encryption run dfx identity new bob --disable-encryption @@ -15,7 +12,6 @@ setup() { # executed after each test teardown() { dfx stop - mv dfx.json.bk dfx.json } @test "Can store and restore assets" { diff --git a/examples/chess/tests/basic.bats b/examples/chess/tests/basic.bats index f1ee962cf..9adc19f0c 100644 --- a/examples/chess/tests/basic.bats +++ b/examples/chess/tests/basic.bats @@ -4,16 +4,12 @@ setup() { # Make sure the directory is clean. npm install - dfx start --clean --background --host "127.0.0.1:0" - local webserver_port=$(cat .dfx/webserver-port) - cp dfx.json dfx.json.bk - cat <<<$(jq .networks.local.bind=\"127.0.0.1:${webserver_port}\" dfx.json) >dfx.json + dfx start --clean --background } # executed after each test teardown() { dfx stop - mv dfx.json.bk dfx.json } @test "Can play chess against AI" { diff --git a/examples/counter/tests/basic.bats b/examples/counter/tests/basic.bats index a26136c2e..83c1f75e3 100644 --- a/examples/counter/tests/basic.bats +++ b/examples/counter/tests/basic.bats @@ -2,16 +2,12 @@ setup() { cd examples/counter # Make sure the directory is clean. - dfx start --clean --background --host "127.0.0.1:0" - local webserver_port=$(cat .dfx/webserver-port) - cp dfx.json dfx.json.bk - cat <<<$(jq .networks.local.bind=\"127.0.0.1:${webserver_port}\" dfx.json) >dfx.json + dfx start --clean --background } # executed after each test teardown() { dfx stop - mv dfx.json.bk dfx.json } @test "Can counter (counter_rs)" { diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index 049c481d3..c294c969c 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -7,8 +7,8 @@ mod main { async fn execute_main_methods() { let arg = CreateCanisterArgument { settings: Some(CanisterSettings { - controllers: Some(vec![ic_cdk::caller()]), - compute_allocation: Some(50.into()), + controllers: Some(vec![ic_cdk::id()]), + compute_allocation: Some(0.into()), memory_allocation: Some(10000.into()), freezing_threshold: Some(10000.into()), }), @@ -83,10 +83,10 @@ mod http_request { let arg = CanisterHttpRequestArgument { url, max_response_bytes: Some(3000), - http_method: HttpMethod::GET, + method: HttpMethod::GET, headers: vec![], body: None, - transform_method_name: Some("transform".to_string()), + transform: Some(TransformType::from_transform_function(transform)), }; let response = http_request(arg).await.unwrap().0; assert_eq!(response.status, 200); @@ -101,7 +101,7 @@ mod http_request { // transform function must be a *query* method of the canister #[query] - async fn transform(arg: HttpResponse) -> HttpResponse { + fn transform(arg: HttpResponse) -> HttpResponse { HttpResponse { headers: vec![HttpHeader { name: "custom-header".to_string(), @@ -160,25 +160,26 @@ mod bitcoin { let arg = GetBalanceRequest { address: address.clone(), network, - min_confirmations: Some(3), + min_confirmations: Some(1), }; let _balance = bitcoin_get_balance(arg).await.unwrap().0; let arg = GetUtxosRequest { address: address.clone(), network, - filter: Some(UtxoFilter::MinConfirmations(6)), + filter: Some(UtxoFilter::MinConfirmations(1)), }; - let _response = bitcoin_get_utxos(arg).await.unwrap().0; - - // TODO: turn on following test when new dfx has replica support it. - - // let arg = GetUtxosRequest { - // address: address.clone(), - // network, - // filter: Some(UtxoFilter::Page(vec![])), - // }; - // let _response = bitcoin_get_utxos(arg).await.unwrap().0; + let mut response = bitcoin_get_utxos(arg).await.unwrap().0; + + while let Some(page) = response.next_page { + ic_cdk::println!("bitcoin_get_utxos next page"); + let arg = GetUtxosRequest { + address: address.clone(), + network, + filter: Some(UtxoFilter::Page(page)), + }; + response = bitcoin_get_utxos(arg).await.unwrap().0; + } let arg = GetCurrentFeePercentilesRequest { network }; let _percentiles = bitcoin_get_current_fee_percentiles(arg).await.unwrap().0; diff --git a/examples/management_canister/tests/basic.bats b/examples/management_canister/tests/basic.bats index 3e47c6642..2308ec79e 100644 --- a/examples/management_canister/tests/basic.bats +++ b/examples/management_canister/tests/basic.bats @@ -3,17 +3,13 @@ setup() { cd examples/management_canister bitcoind -regtest -daemonwait # Make sure the directory is clean. - dfx start --clean --background --host "127.0.0.1:0" - local webserver_port=$(cat .dfx/webserver-port) - cp dfx.json dfx.json.bk - cat <<<$(jq .networks.local.bind=\"127.0.0.1:${webserver_port}\" dfx.json) >dfx.json + dfx start --clean --background } # executed after each test teardown() { dfx stop bitcoin-cli -regtest stop - mv dfx.json.bk dfx.json } @test "All management canister methods succeed" { @@ -21,6 +17,6 @@ teardown() { run dfx canister call caller execute_main_methods run dfx canister call caller execute_provisional_methods run dfx canister call caller http_request_example - run dfx canister call caller execute_threshold_ecdsa_methods + run dfx canister call caller execute_ecdsa_methods run dfx canister call caller execute_bitcoin_methods } diff --git a/examples/profile/tests/basic.bats b/examples/profile/tests/basic.bats index 91690c1d6..6b016151f 100644 --- a/examples/profile/tests/basic.bats +++ b/examples/profile/tests/basic.bats @@ -2,16 +2,12 @@ setup() { cd examples/profile # Make sure the directory is clean. - dfx start --clean --background --host "127.0.0.1:0" - local webserver_port=$(cat .dfx/webserver-port) - cp dfx.json dfx.json.bk - cat <<<$(jq .networks.local.bind=\"127.0.0.1:${webserver_port}\" dfx.json) >dfx.json + dfx start --clean --background } # executed after each test teardown() { dfx stop - mv dfx.json.bk dfx.json } @test "Can get, update, search (profile_rs)" { diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index c8946fd2d..07bf8166b 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Fixed +- overhaul management canister, especially `transform` type in `http_request` (#312) + ## [0.5.6] - 2022-08-10 ### Added @@ -14,7 +17,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `ManualReply::reject` function (#297) ### Fixed - - Failure to decode the reply in `ic_cdk::call` does not trap anymore (#301) ## [0.5.5] - 2022-07-22 diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index d71662057..c7ca15485 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -407,7 +407,7 @@ fn decoder_error_to_reject(err: candid::error::Error) -> (RejectionCode, Stri /// Performs an asynchronous call to another canister using the [System API](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-call). /// -/// If the reply payload is not a valid encoding of the expected type [T], +/// If the reply payload is not a valid encoding of the expected type `T`, /// the call results in [RejectionCode::CanisterError] error. pub fn call ArgumentDecoder<'a>>( id: Principal, diff --git a/src/ic-cdk/src/api/management_canister/bitcoin/types.rs b/src/ic-cdk/src/api/management_canister/bitcoin/types.rs index 10b826584..776b45f16 100644 --- a/src/ic-cdk/src/api/management_canister/bitcoin/types.rs +++ b/src/ic-cdk/src/api/management_canister/bitcoin/types.rs @@ -9,13 +9,16 @@ pub type Satoshi = u64; CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, )] pub enum BitcoinNetwork { - // TODO: The variants are Capitalized while they are lowercase in the spec /// Mainnet. + #[serde(rename = "mainnet")] Mainnet, /// Testnet. + #[serde(rename = "testnet")] Testnet, - // TODO: the spec doesn't have this type of network /// Regtest. + /// + /// This is only available when developing with local replica. + #[serde(rename = "regtest")] Regtest, } @@ -63,13 +66,14 @@ pub struct Utxo { CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, )] pub enum UtxoFilter { - // TODO: In the spec, variants are in snake case /// Minimum number of confirmations. There is an upper bound of 144. Typically set to a value around 6 in practice. + #[serde(rename = "min_confirmations")] MinConfirmations(u32), /// Page reference. /// /// DON'T construct it from scratch. /// Only get it from the `next_page` field of [GetUtxosResponse]. + #[serde(rename = "page")] Page(Vec), } diff --git a/src/ic-cdk/src/api/management_canister/http_request.rs b/src/ic-cdk/src/api/management_canister/http_request.rs index bd7882bce..13a3f5477 100644 --- a/src/ic-cdk/src/api/management_canister/http_request.rs +++ b/src/ic-cdk/src/api/management_canister/http_request.rs @@ -1,9 +1,73 @@ //! Canister HTTP request. use crate::api::call::{call_with_payment128, CallResult}; -use candid::{CandidType, Principal}; +use candid::{ + parser::types::FuncMode, + types::{Function, Serializer, Type}, + CandidType, Principal, +}; +use core::hash::Hash; use serde::{Deserialize, Serialize}; +/// "transform" function of type: `func (http_response) -> (http_response) query` +#[derive(Deserialize, Debug, PartialEq, Clone)] +pub struct TransformFunc(pub candid::Func); + +impl CandidType for TransformFunc { + fn _ty() -> Type { + Type::Func(Function { + modes: vec![FuncMode::Query], + args: vec![HttpResponse::ty()], + rets: vec![HttpResponse::ty()], + }) + } + + fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> { + serializer.serialize_function(self.0.principal.as_slice(), &self.0.method) + } +} + +/// "transform" reference function type: +/// `opt variant { function: func (http_response) -> (http_response) query }` +#[derive(CandidType, Deserialize, Debug, PartialEq, Clone)] +pub enum TransformType { + /// reference function with signature: `func (http_response) -> (http_response) query` + #[serde(rename = "function")] + Function(TransformFunc), +} + +impl TransformType { + /// Construct `TransformType` from a transform function. + /// + /// # example + /// + /// ```ignore + /// #[ic_cdk_macros::query] + /// fn my_transform(arg: HttpResponse) -> HttpResponse { + /// ... + /// } + /// + /// let transform = TransformType::from_transform_function(my_transform); + /// ``` + pub fn from_transform_function(func: T) -> Self + where + T: Fn(HttpResponse) -> HttpResponse, + { + Self::Function(TransformFunc(candid::Func { + principal: crate::id(), + method: get_function_name(func).to_string(), + })) + } +} + +fn get_function_name(_: F) -> &'static str { + let full_name = std::any::type_name::(); + match full_name.rfind(':') { + Some(index) => &full_name[index + 1..], + None => full_name, + } +} + /// HTTP header. #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, @@ -23,32 +87,31 @@ pub struct HttpHeader { )] pub enum HttpMethod { /// GET + #[serde(rename = "get")] GET, /// POST + #[serde(rename = "post")] POST, /// HEAD + #[serde(rename = "head")] HEAD, } /// Argument type of [http_request]. -#[derive( - CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, -)] +#[derive(CandidType, Deserialize, Debug, PartialEq, Clone)] pub struct CanisterHttpRequestArgument { /// The requested URL. pub url: String, /// The maximal size of the response in bytes. If None, 2MiB will be the limit. pub max_response_bytes: Option, - // TODO: Different name in the Spec. /// The method of HTTP request. - pub http_method: HttpMethod, + pub method: HttpMethod, /// List of HTTP request headers and their corresponding values. pub headers: Vec, /// Optionally provide request body. pub body: Option>, - // TODO: Here is a discrepancy between System API and the implementation. /// Name of the transform function which is `func (http_response) -> (http_response) query`. - pub transform_method_name: Option, + pub transform: Option, } /// The returned HTTP response. @@ -56,9 +119,8 @@ pub struct CanisterHttpRequestArgument { CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, )] pub struct HttpResponse { - // TODO: Different type in the Spec. /// The response status (e.g., 200, 404). - pub status: u64, + pub status: candid::Nat, /// List of HTTP response headers and their corresponding values. pub headers: Vec, /// The response’s body. @@ -103,12 +165,12 @@ mod tests { let arg = CanisterHttpRequestArgument { url, max_response_bytes: Some(3000), - http_method: HttpMethod::GET, + method: HttpMethod::GET, headers: vec![], body: None, - transform_method_name: None, + transform: None, }; - assert_eq!(http_request_required_cycles(&arg), 713100000u128); + assert_eq!(http_request_required_cycles(&arg), 716500000u128); } #[test] @@ -117,11 +179,17 @@ mod tests { let arg = CanisterHttpRequestArgument { url, max_response_bytes: None, - http_method: HttpMethod::GET, + method: HttpMethod::GET, headers: vec![], body: None, - transform_method_name: None, + transform: None, }; - assert_eq!(http_request_required_cycles(&arg), 210127500000u128); + assert_eq!(http_request_required_cycles(&arg), 210130900000u128); + } + + #[test] + fn get_function_name_work() { + fn func() {} + assert_eq!(get_function_name(func), "func"); } } diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index adf54702e..478024a1f 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -45,13 +45,16 @@ pub struct UpdateSettingsArgument { #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, )] -#[serde(rename_all = "lowercase")] +// #[serde(rename_all = "lowercase")] pub enum CanisterInstallMode { /// A fresh install of a new canister. + #[serde(rename = "install")] Install, /// Reinstalling a canister that was already installed. + #[serde(rename = "reinstall")] Reinstall, /// Upgrade an existing canister. + #[serde(rename = "upgrade")] Upgrade, } @@ -86,13 +89,16 @@ pub struct CanisterIdRecord { #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, )] -#[serde(rename_all = "lowercase")] +// #[serde(rename_all = "lowercase")] pub enum CanisterStatusType { /// The canister is running. + #[serde(rename = "running")] Running, /// The canister is stopping. + #[serde(rename = "stopping")] Stopping, /// The canister is stopped. + #[serde(rename = "stopped")] Stopped, } From 9ee66f23b7dbd2882bc0e98f133efa2d4bf4d87f Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 27 Sep 2022 12:55:27 -0400 Subject: [PATCH 100/234] chore: release ic-cdk v0.5.7 (#318) --- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 2 ++ src/ic-cdk/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 86e638e07..ddbc8b426 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.5.6" +version = "0.5.7" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 07bf8166b..4e9d06a79 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.5.7] - 2022-09-27 + ### Fixed - overhaul management canister, especially `transform` type in `http_request` (#312) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index b665914c0..7a27e7423 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.5.6" +version = "0.5.7" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." From c7aaaddaaf5e39c90a51035f87be68a0215c8c10 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 3 Oct 2022 15:05:33 -0400 Subject: [PATCH 101/234] feat: upgrade candid to 0.8.0 (#321) * chore!: upgrade candid to 0.8.0 * fmt * date --- README.md | 6 +++--- e2e-tests/Cargo.toml | 2 +- e2e-tests/canisters/async.rs | 2 +- e2e-tests/tests/e2e.rs | 6 ++++-- examples/asset_storage/src/asset_storage_rs/Cargo.toml | 4 ++-- examples/chess/src/chess_rs/Cargo.toml | 6 +++--- examples/counter/src/counter_rs/Cargo.toml | 6 +++--- examples/counter/src/inter2_rs/Cargo.toml | 6 +++--- examples/counter/src/inter_rs/Cargo.toml | 6 +++--- examples/management_canister/src/caller/Cargo.toml | 4 ++-- examples/print/src/print_rs/Cargo.toml | 4 ++-- examples/profile/src/profile_inter_rs/Cargo.toml | 6 +++--- examples/profile/src/profile_rs/Cargo.toml | 6 +++--- library/ic-ledger-types/Cargo.toml | 4 ++-- src/ic-cdk-macros/Cargo.toml | 6 +++--- src/ic-cdk/CHANGELOG.md | 8 +++++++- src/ic-cdk/Cargo.toml | 4 ++-- src/ic-cdk/src/api/call.rs | 3 +-- src/ic-cdk/src/api/mod.rs | 2 +- src/ic-cdk/src/lib.rs | 2 +- 20 files changed, 50 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index defbd7b19..78828c317 100644 --- a/README.md +++ b/README.md @@ -44,9 +44,9 @@ In Cargo.toml: crate-type = ["cdylib"] [dependencies] -candid = "0.7.16" # this is required if you want to use the `#[import]` macro -ic-cdk = "0.5" -ic-cdk-macros = "0.5" +candid = "0.8.0" # this is required if you want to use the `#[import]` macro +ic-cdk = "0.6" +ic-cdk-macros = "0.6" ``` Then in your rust source code: diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index f8332f79b..a826deb1e 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -8,7 +8,6 @@ license = "Apache-2.0" repository = "https://github.com/dfinity/cdk-rs" [dependencies] -candid = "0.7.4" cargo_metadata = "0.14.2" escargot = { version = "0.5.7", features = ["print"] } ic-cdk = { path = "../src/ic-cdk" } @@ -34,3 +33,4 @@ path = "canisters/api_call.rs" [dev-dependencies] ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "02a4a828f2f4d3b1dcb93a84e60672a3f3fdb400" } +candid_legecy = { package = "candid", version = "0.7.18" } diff --git a/e2e-tests/canisters/async.rs b/e2e-tests/canisters/async.rs index 33a886dc0..c24db8df5 100644 --- a/e2e-tests/canisters/async.rs +++ b/e2e-tests/canisters/async.rs @@ -1,4 +1,4 @@ -use candid::Principal; +use ic_cdk::export::Principal; use ic_cdk_macros::{query, update}; use lazy_static::lazy_static; use std::sync::RwLock; diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 9fc6556b2..a05764609 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -1,5 +1,7 @@ -use candid::utils::{decode_args, encode_args, ArgumentDecoder, ArgumentEncoder}; -use candid::Encode; +// use ic_cdk::export::candid::utils::{decode_args, encode_args, ArgumentDecoder, ArgumentEncoder}; +// use ic_cdk::export::candid::Encode; +use candid_legecy::utils::{decode_args, encode_args, ArgumentDecoder, ArgumentEncoder}; +use candid_legecy::Encode; use ic_cdk_e2e_tests::cargo_build_canister; use ic_state_machine_tests::{CanisterId, ErrorCode, StateMachine, UserError, WasmResult}; use serde_bytes::ByteBuf; diff --git a/examples/asset_storage/src/asset_storage_rs/Cargo.toml b/examples/asset_storage/src/asset_storage_rs/Cargo.toml index 715975203..b6baf50de 100644 --- a/examples/asset_storage/src/asset_storage_rs/Cargo.toml +++ b/examples/asset_storage/src/asset_storage_rs/Cargo.toml @@ -11,5 +11,5 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } +ic-cdk = { path = "../../../../src/ic-cdk" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } diff --git a/examples/chess/src/chess_rs/Cargo.toml b/examples/chess/src/chess_rs/Cargo.toml index 3a9a69be1..f1d0a01f1 100644 --- a/examples/chess/src/chess_rs/Cargo.toml +++ b/examples/chess/src/chess_rs/Cargo.toml @@ -11,8 +11,8 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.7.15" -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } +candid = "0.8.0" +ic-cdk = { path = "../../../../src/ic-cdk" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } serde = "1.0.111" pleco = "0.5.0" diff --git a/examples/counter/src/counter_rs/Cargo.toml b/examples/counter/src/counter_rs/Cargo.toml index c88c4ac66..905b5a8e4 100644 --- a/examples/counter/src/counter_rs/Cargo.toml +++ b/examples/counter/src/counter_rs/Cargo.toml @@ -11,7 +11,7 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.7.15" -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } +candid = "0.8.0" +ic-cdk = { path = "../../../../src/ic-cdk" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } lazy_static = "1.4.0" diff --git a/examples/counter/src/inter2_rs/Cargo.toml b/examples/counter/src/inter2_rs/Cargo.toml index d6bcf142a..6aec3b5ae 100644 --- a/examples/counter/src/inter2_rs/Cargo.toml +++ b/examples/counter/src/inter2_rs/Cargo.toml @@ -11,6 +11,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.7.15" -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } +candid = "0.8.0" +ic-cdk = { path = "../../../../src/ic-cdk" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } diff --git a/examples/counter/src/inter_rs/Cargo.toml b/examples/counter/src/inter_rs/Cargo.toml index e80f06ee0..8bed7e26b 100644 --- a/examples/counter/src/inter_rs/Cargo.toml +++ b/examples/counter/src/inter_rs/Cargo.toml @@ -11,6 +11,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.7.15" -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } +candid = "0.8.0" +ic-cdk = { path = "../../../../src/ic-cdk" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } diff --git a/examples/management_canister/src/caller/Cargo.toml b/examples/management_canister/src/caller/Cargo.toml index 89a08e6f5..6f5097ef1 100644 --- a/examples/management_canister/src/caller/Cargo.toml +++ b/examples/management_canister/src/caller/Cargo.toml @@ -10,6 +10,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } +ic-cdk = { path = "../../../../src/ic-cdk" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } sha2 = "0.10" diff --git a/examples/print/src/print_rs/Cargo.toml b/examples/print/src/print_rs/Cargo.toml index cf6d0587f..a7b8a65ad 100644 --- a/examples/print/src/print_rs/Cargo.toml +++ b/examples/print/src/print_rs/Cargo.toml @@ -11,6 +11,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } +ic-cdk = { path = "../../../../src/ic-cdk" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } diff --git a/examples/profile/src/profile_inter_rs/Cargo.toml b/examples/profile/src/profile_inter_rs/Cargo.toml index 0b5b54c28..14bfa6245 100644 --- a/examples/profile/src/profile_inter_rs/Cargo.toml +++ b/examples/profile/src/profile_inter_rs/Cargo.toml @@ -11,6 +11,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.7.15" -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } +candid = "0.8.0" +ic-cdk = { path = "../../../../src/ic-cdk" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } diff --git a/examples/profile/src/profile_rs/Cargo.toml b/examples/profile/src/profile_rs/Cargo.toml index 62753b197..ec92c8c76 100644 --- a/examples/profile/src/profile_rs/Cargo.toml +++ b/examples/profile/src/profile_rs/Cargo.toml @@ -11,7 +11,7 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.7.15" -ic-cdk = { path = "../../../../src/ic-cdk", version = "0.5" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros", version = "0.5" } +candid = "0.8.0" +ic-cdk = { path = "../../../../src/ic-cdk" } +ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } serde = "1.0.111" diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 39608e35f..e2718cb0c 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -17,8 +17,8 @@ rust-version = "1.60.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ic-cdk = { path = "../../src/ic-cdk", version = "0.5" } -candid = "0.7.15" +ic-cdk = { path = "../../src/ic-cdk" } +candid = "0.8.0" crc32fast = "1.2.0" hex = "0.4" serde = "1" diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index ddbc8b426..af63b472e 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.5.7" +version = "0.6.0" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." @@ -18,8 +18,8 @@ rust-version = "1.60.0" proc-macro = true [dependencies] -candid = "0.7.15" -ic-cdk = { path = "../ic-cdk", version = "0.5" } +candid = "0.8.0" +ic-cdk = { path = "../ic-cdk", version = "0.6" } syn = { version = "1.0.58", features = ["fold", "full"] } quote = "1.0" proc-macro2 = "1.0" diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 4e9d06a79..17e5cc94c 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,10 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.6.0] - 2022-10-03 + +### Changed + +- Upgrade `candid` to `0.8.0` (#321) + ## [0.5.7] - 2022-09-27 ### Fixed -- overhaul management canister, especially `transform` type in `http_request` (#312) +- Overhaul management canister, especially `transform` type in `http_request` (#312) ## [0.5.6] - 2022-08-10 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 7a27e7423..8fd7345e2 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.5.7" +version = "0.6.0" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." @@ -15,7 +15,7 @@ repository = "https://github.com/dfinity/cdk-rs" rust-version = "1.60.0" [dependencies] -candid = "0.7.15" +candid = "0.8" cfg-if = "1.0.0" serde = "1.0.110" diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index c7ca15485..d2860448d 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -1,8 +1,7 @@ //! APIs to make and manage calls in the canister. use crate::api::{ic0, trap}; -use crate::export::Principal; use candid::utils::{ArgumentDecoder, ArgumentEncoder}; -use candid::{decode_args, encode_args, write_args, CandidType, Deserialize}; +use candid::{decode_args, encode_args, write_args, CandidType, Deserialize, Principal}; use serde::ser::Error; use std::future::Future; use std::marker::PhantomData; diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index eb45edf88..433ddc305 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -1,5 +1,5 @@ //! System API and low level functions for it. -use crate::export::Principal; +use candid::Principal; use std::convert::TryFrom; pub mod call; diff --git a/src/ic-cdk/src/lib.rs b/src/ic-cdk/src/lib.rs index af9c6a859..0796f3528 100644 --- a/src/ic-cdk/src/lib.rs +++ b/src/ic-cdk/src/lib.rs @@ -23,7 +23,7 @@ static mut DONE: bool = false; /// Re-exports crates those are necessary for using ic-cdk pub mod export { pub use candid; - pub use candid::types::ic_types::Principal; + pub use candid::Principal; pub use serde; } From 25154326c52397cd8ae110d0c9ab2e175ae1467c Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 14 Oct 2022 16:42:38 -0400 Subject: [PATCH 102/234] feat: specify cycles when create canister (#322) * feat: specify cycles when create canister * bump and changelog * fmt --- .../management_canister/src/caller/lib.rs | 11 +++++++- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 10 +++++++ src/ic-cdk/Cargo.toml | 2 +- .../src/api/management_canister/main/mod.rs | 26 +++++++++++++++++-- 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index c294c969c..03502f447 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -13,7 +13,16 @@ mod main { freezing_threshold: Some(10000.into()), }), }; - let canister_id = create_canister(arg).await.unwrap().0.canister_id; + create_canister(arg).await.unwrap(); + + let canister_id = create_canister_with_extra_cycles( + CreateCanisterArgument::default(), + 1_000_000_000_000u128, + ) + .await + .unwrap() + .0 + .canister_id; let arg = UpdateSettingsArgument { canister_id, diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index af63b472e..a5335b872 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.6.0" +version = "0.6.1" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 17e5cc94c..f9ba9485e 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.6.1] - 2022-10-14 + +### Added + +- `create_canister_with_extra_cycles` to specify cycles when create canister (#322) + +### Fixed + +- `create_canister` should charge 0.1T cycles (#322) + ## [0.6.0] - 2022-10-03 ### Changed diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 8fd7345e2..24ce3fb87 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.6.0" +version = "0.6.1" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic-cdk/src/api/management_canister/main/mod.rs b/src/ic-cdk/src/api/management_canister/main/mod.rs index 39da27d24..b3130fb1a 100644 --- a/src/ic-cdk/src/api/management_canister/main/mod.rs +++ b/src/ic-cdk/src/api/management_canister/main/mod.rs @@ -11,11 +11,15 @@ use candid::Principal; mod types; pub use types::*; -// https://internetcomputer.org/docs/current/developer-docs/deploy/computation-and-storage-costs -const CREATE_CANISTER_CYCLES: u128 = 1_000_000_000_000u128; +/// Cycles cost to create a canister. +/// +/// https://internetcomputer.org/docs/current/developer-docs/deploy/computation-and-storage-costs +pub const CREATE_CANISTER_CYCLES: u128 = 100_000_000_000u128; /// Register a new canister and get its canister id. /// +/// Note: This call charges [CREATE_CANISTER_CYCLES] from the caller canister. +/// /// See [IC method `create_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-create_canister). pub async fn create_canister(arg: CreateCanisterArgument) -> CallResult<(CanisterIdRecord,)> { call_with_payment128( @@ -27,6 +31,24 @@ pub async fn create_canister(arg: CreateCanisterArgument) -> CallResult<(Caniste .await } +/// [create_canister] and specify extra cycles to the new canister. +/// +/// Note: This call charges [CREATE_CANISTER_CYCLES] and the specified extra cycles from the caller canister. +/// +/// See [IC method `create_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-create_canister). +pub async fn create_canister_with_extra_cycles( + arg: CreateCanisterArgument, + cycles: u128, +) -> CallResult<(CanisterIdRecord,)> { + call_with_payment128( + Principal::management_canister(), + "create_canister", + (arg,), + CREATE_CANISTER_CYCLES + cycles, + ) + .await +} + /// Update the settings of a canister. /// /// See [IC method `update_settings`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-update_settings). From 30fa7f26ead644cdff599eeacc0fb540cd018462 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 24 Oct 2022 11:06:08 -0400 Subject: [PATCH 103/234] refactor: make system API a separate crate (#324) * init * files * build script * metadata * fix clippy * ic-cdk use new ic0 crate * readme * ic-cdk 0.6.2 --- Cargo.toml | 1 + src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 6 + src/ic-cdk/Cargo.toml | 3 +- src/ic-cdk/src/api/call.rs | 2 +- src/ic-cdk/src/api/ic0.rs | 145 ------------------------ src/ic-cdk/src/api/mod.rs | 2 - src/ic-cdk/src/api/stable/canister.rs | 1 - src/ic-cdk/src/api/stable/mod.rs | 2 +- src/ic0/Cargo.toml | 16 +++ src/ic0/LICENSE | 1 + src/ic0/README.md | 18 +++ src/ic0/build.rs | 152 ++++++++++++++++++++++++++ src/ic0/ic0.txt | 65 +++++++++++ src/ic0/src/ic0.rs | 60 ++++++++++ src/ic0/src/lib.rs | 2 + 16 files changed, 326 insertions(+), 152 deletions(-) delete mode 100644 src/ic-cdk/src/api/ic0.rs create mode 100644 src/ic0/Cargo.toml create mode 120000 src/ic0/LICENSE create mode 100644 src/ic0/README.md create mode 100644 src/ic0/build.rs create mode 100644 src/ic0/ic0.txt create mode 100644 src/ic0/src/ic0.rs create mode 100644 src/ic0/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 6315db62a..ed37aa922 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "src/ic0", "src/ic-cdk", "src/ic-cdk-macros", "library/ic-certified-map", diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index a5335b872..af6df6a6b 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.6.1" +version = "0.6.2" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index f9ba9485e..65ff7f6d9 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.6.2] - 2022-10-24 + +## Refactored + +- Separate `ic0` crate for system API. (#324) + ## [0.6.1] - 2022-10-14 ### Added diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 24ce3fb87..895ca30f0 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.6.1" +version = "0.6.2" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." @@ -18,6 +18,7 @@ rust-version = "1.60.0" candid = "0.8" cfg-if = "1.0.0" serde = "1.0.110" +ic0 = { path = "../ic0", version = "0.18.4" } [dev-dependencies] rstest = "0.12.0" diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index d2860448d..4a5af7ac5 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -1,5 +1,5 @@ //! APIs to make and manage calls in the canister. -use crate::api::{ic0, trap}; +use crate::api::trap; use candid::utils::{ArgumentDecoder, ArgumentEncoder}; use candid::{decode_args, encode_args, write_args, CandidType, Deserialize, Principal}; use serde::ser::Error; diff --git a/src/ic-cdk/src/api/ic0.rs b/src/ic-cdk/src/api/ic0.rs deleted file mode 100644 index 6d0e57c81..000000000 --- a/src/ic-cdk/src/api/ic0.rs +++ /dev/null @@ -1,145 +0,0 @@ -#![allow(clippy::all)] -#![allow(dead_code)] - -//! This files represent the API endpoints for the IC System API. -//! It is meant to be a copy-paste of the System API from the spec, -//! and also not exported outside this crate. -//! -//! Each of these functions are in a private module accessible only -//! in this crate. Each function should have a rust-typed version here -//! as an export point, and have a fully counterpart that is public -//! and declared in [api.rs]. -//! -//! An example is arg data; the msg_arg_data_copy() takes a pointer -//! and a length, there should be two versions of this API endpoint: -//! -//! 1. [ic0::private::msg_arg_data_copy(i32, i32) -> ()] that is the -//! actual export of the system api. -//! 2. [api::msg_arg_data() -> Vec] which calls the size, allocate -//! a buffer, and fills it with the data itself. - -// These two macros are used to being able to copy-paste the system API imports from the -// spec without actually changing anything. This makes it possible to generate at build -// time the list of imports from the spec. We don't do that (yet) as the spec isn't -// open sourced. -// The exported methods are in an `internal` module. -macro_rules! _ic0_module_ret { - ( ( $_: ident : $t: ty ) ) => { - $t - }; - ( ( $_i1: ident : $t1: ty , $_i2: ident : $t2: ty) ) => { - ($t1, $t2) - }; - ( ( $t: ty ) ) => { - $t - }; - ( $t: ty ) => { - $t - }; -} - -// Declare the module itself as a list of API endpoints. -macro_rules! ic0_module { - ( $( ic0. $name: ident : ( $( $argname: ident : $argtype: ty ),* ) -> $rettype: tt ; )+ ) => { - - #[allow(improper_ctypes)] - #[cfg(target_arch = "wasm32")] - #[link(wasm_import_module = "ic0")] - extern "C" { - $(pub(super) fn $name($( $argname: $argtype, )*) -> _ic0_module_ret!($rettype) ;)* - } - - $( - #[cfg(not(target_arch = "wasm32"))] - pub(super) unsafe fn $name($( $argname: $argtype, )*) -> _ic0_module_ret!($rettype) { - let _ = ( $( $argname, )* ); // make sure the arguments are used. - panic!("{} should only be called inside canisters.", stringify!( $name )); - } - )* - }; -} - -// This is a private module that can only be used internally in this file. -// Copy-paste the spec section of the API here. -// https://github.com/dfinity/interface-spec/blob/master/spec/ic0.txt -/* -The comment after each function lists from where these functions may be invoked: -I: from canister_init or canister_post_upgrade -G: from canister_pre_upgrade -U: from canister_update … -Q: from canister_query … -Ry: from a reply callback -Rt: from a reject callback -C: from a cleanup callback -s: the (start) module initialization function -F: from canister_inspect_message -H: from canister_heartbeat -* = I G U Q Ry Rt C F H (NB: Not (start)) -*/ -ic0_module! { - ic0.msg_arg_data_size : () -> i32; // I U Q Ry F - ic0.msg_arg_data_copy : (dst : i32, offset : i32, size : i32) -> (); // I U Q Ry F - ic0.msg_caller_size : () -> i32; // I G U Q F - ic0.msg_caller_copy : (dst : i32, offset: i32, size : i32) -> (); // I G U Q F - ic0.msg_reject_code : () -> i32; // Ry Rt - ic0.msg_reject_msg_size : () -> i32; // Rt - ic0.msg_reject_msg_copy : (dst : i32, offset : i32, size : i32) -> (); // Rt - - ic0.msg_reply_data_append : (src : i32, size : i32) -> (); // U Q Ry Rt - ic0.msg_reply : () -> (); // U Q Ry Rt - ic0.msg_reject : (src : i32, size : i32) -> (); // U Q Ry Rt - - ic0.msg_cycles_available : () -> i64; // U Rt Ry - ic0.msg_cycles_available128 : (dst : i32) -> (); // U Rt Ry - ic0.msg_cycles_refunded : () -> i64; // Rt Ry - ic0.msg_cycles_refunded128 : (dst : i32) -> (); // Rt Ry - ic0.msg_cycles_accept : (max_amount : i64) -> (amount : i64); // U Rt Ry - ic0.msg_cycles_accept128 : (max_amount_high : i64, max_amount_low: i64, dst : i32) - -> (); // U Rt Ry - - ic0.canister_self_size : () -> i32; // * - ic0.canister_self_copy : (dst : i32, offset : i32, size : i32) -> (); // * - ic0.canister_cycle_balance : () -> i64; // * - ic0.canister_cycle_balance128 : (dst : i32) -> (); // * - ic0.canister_status : () -> i32; // * - - ic0.msg_method_name_size : () -> i32; // F - ic0.msg_method_name_copy : (dst : i32, offset : i32, size : i32) -> (); // F - ic0.accept_message : () -> (); // F - - ic0.call_new : // U Ry Rt H - ( callee_src : i32, - callee_size : i32, - name_src : i32, - name_size : i32, - reply_fun : i32, - reply_env : i32, - reject_fun : i32, - reject_env : i32 - ) -> (); - ic0.call_on_cleanup : (fun : i32, env : i32) -> (); // U Ry Rt H - ic0.call_data_append : (src : i32, size : i32) -> (); // U Ry Rt H - ic0.call_cycles_add : (amount : i64) -> (); // U Ry Rt H - ic0.call_cycles_add128 : (amount_high : i64, amount_low: i64) -> (); // U Ry Rt H - ic0.call_perform : () -> ( err_code : i32 ); // U Ry Rt H - - ic0.stable_size : () -> (page_count : i32); // * - ic0.stable_grow : (new_pages : i32) -> (old_page_count : i32); // * - ic0.stable_write : (offset : i32, src : i32, size : i32) -> (); // * - ic0.stable_read : (dst : i32, offset : i32, size : i32) -> (); // * - ic0.stable64_size : () -> (page_count : i64); // * - ic0.stable64_grow : (new_pages : i64) -> (old_page_count : i64); // * - ic0.stable64_write : (offset : i64, src : i64, size : i64) -> (); // * - ic0.stable64_read : (dst : i64, offset : i64, size : i64) -> (); // * - - ic0.certified_data_set : (src: i32, size: i32) -> (); // I G U Ry Rt H - ic0.data_certificate_present : () -> i32; // * - ic0.data_certificate_size : () -> i32; // * - ic0.data_certificate_copy : (dst: i32, offset: i32, size: i32) -> (); // * - - ic0.time : () -> (timestamp : i64); // * - ic0.performance_counter : (counter_type : i32) -> (counter : i64); // * s - - ic0.debug_print : (src : i32, size : i32) -> (); // * s - ic0.trap : (src : i32, size : i32) -> (); // * s -} diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index 433ddc305..f80c41305 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -6,8 +6,6 @@ pub mod call; pub mod management_canister; pub mod stable; -mod ic0; - /// Prints the given message. pub fn print>(s: S) { let s = s.as_ref(); diff --git a/src/ic-cdk/src/api/stable/canister.rs b/src/ic-cdk/src/api/stable/canister.rs index 113e3c3f7..3189f5e61 100644 --- a/src/ic-cdk/src/api/stable/canister.rs +++ b/src/ic-cdk/src/api/stable/canister.rs @@ -1,5 +1,4 @@ use super::*; -use crate::api::ic0; /// A standard implementation of [`StableMemory`]. /// diff --git a/src/ic-cdk/src/api/stable/mod.rs b/src/ic-cdk/src/api/stable/mod.rs index 741fc866f..59aa617ff 100644 --- a/src/ic-cdk/src/api/stable/mod.rs +++ b/src/ic-cdk/src/api/stable/mod.rs @@ -123,7 +123,7 @@ pub fn stable_bytes() -> Vec { let size = (stable_size() as usize) << 16; let mut vec = Vec::with_capacity(size); unsafe { - super::ic0::stable_read(vec.as_ptr() as i32, 0, size as i32); + ic0::stable_read(vec.as_ptr() as i32, 0, size as i32); vec.set_len(size); } vec diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml new file mode 100644 index 000000000..79d2d20ae --- /dev/null +++ b/src/ic0/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "ic0" +version = "0.18.4" +authors = ["DFINITY Stiftung "] +edition = "2021" +description = "Internet Computer System API Binding." +license = "Apache-2.0" +readme = "README.md" +categories = ["api-bindings", "development-tools::ffi"] +keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] +repository = "https://github.com/dfinity/cdk-rs" +rust-version = "1.60.0" + +[build-dependencies] +quote = "1.0" +syn = { version = "1.0", features = ["parsing", "full", "extra-traits"] } diff --git a/src/ic0/LICENSE b/src/ic0/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/src/ic0/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/src/ic0/README.md b/src/ic0/README.md new file mode 100644 index 000000000..1b219b100 --- /dev/null +++ b/src/ic0/README.md @@ -0,0 +1,18 @@ +# ic0 + +Internet Computer System API binding. + +## What + +`ic0` is simply an unsafe Rust translation of Internet Computer System API as described in the [Specification](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-imports). + +## Update and Version Strategy + +`ic0` keeps in step with [interface-spec][1]. Particularly, `ic0` is directly generated from [ic0.txt][2] in that repo. + +When interface-spec releases a new version that modify [ic0.txt][2], we replace `ic0.txt` in the root of this crate and run `cargo build` to generate a new `src/ic0.rs`. + +The version of `ic0` crate will also bump to the same version as [interface-spec][1]. + +[1]: https://github.com/dfinity/interface-spec +[2]: https://github.com/dfinity/interface-spec/blob/master/spec/ic0.txt diff --git a/src/ic0/build.rs b/src/ic0/build.rs new file mode 100644 index 000000000..06c97e85c --- /dev/null +++ b/src/ic0/build.rs @@ -0,0 +1,152 @@ +use quote::quote; +use syn::parse::{Parse, ParseStream, Result}; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::token::Comma; +use syn::{parenthesized, Error}; +use syn::{FnArg, Ident, Token, TypePath}; + +use std::fs; +use std::io::Write; +use std::process::Command; + +#[derive(Clone, Debug)] +pub struct SystemAPI { + pub name: Ident, + pub args: Vec, + pub output: Option, +} + +impl Parse for SystemAPI { + fn parse(input: ParseStream) -> Result { + let ic0_token: Ident = input.parse()?; + if ic0_token != "ic0" { + return Err(Error::new(ic0_token.span(), "expected `ic0`")); + } + input.parse::()?; + let name: Ident = input.parse()?; + input.parse::()?; + + // args + let content; + parenthesized!(content in input); + let args = Punctuated::::parse_terminated(&content)?; + let args: Vec = args.iter().cloned().collect(); + for arg in &args { + match arg { + FnArg::Receiver(r) => return Err(Error::new(r.span(), "receiver not expected")), + FnArg::Typed(pat_type) => match &*pat_type.ty { + syn::Type::Path(ty) => { + type_supported(ty)?; + } + _ => return Err(Error::new(pat_type.span(), "expected type as i32")), + }, + } + } + + input.parse::]>()?; + + // output + let output = if input.peek(syn::token::Paren) { + let content; + parenthesized!(content in input); + if content.is_empty() { + None + } else { + let _output_name: Ident = content.parse()?; + content.parse::()?; + let ty: TypePath = content.parse()?; + if !content.is_empty() { + return Err(Error::new(ty.span(), "expected only one return type")); + } + type_supported(&ty)?; + Some(ty) + } + } else { + let ty: TypePath = input.parse()?; + type_supported(&ty)?; + Some(ty) + }; + + input.parse::()?; + + Ok(Self { name, args, output }) + } +} + +fn type_supported(ty: &TypePath) -> Result<()> { + let supported = match ty.path.get_ident() { + Some(i) => i == "i32" || i == "i64", + None => false, + }; + match supported { + true => Ok(()), + false => Err(Error::new(ty.span(), "expected i32 or i64")), + } +} + +#[derive(Clone, Debug)] +pub struct IC0 { + pub apis: Vec, +} + +impl Parse for IC0 { + fn parse(input: ParseStream) -> Result { + Ok(Self { + apis: { + let mut apis = vec![]; + while !input.is_empty() { + apis.push(input.parse()?); + } + apis + }, + }) + } +} + +fn main() { + let s = include_str!("ic0.txt"); + let ic0: IC0 = syn::parse_str(s).unwrap(); + + // let out_dir = env::var_os("OUT_DIR").unwrap(); + // let dest_path = Path::new(&out_dir).join("ic0.rs"); + + let mut f = fs::File::create("src/ic0.rs").unwrap(); + + writeln!( + f, + r#"// This file is generated from ic0.txt. +// Don't manually modify it. +#[link(wasm_import_module = "ic0")] +extern "C" {{"#, + ) + .unwrap(); + + for api in ic0.apis { + let fn_name = api.name; + let args = api.args; + + let mut r = quote! { + pub fn #fn_name(#(#args),*) + }; + + if let Some(output) = api.output { + r = quote! { + #r -> #output + } + } + + r = quote! {#r;}; + writeln!(f, "{}", r).unwrap(); + } + + writeln!(f, "}}").unwrap(); + + Command::new("cargo") + .args(["fmt"]) + .output() + .expect("`cargo fmt` failed"); + + println!("cargo:rerun-if-changed=ic0.txt"); + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/src/ic0/ic0.txt b/src/ic0/ic0.txt new file mode 100644 index 000000000..53e9d2716 --- /dev/null +++ b/src/ic0/ic0.txt @@ -0,0 +1,65 @@ +ic0.msg_arg_data_size : () -> i32; // I U Q Ry F +ic0.msg_arg_data_copy : (dst : i32, offset : i32, size : i32) -> (); // I U Q Ry F +ic0.msg_caller_size : () -> i32; // I G U Q F +ic0.msg_caller_copy : (dst : i32, offset: i32, size : i32) -> (); // I G U Q F +ic0.msg_reject_code : () -> i32; // Ry Rt +ic0.msg_reject_msg_size : () -> i32; // Rt +ic0.msg_reject_msg_copy : (dst : i32, offset : i32, size : i32) -> (); // Rt + +ic0.msg_reply_data_append : (src : i32, size : i32) -> (); // U Q Ry Rt +ic0.msg_reply : () -> (); // U Q Ry Rt +ic0.msg_reject : (src : i32, size : i32) -> (); // U Q Ry Rt + +ic0.msg_cycles_available : () -> i64; // U Rt Ry +ic0.msg_cycles_available128 : (dst : i32) -> (); // U Rt Ry +ic0.msg_cycles_refunded : () -> i64; // Rt Ry +ic0.msg_cycles_refunded128 : (dst : i32) -> (); // Rt Ry +ic0.msg_cycles_accept : (max_amount : i64) -> (amount : i64); // U Rt Ry +ic0.msg_cycles_accept128 : (max_amount_high : i64, max_amount_low: i64, dst : i32) + -> (); // U Rt Ry + +ic0.canister_self_size : () -> i32; // * +ic0.canister_self_copy : (dst : i32, offset : i32, size : i32) -> (); // * +ic0.canister_cycle_balance : () -> i64; // * +ic0.canister_cycle_balance128 : (dst : i32) -> (); // * +ic0.canister_status : () -> i32; // * + +ic0.msg_method_name_size : () -> i32; // F +ic0.msg_method_name_copy : (dst : i32, offset : i32, size : i32) -> (); // F +ic0.accept_message : () -> (); // F + +ic0.call_new : // U Ry Rt H + ( callee_src : i32, + callee_size : i32, + name_src : i32, + name_size : i32, + reply_fun : i32, + reply_env : i32, + reject_fun : i32, + reject_env : i32 + ) -> (); +ic0.call_on_cleanup : (fun : i32, env : i32) -> (); // U Ry Rt H +ic0.call_data_append : (src : i32, size : i32) -> (); // U Ry Rt H +ic0.call_cycles_add : (amount : i64) -> (); // U Ry Rt H +ic0.call_cycles_add128 : (amount_high : i64, amount_low: i64) -> (); // U Ry Rt H +ic0.call_perform : () -> ( err_code : i32 ); // U Ry Rt H + +ic0.stable_size : () -> (page_count : i32); // * +ic0.stable_grow : (new_pages : i32) -> (old_page_count : i32); // * +ic0.stable_write : (offset : i32, src : i32, size : i32) -> (); // * +ic0.stable_read : (dst : i32, offset : i32, size : i32) -> (); // * +ic0.stable64_size : () -> (page_count : i64); // * +ic0.stable64_grow : (new_pages : i64) -> (old_page_count : i64); // * +ic0.stable64_write : (offset : i64, src : i64, size : i64) -> (); // * +ic0.stable64_read : (dst : i64, offset : i64, size : i64) -> (); // * + +ic0.certified_data_set : (src: i32, size: i32) -> (); // I G U Ry Rt H +ic0.data_certificate_present : () -> i32; // * +ic0.data_certificate_size : () -> i32; // * +ic0.data_certificate_copy : (dst: i32, offset: i32, size: i32) -> (); // * + +ic0.time : () -> (timestamp : i64); // * +ic0.performance_counter : (counter_type : i32) -> (counter : i64); // * s + +ic0.debug_print : (src : i32, size : i32) -> (); // * s +ic0.trap : (src : i32, size : i32) -> (); // * s \ No newline at end of file diff --git a/src/ic0/src/ic0.rs b/src/ic0/src/ic0.rs new file mode 100644 index 000000000..33375296f --- /dev/null +++ b/src/ic0/src/ic0.rs @@ -0,0 +1,60 @@ +// This file is generated from ic0.txt. +// Don't manually modify it. +#[link(wasm_import_module = "ic0")] +extern "C" { + pub fn msg_arg_data_size() -> i32; + pub fn msg_arg_data_copy(dst: i32, offset: i32, size: i32); + pub fn msg_caller_size() -> i32; + pub fn msg_caller_copy(dst: i32, offset: i32, size: i32); + pub fn msg_reject_code() -> i32; + pub fn msg_reject_msg_size() -> i32; + pub fn msg_reject_msg_copy(dst: i32, offset: i32, size: i32); + pub fn msg_reply_data_append(src: i32, size: i32); + pub fn msg_reply(); + pub fn msg_reject(src: i32, size: i32); + pub fn msg_cycles_available() -> i64; + pub fn msg_cycles_available128(dst: i32); + pub fn msg_cycles_refunded() -> i64; + pub fn msg_cycles_refunded128(dst: i32); + pub fn msg_cycles_accept(max_amount: i64) -> i64; + pub fn msg_cycles_accept128(max_amount_high: i64, max_amount_low: i64, dst: i32); + pub fn canister_self_size() -> i32; + pub fn canister_self_copy(dst: i32, offset: i32, size: i32); + pub fn canister_cycle_balance() -> i64; + pub fn canister_cycle_balance128(dst: i32); + pub fn canister_status() -> i32; + pub fn msg_method_name_size() -> i32; + pub fn msg_method_name_copy(dst: i32, offset: i32, size: i32); + pub fn accept_message(); + pub fn call_new( + callee_src: i32, + callee_size: i32, + name_src: i32, + name_size: i32, + reply_fun: i32, + reply_env: i32, + reject_fun: i32, + reject_env: i32, + ); + pub fn call_on_cleanup(fun: i32, env: i32); + pub fn call_data_append(src: i32, size: i32); + pub fn call_cycles_add(amount: i64); + pub fn call_cycles_add128(amount_high: i64, amount_low: i64); + pub fn call_perform() -> i32; + pub fn stable_size() -> i32; + pub fn stable_grow(new_pages: i32) -> i32; + pub fn stable_write(offset: i32, src: i32, size: i32); + pub fn stable_read(dst: i32, offset: i32, size: i32); + pub fn stable64_size() -> i64; + pub fn stable64_grow(new_pages: i64) -> i64; + pub fn stable64_write(offset: i64, src: i64, size: i64); + pub fn stable64_read(dst: i64, offset: i64, size: i64); + pub fn certified_data_set(src: i32, size: i32); + pub fn data_certificate_present() -> i32; + pub fn data_certificate_size() -> i32; + pub fn data_certificate_copy(dst: i32, offset: i32, size: i32); + pub fn time() -> i64; + pub fn performance_counter(counter_type: i32) -> i64; + pub fn debug_print(src: i32, size: i32); + pub fn trap(src: i32, size: i32); +} diff --git a/src/ic0/src/lib.rs b/src/ic0/src/lib.rs new file mode 100644 index 000000000..6675c6b35 --- /dev/null +++ b/src/ic0/src/lib.rs @@ -0,0 +1,2 @@ +mod ic0; +pub use ic0::*; From 936a7b563d2b63da82ec275bacfc33a691e07278 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 26 Oct 2022 12:47:13 -0400 Subject: [PATCH 104/234] fix: no build script for ic0 (#327) * use example for build * readme and version bump * also bump ic-cdk --- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 6 ++++++ src/ic-cdk/Cargo.toml | 2 +- src/ic0/Cargo.toml | 12 +++++++++--- src/ic0/README.md | 7 ++++++- src/ic0/{build.rs => util/ic0build.rs} | 12 +++++------- 6 files changed, 28 insertions(+), 13 deletions(-) rename src/ic0/{build.rs => util/ic0build.rs} (92%) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index af6df6a6b..2518ee3b5 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.6.2" +version = "0.6.3" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 65ff7f6d9..14d434842 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.6.3] - 2022-10-26 + +### Fixed + +- Doc can build on docs.rs. (#327) + ## [0.6.2] - 2022-10-24 ## Refactored diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 895ca30f0..08af60f2e 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.6.2" +version = "0.6.3" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml index 79d2d20ae..ba0b05752 100644 --- a/src/ic0/Cargo.toml +++ b/src/ic0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic0" -version = "0.18.4" +version = "0.18.5" authors = ["DFINITY Stiftung "] edition = "2021" description = "Internet Computer System API Binding." @@ -8,9 +8,15 @@ license = "Apache-2.0" readme = "README.md" categories = ["api-bindings", "development-tools::ffi"] keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] +include = ["src", "Cargo.toml", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" rust-version = "1.60.0" -[build-dependencies] -quote = "1.0" +[dev-dependencies] +quote = { version = "1.0" } syn = { version = "1.0", features = ["parsing", "full", "extra-traits"] } + +# This is not a real example but a utility for auto-generating ic0.rs +[[example]] +name = "ic0build" +path = "util/ic0build.rs" diff --git a/src/ic0/README.md b/src/ic0/README.md index 1b219b100..786868d36 100644 --- a/src/ic0/README.md +++ b/src/ic0/README.md @@ -10,7 +10,12 @@ Internet Computer System API binding. `ic0` keeps in step with [interface-spec][1]. Particularly, `ic0` is directly generated from [ic0.txt][2] in that repo. -When interface-spec releases a new version that modify [ic0.txt][2], we replace `ic0.txt` in the root of this crate and run `cargo build` to generate a new `src/ic0.rs`. +When interface-spec releases a new version that modify [ic0.txt][2]: + +1. replace `ic0.txt` in the root of this crate; +2. execute `cargo run --example=ic0build`; + +`src/ic0.rs` should be updated. The version of `ic0` crate will also bump to the same version as [interface-spec][1]. diff --git a/src/ic0/build.rs b/src/ic0/util/ic0build.rs similarity index 92% rename from src/ic0/build.rs rename to src/ic0/util/ic0build.rs index 06c97e85c..c32b71388 100644 --- a/src/ic0/build.rs +++ b/src/ic0/util/ic0build.rs @@ -8,6 +8,7 @@ use syn::{FnArg, Ident, Token, TypePath}; use std::fs; use std::io::Write; +use std::path::PathBuf; use std::process::Command; #[derive(Clone, Debug)] @@ -105,13 +106,13 @@ impl Parse for IC0 { } fn main() { - let s = include_str!("ic0.txt"); + let s = include_str!("../ic0.txt"); let ic0: IC0 = syn::parse_str(s).unwrap(); - // let out_dir = env::var_os("OUT_DIR").unwrap(); - // let dest_path = Path::new(&out_dir).join("ic0.rs"); + let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + d.push("src/ic0.rs"); - let mut f = fs::File::create("src/ic0.rs").unwrap(); + let mut f = fs::File::create(d).unwrap(); writeln!( f, @@ -146,7 +147,4 @@ extern "C" {{"#, .args(["fmt"]) .output() .expect("`cargo fmt` failed"); - - println!("cargo:rerun-if-changed=ic0.txt"); - println!("cargo:rerun-if-changed=build.rs"); } From bfc7c50d04e8a06c2444c5688f6381783357d499 Mon Sep 17 00:00:00 2001 From: Chandra Penke <16369152+ncpenke@users.noreply.github.com> Date: Fri, 28 Oct 2022 13:17:04 -0700 Subject: [PATCH 105/234] feat: expose offsets in reader and writer (#330) * feat: expose offsets in reader and writer * bump version Co-authored-by: Linwei Shang --- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 6 +++++ src/ic-cdk/Cargo.toml | 2 +- src/ic-cdk/src/api/stable/mod.rs | 20 +++++++++++++++ src/ic-cdk/src/api/stable/tests.rs | 40 ++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 2518ee3b5..bacff9c31 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.6.3" +version = "0.6.4" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 14d434842..0c2770ca7 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.6.4] - 2022-10-28 + +### Added + +- Expose `offset` of `StableReader` and `StableWriter`. (#330) + ## [0.6.3] - 2022-10-26 ### Fixed diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 08af60f2e..ae043166a 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.6.3" +version = "0.6.4" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic-cdk/src/api/stable/mod.rs b/src/ic-cdk/src/api/stable/mod.rs index 59aa617ff..cba46f545 100644 --- a/src/ic-cdk/src/api/stable/mod.rs +++ b/src/ic-cdk/src/api/stable/mod.rs @@ -165,6 +165,11 @@ impl StableWriter { } } + /// Returns the offset of the writer + pub fn offset(&self) -> usize { + self.offset + } + /// Attempts to grow the memory by adding new pages. pub fn grow(&mut self, new_pages: u32) -> Result<(), StableMemoryError> { let old_page_count = self.memory.stable_grow(new_pages)?; @@ -231,6 +236,11 @@ impl BufferedStableWriter { inner: io::BufWriter::with_capacity(buffer_size, writer), } } + + /// Returns the offset of the writer + pub fn offset(&self) -> usize { + self.inner.get_ref().offset() + } } impl io::Write for BufferedStableWriter { @@ -275,6 +285,11 @@ impl StableReader { } } + /// Returns the offset of the reader + pub fn offset(&self) -> usize { + self.offset + } + /// Reads data from the stable memory location specified by an offset. /// /// Note: @@ -325,6 +340,11 @@ impl BufferedStableReader { inner: io::BufReader::with_capacity(buffer_size, reader), } } + + /// Returns the offset of the reader + pub fn offset(&self) -> usize { + self.inner.get_ref().offset() + } } impl io::Read for BufferedStableReader { diff --git a/src/ic-cdk/src/api/stable/tests.rs b/src/ic-cdk/src/api/stable/tests.rs index 4bcb38c38..03961e3a9 100644 --- a/src/ic-cdk/src/api/stable/tests.rs +++ b/src/ic-cdk/src/api/stable/tests.rs @@ -153,6 +153,25 @@ mod stable_writer_tests { assert_eq!(capacity_pages, min_pages_required as u64); } + #[test] + fn check_offset() { + const WRITE_SIZE: usize = 1025; + + let memory = Rc::new(Mutex::new(Vec::new())); + let mut writer = StableWriter::with_memory(TestStableMemory::new(memory.clone()), 0); + assert_eq!(writer.offset(), 0); + assert_eq!(writer.write(&vec![0; WRITE_SIZE]).unwrap(), WRITE_SIZE); + assert_eq!(writer.offset(), WRITE_SIZE); + + let mut writer = BufferedStableWriter::with_writer( + WRITE_SIZE - 1, + StableWriter::with_memory(TestStableMemory::new(memory), 0), + ); + assert_eq!(writer.offset(), 0); + assert_eq!(writer.write(&vec![0; WRITE_SIZE]).unwrap(), WRITE_SIZE); + assert_eq!(writer.offset(), WRITE_SIZE); + } + fn build_writer(memory: TestStableMemory, buffer_size: Option) -> Box { let writer = StableWriter::with_memory(memory, 0); if let Some(buffer_size) = buffer_size { @@ -185,6 +204,27 @@ mod stable_reader_tests { assert_eq!(input, output[..input.len()]); } + #[test] + fn check_offset() { + const READ_SIZE: usize = 1025; + + let memory = Rc::new(Mutex::new(vec![1; READ_SIZE])); + let mut reader = StableReader::with_memory(TestStableMemory::new(memory.clone()), 0); + assert_eq!(reader.offset(), 0); + let mut bytes = vec![0; READ_SIZE]; + assert_eq!(reader.read(&mut bytes).unwrap(), READ_SIZE); + assert_eq!(reader.offset(), READ_SIZE); + + let mut reader = BufferedStableReader::with_reader( + READ_SIZE - 1, + StableReader::with_memory(TestStableMemory::new(memory), 0), + ); + assert_eq!(reader.offset(), 0); + let mut bytes = vec![0; READ_SIZE]; + assert_eq!(reader.read(&mut bytes).unwrap(), READ_SIZE); + assert_eq!(reader.offset(), READ_SIZE); + } + fn build_reader(memory: TestStableMemory, buffer_size: Option) -> Box { let reader = StableReader::with_memory(memory, 0); if let Some(buffer_size) = buffer_size { From 4610c4f328d831fee7223a2e3fa25f80eb7e7db1 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 4 Nov 2022 11:37:53 -0400 Subject: [PATCH 106/234] chore: release ic-ledger-types v0.2.0 (#332) --- library/ic-ledger-types/CHANGELOG.md | 4 ++++ library/ic-ledger-types/Cargo.toml | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index 569f6aef3..137fe6153 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.0] - 2022-11-04 +### Changed +- Upgrade `ic-cdk` to v0.6 and `candid` to v0.8. + ## [0.1.2] - 2022-05-31 ### Added - Integrate with the ledger's `token_symbol` method diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index e2718cb0c..94d97f756 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.1.2" +version = "0.2.0" edition = "2021" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." @@ -17,11 +17,10 @@ rust-version = "1.60.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ic-cdk = { path = "../../src/ic-cdk" } +ic-cdk = { path = "../../src/ic-cdk", version = "0.6" } candid = "0.8.0" crc32fast = "1.2.0" hex = "0.4" serde = "1" serde_bytes = "0.11" sha2 = "0.9" - From 14267d8d8059e734c5682fce44e66905bf5d922b Mon Sep 17 00:00:00 2001 From: QJ Yu <79867586+qj-yu@users.noreply.github.com> Date: Fri, 4 Nov 2022 11:54:36 -0700 Subject: [PATCH 107/234] chore: BREAKING CHANGE: Update for HTTPS Outcalls transform function with context. (#326) * Update for HTTPS Outcalls transform function with context. * fix errors * another fix * working * update changelog * fix test * bump dfx for examples * changelog Co-authored-by: Linwei Shang --- .github/workflows/examples.yml | 2 +- .../management_canister/src/caller/lib.rs | 6 +- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 9 ++- src/ic-cdk/Cargo.toml | 3 +- .../api/management_canister/http_request.rs | 64 +++++++++++++------ 6 files changed, 59 insertions(+), 27 deletions(-) diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 90fc5481d..47ccabbb2 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -12,7 +12,7 @@ concurrency: env: rust-version: 1.60.0 - dfx-version: 0.12.0-beta.3 + dfx-version: 0.12.0-beta.6 jobs: test: diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index 03502f447..49f42a0b2 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -95,7 +95,7 @@ mod http_request { method: HttpMethod::GET, headers: vec![], body: None, - transform: Some(TransformType::from_transform_function(transform)), + transform: Some(TransformContext::new(transform, vec![])), }; let response = http_request(arg).await.unwrap().0; assert_eq!(response.status, 200); @@ -110,13 +110,13 @@ mod http_request { // transform function must be a *query* method of the canister #[query] - fn transform(arg: HttpResponse) -> HttpResponse { + fn transform(arg: TransformArgs) -> HttpResponse { HttpResponse { headers: vec![HttpHeader { name: "custom-header".to_string(), value: "test".to_string(), }], - ..arg + ..arg.response } } } diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index bacff9c31..9329c06c0 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.6.4" +version = "0.6.5" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 0c2770ca7..1337dae40 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.6.5] - 2022-11-04 + +### Changed + +BREAKING CHANGE of experimental API: +- `http_request` to support `context` field in callback function. (#326) + ## [0.6.4] - 2022-10-28 ### Added @@ -20,7 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.6.2] - 2022-10-24 -## Refactored +### Refactored - Separate `ic0` crate for system API. (#324) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index ae043166a..6cd2d8430 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.6.4" +version = "0.6.5" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." @@ -18,6 +18,7 @@ rust-version = "1.60.0" candid = "0.8" cfg-if = "1.0.0" serde = "1.0.110" +serde_bytes = "0.11.7" ic0 = { path = "../ic0", version = "0.18.4" } [dev-dependencies] diff --git a/src/ic-cdk/src/api/management_canister/http_request.rs b/src/ic-cdk/src/api/management_canister/http_request.rs index 13a3f5477..6b6beb52b 100644 --- a/src/ic-cdk/src/api/management_canister/http_request.rs +++ b/src/ic-cdk/src/api/management_canister/http_request.rs @@ -17,7 +17,7 @@ impl CandidType for TransformFunc { fn _ty() -> Type { Type::Func(Function { modes: vec![FuncMode::Query], - args: vec![HttpResponse::ty()], + args: vec![TransformArgs::ty()], rets: vec![HttpResponse::ty()], }) } @@ -27,36 +27,60 @@ impl CandidType for TransformFunc { } } -/// "transform" reference function type: -/// `opt variant { function: func (http_response) -> (http_response) query }` -#[derive(CandidType, Deserialize, Debug, PartialEq, Clone)] -pub enum TransformType { - /// reference function with signature: `func (http_response) -> (http_response) query` - #[serde(rename = "function")] - Function(TransformFunc), +/// Type used for encoding/decoding: +/// `record { +/// response : http_response; +/// context : blob; +/// }` +#[derive(CandidType, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct TransformArgs { + /// Raw response from remote service, to be transformed + pub response: HttpResponse, + + /// Context for response transformation + #[serde(with = "serde_bytes")] + pub context: Vec, +} + +/// Type used for encoding/decoding: +/// `record { +// function : func (record {response : http_response; context : blob}) -> (http_response) query; +// context : blob; +// }` +#[derive(CandidType, Clone, Debug, Deserialize, PartialEq)] +pub struct TransformContext { + /// Reference function with signature: `func (record {response : http_response; context : blob}) -> (http_response) query;`. + pub function: TransformFunc, + + /// Context to be passed to `transform` function to transform HTTP response for consensus + #[serde(with = "serde_bytes")] + pub context: Vec, } -impl TransformType { +impl TransformContext { /// Construct `TransformType` from a transform function. /// /// # example /// /// ```ignore /// #[ic_cdk_macros::query] - /// fn my_transform(arg: HttpResponse) -> HttpResponse { + /// fn my_transform(arg: TransformArgs) -> HttpResponse { /// ... /// } /// /// let transform = TransformType::from_transform_function(my_transform); /// ``` - pub fn from_transform_function(func: T) -> Self + pub fn new(func: T, context: Vec) -> Self where - T: Fn(HttpResponse) -> HttpResponse, + T: Fn(TransformArgs) -> HttpResponse, { - Self::Function(TransformFunc(candid::Func { - principal: crate::id(), - method: get_function_name(func).to_string(), - })) + Self { + function: TransformFunc(candid::Func { + principal: crate::id(), + method: get_function_name(func).to_string(), + }), + context, + } } } @@ -110,8 +134,8 @@ pub struct CanisterHttpRequestArgument { pub headers: Vec, /// Optionally provide request body. pub body: Option>, - /// Name of the transform function which is `func (http_response) -> (http_response) query`. - pub transform: Option, + /// Name of the transform function which is `func (transform_args) -> (http_response) query`. + pub transform: Option, } /// The returned HTTP response. @@ -170,7 +194,7 @@ mod tests { body: None, transform: None, }; - assert_eq!(http_request_required_cycles(&arg), 716500000u128); + assert_eq!(http_request_required_cycles(&arg), 718500000u128); } #[test] @@ -184,7 +208,7 @@ mod tests { body: None, transform: None, }; - assert_eq!(http_request_required_cycles(&arg), 210130900000u128); + assert_eq!(http_request_required_cycles(&arg), 210132900000u128); } #[test] From a8e77335c8e47a80f83972fbd2d7debdab5c97d7 Mon Sep 17 00:00:00 2001 From: Chandra Penke <16369152+ncpenke@users.noreply.github.com> Date: Wed, 9 Nov 2022 13:17:07 -0800 Subject: [PATCH 108/234] feat: generalize stable storage API by adding 64-bit support for std:io traits (#335) * feat: generalize stable storage API by adding 64-bit support for std::io traits * Implement io::Seek * Add StableIO structure that implements both io::Read, and io::Write Co-authored-by: Dmitry Demin * bump version Co-authored-by: Dmitry Demin Co-authored-by: Linwei Shang --- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 12 ++ src/ic-cdk/Cargo.toml | 2 +- src/ic-cdk/src/api/stable/mod.rs | 286 ++++++++++++++++++++------- src/ic-cdk/src/api/stable/private.rs | 52 +++++ src/ic-cdk/src/api/stable/tests.rs | 49 ++++- 6 files changed, 330 insertions(+), 73 deletions(-) create mode 100644 src/ic-cdk/src/api/stable/private.rs diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 9329c06c0..1c8d319cc 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.6.5" +version = "0.6.6" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 1337dae40..b05a6908b 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.6.6] - 2022-11-09 + +### Added + +- Added `StableIO` to implement both `io::Write` and `io::Read` for stable memory. (#335) +- Added 64-bit support for `io::Write` and `io::Read` via `StableIO`. +- Implement `io::Seek` for stable storage. + +### Changed + +- `StableWriter` and `StableReader` are now wrappers around `StableIO`. + ## [0.6.5] - 2022-11-04 ### Changed diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 6cd2d8430..2404cfdec 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.6.5" +version = "0.6.6" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic-cdk/src/api/stable/mod.rs b/src/ic-cdk/src/api/stable/mod.rs index cba46f545..5a988fe93 100644 --- a/src/ic-cdk/src/api/stable/mod.rs +++ b/src/ic-cdk/src/api/stable/mod.rs @@ -3,6 +3,7 @@ //! You can check the [Internet Computer Specification](https://smartcontracts.org/docs/interface-spec/index.html#system-api-stable-memory) //! for a in-depth explanation of stable memory. mod canister; +mod private; #[cfg(test)] mod tests; @@ -129,84 +130,226 @@ pub fn stable_bytes() -> Vec { vec } -/// A writer to the stable memory. +/// Performs generic IO (read, write, and seek) on stable memory. /// -/// Warning: This will overwrite any existing data in stable memory as it writes, so ensure you set -/// the `offset` value accordingly if you wish to preserve existing data. +/// Warning: When using write functionality, this will overwrite any existing +/// data in stable memory as it writes, so ensure you set the `offset` value +/// accordingly if you wish to preserve existing data. /// /// Will attempt to grow the memory as it writes, /// and keep offsets and total capacity. -pub struct StableWriter { + +pub struct StableIO { /// The offset of the next write. - offset: usize, + offset: A, /// The capacity, in pages. - capacity: u32, + capacity: A, /// The stable memory to write data to. memory: M, } -impl Default for StableWriter { +impl Default for StableIO { fn default() -> Self { Self::with_memory(CanisterStableMemory::default(), 0) } } +// Helper macro to implement StableIO for both 32-bit and 64-bit. +// +// We use a macro here since capturing all the traits required to add and manipulate memory +// addresses with generics becomes cumbersome. +macro_rules! impl_stable_io { + ($address:ty) => { + impl + StableMemory> StableIO { + /// Creates a new `StableIO` which writes to the selected memory + pub fn with_memory(memory: M, offset: $address) -> Self { + let capacity = memory.stable_size_(); + + Self { + offset, + capacity, + memory, + } + } + + /// Returns the offset of the writer + pub fn offset(&self) -> $address { + self.offset + } + + /// Attempts to grow the memory by adding new pages. + pub fn grow(&mut self, new_pages: $address) -> Result<(), StableMemoryError> { + let old_page_count = self.memory.stable_grow_(new_pages)?; + self.capacity = old_page_count + new_pages; + Ok(()) + } + + /// Writes a byte slice to the buffer. + /// + /// The only condition where this will + /// error out is if it cannot grow the memory. + pub fn write(&mut self, buf: &[u8]) -> Result { + let required_capacity_bytes = self.offset + buf.len() as $address; + let required_capacity_pages = + ((required_capacity_bytes + WASM_PAGE_SIZE_IN_BYTES as $address - 1) + / WASM_PAGE_SIZE_IN_BYTES as $address); + let current_pages = self.capacity; + let additional_pages_required = + required_capacity_pages.saturating_sub(current_pages); + + if additional_pages_required > 0 { + self.grow(additional_pages_required)?; + } + + self.memory.stable_write_(self.offset, buf); + self.offset += buf.len() as $address; + Ok(buf.len()) + } + + /// Reads data from the stable memory location specified by an offset. + /// + /// Note: + /// The stable memory size is cached on creation of the StableReader. + /// Therefore, in following scenario, it will get an `OutOfBounds` error: + /// 1. Create a StableReader + /// 2. Write some data to the stable memory which causes it grow + /// 3. call `read()` to read the newly written bytes + pub fn read(&mut self, buf: &mut [u8]) -> Result { + let capacity_bytes = self.capacity * WASM_PAGE_SIZE_IN_BYTES as $address; + let read_buf = if buf.len() as $address + self.offset > capacity_bytes { + if self.offset < capacity_bytes { + &mut buf[..(capacity_bytes - self.offset) as usize] + } else { + return Err(StableMemoryError::OutOfBounds); + } + } else { + buf + }; + self.memory.stable_read_(self.offset, read_buf); + self.offset += read_buf.len() as $address; + Ok(read_buf.len()) + } + + // Helper used to implement io::Seek + fn seek(&mut self, offset: io::SeekFrom) -> io::Result { + self.offset = match offset { + io::SeekFrom::Start(offset) => offset as $address, + io::SeekFrom::End(offset) => { + ((self.capacity * WASM_PAGE_SIZE_IN_BYTES as $address) as i64 + offset) + as $address + } + io::SeekFrom::Current(offset) => (self.offset as i64 + offset) as $address, + }; + + Ok(self.offset as u64) + } + } + + impl + StableMemory> io::Write + for StableIO + { + fn write(&mut self, buf: &[u8]) -> Result { + self.write(buf) + .map_err(|e| io::Error::new(io::ErrorKind::OutOfMemory, e)) + } + + fn flush(&mut self) -> Result<(), io::Error> { + // Noop. + Ok(()) + } + } + + impl + StableMemory> io::Read + for StableIO + { + fn read(&mut self, buf: &mut [u8]) -> Result { + Self::read(self, buf).or(Ok(0)) // Read defines EOF to be success + } + } + + impl + StableMemory> io::Seek + for StableIO + { + fn seek(&mut self, offset: io::SeekFrom) -> io::Result { + self.seek(offset) + } + } + }; +} + +impl_stable_io!(u32); +impl_stable_io!(u64); + +/// A writer to the stable memory. +/// +/// Warning: This will overwrite any existing data in stable memory as it writes, so ensure you set +/// the `offset` value accordingly if you wish to preserve existing data. +/// +/// Will attempt to grow the memory as it writes, +/// and keep offsets and total capacity. +pub struct StableWriter(StableIO); + +#[allow(clippy::derivable_impls)] +impl Default for StableWriter { + #[inline] + fn default() -> Self { + Self(StableIO::default()) + } +} + impl StableWriter { /// Creates a new `StableWriter` which writes to the selected memory + #[inline] pub fn with_memory(memory: M, offset: usize) -> Self { - let capacity = memory.stable_size(); - - Self { - offset, - capacity, - memory, - } + Self(StableIO::::with_memory(memory, offset as u32)) } /// Returns the offset of the writer + #[inline] pub fn offset(&self) -> usize { - self.offset + self.0.offset() as usize } /// Attempts to grow the memory by adding new pages. + #[inline] pub fn grow(&mut self, new_pages: u32) -> Result<(), StableMemoryError> { - let old_page_count = self.memory.stable_grow(new_pages)?; - self.capacity = old_page_count + new_pages; - Ok(()) + self.0.grow(new_pages) } /// Writes a byte slice to the buffer. /// /// The only condition where this will /// error out is if it cannot grow the memory. + #[inline] pub fn write(&mut self, buf: &[u8]) -> Result { - let required_capacity_bytes = self.offset + buf.len(); - let required_capacity_pages = ((required_capacity_bytes + WASM_PAGE_SIZE_IN_BYTES - 1) - / WASM_PAGE_SIZE_IN_BYTES) as u32; - let current_pages = self.capacity; - let additional_pages_required = required_capacity_pages.saturating_sub(current_pages); - - if additional_pages_required > 0 { - self.grow(additional_pages_required)?; - } - - self.memory.stable_write(self.offset as u32, buf); - self.offset += buf.len(); - Ok(buf.len()) + self.0.write(buf) } } impl io::Write for StableWriter { + #[inline] fn write(&mut self, buf: &[u8]) -> Result { - self.write(buf) - .map_err(|e| io::Error::new(io::ErrorKind::OutOfMemory, e)) + io::Write::write(&mut self.0, buf) } + #[inline] fn flush(&mut self) -> Result<(), io::Error> { - // Noop. - Ok(()) + io::Write::flush(&mut self.0) + } +} + +impl io::Seek for StableWriter { + #[inline] + fn seek(&mut self, pos: io::SeekFrom) -> io::Result { + io::Seek::seek(&mut self.0, pos) + } +} + +impl From> for StableWriter { + fn from(io: StableIO) -> Self { + Self(io) } } @@ -253,41 +396,36 @@ impl io::Write for BufferedStableWriter { } } -/// A reader to the stable memory. +impl io::Seek for BufferedStableWriter { + #[inline] + fn seek(&mut self, pos: io::SeekFrom) -> io::Result { + io::Seek::seek(&mut self.inner, pos) + } +} + +// A reader to the stable memory. /// /// Keeps an offset and reads off stable memory consecutively. -pub struct StableReader { - /// The offset of the next read. - offset: usize, - - /// The capacity, in pages. - capacity: u32, - - /// The stable memory to read data from. - memory: M, -} +pub struct StableReader(StableIO); +#[allow(clippy::derivable_impls)] impl Default for StableReader { fn default() -> Self { - Self::with_memory(CanisterStableMemory::default(), 0) + Self(StableIO::default()) } } impl StableReader { /// Creates a new `StableReader` which reads from the selected memory + #[inline] pub fn with_memory(memory: M, offset: usize) -> Self { - let capacity = memory.stable_size(); - - Self { - offset, - capacity, - memory, - } + Self(StableIO::::with_memory(memory, offset as u32)) } /// Returns the offset of the reader + #[inline] pub fn offset(&self) -> usize { - self.offset + self.0.offset() as usize } /// Reads data from the stable memory location specified by an offset. @@ -298,26 +436,29 @@ impl StableReader { /// 1. Create a StableReader /// 2. Write some data to the stable memory which causes it grow /// 3. call `read()` to read the newly written bytes + #[inline] pub fn read(&mut self, buf: &mut [u8]) -> Result { - let capacity_bytes = self.capacity as usize * WASM_PAGE_SIZE_IN_BYTES; - let read_buf = if buf.len() + self.offset > capacity_bytes { - if self.offset < capacity_bytes { - &mut buf[..capacity_bytes - self.offset] - } else { - return Err(StableMemoryError::OutOfBounds); - } - } else { - buf - }; - self.memory.stable_read(self.offset as u32, read_buf); - self.offset += read_buf.len(); - Ok(read_buf.len()) + self.0.read(buf) } } impl io::Read for StableReader { + #[inline] fn read(&mut self, buf: &mut [u8]) -> Result { - self.read(buf).or(Ok(0)) // Read defines EOF to be success + io::Read::read(&mut self.0, buf) + } +} + +impl io::Seek for StableReader { + #[inline] + fn seek(&mut self, pos: io::SeekFrom) -> io::Result { + io::Seek::seek(&mut self.0, pos) + } +} + +impl From> for StableReader { + fn from(io: StableIO) -> Self { + Self(io) } } @@ -352,3 +493,10 @@ impl io::Read for BufferedStableReader { self.inner.read(buf) } } + +impl io::Seek for BufferedStableReader { + #[inline] + fn seek(&mut self, pos: io::SeekFrom) -> io::Result { + io::Seek::seek(&mut self.inner, pos) + } +} diff --git a/src/ic-cdk/src/api/stable/private.rs b/src/ic-cdk/src/api/stable/private.rs new file mode 100644 index 000000000..e5f967b4a --- /dev/null +++ b/src/ic-cdk/src/api/stable/private.rs @@ -0,0 +1,52 @@ +//! Private module for traits that provide implementations for both u32 and u64 address space. + +use super::*; +pub trait AddressSize {} +impl AddressSize for u64 {} +impl AddressSize for u32 {} + +// An internal helper trait to have stable memory API specific to an address size +pub trait StableMemory_ { + fn stable_size_(&self) -> A; + fn stable_grow_(&self, new_pages: A) -> Result; + fn stable_write_(&self, offset: A, buf: &[u8]); + fn stable_read_(&self, offset: A, buf: &mut [u8]); +} + +// Blanket implementation for 32-bit addresses for any stable memory implementation +impl StableMemory_ for M { + fn stable_read_(&self, offset: u32, buf: &mut [u8]) { + StableMemory::stable_read(self, offset, buf) + } + + fn stable_grow_(&self, new_pages: u32) -> Result { + StableMemory::stable_grow(self, new_pages) + } + + fn stable_size_(&self) -> u32 { + StableMemory::stable_size(self) + } + + fn stable_write_(&self, offset: u32, buf: &[u8]) { + StableMemory::stable_write(self, offset, buf) + } +} + +// Blanket implementation for 64-bit addresses for any stable memory implementation +impl StableMemory_ for M { + fn stable_read_(&self, offset: u64, buf: &mut [u8]) { + StableMemory::stable64_read(self, offset, buf) + } + + fn stable_grow_(&self, new_pages: u64) -> Result { + StableMemory::stable64_grow(self, new_pages) + } + + fn stable_size_(&self) -> u64 { + StableMemory::stable64_size(self) + } + + fn stable_write_(&self, offset: u64, buf: &[u8]) { + StableMemory::stable64_write(self, offset, buf) + } +} diff --git a/src/ic-cdk/src/api/stable/tests.rs b/src/ic-cdk/src/api/stable/tests.rs index 03961e3a9..3371e3710 100644 --- a/src/ic-cdk/src/api/stable/tests.rs +++ b/src/ic-cdk/src/api/stable/tests.rs @@ -80,7 +80,7 @@ fn pages_required(bytes_len: usize) -> usize { mod stable_writer_tests { use super::*; use rstest::rstest; - use std::io::Write; + use std::io::{Seek, Write}; #[rstest] #[case(None)] @@ -172,6 +172,26 @@ mod stable_writer_tests { assert_eq!(writer.offset(), WRITE_SIZE); } + #[test] + fn test_seek() { + let memory = Rc::new(Mutex::new(Vec::new())); + let mut writer = StableWriter::with_memory(TestStableMemory::new(memory.clone()), 0); + writer + .seek(std::io::SeekFrom::Start(WASM_PAGE_SIZE_IN_BYTES as u64)) + .unwrap(); + assert_eq!( + writer.stream_position().unwrap() as usize, + WASM_PAGE_SIZE_IN_BYTES + ); + assert_eq!(writer.write(&[1_u8]).unwrap(), 1); + assert_eq!( + writer.seek(std::io::SeekFrom::End(0)).unwrap() as usize, + WASM_PAGE_SIZE_IN_BYTES * 2 + ); + let capacity_pages = TestStableMemory::new(memory).stable64_size(); + assert_eq!(capacity_pages, 2); + } + fn build_writer(memory: TestStableMemory, buffer_size: Option) -> Box { let writer = StableWriter::with_memory(memory, 0); if let Some(buffer_size) = buffer_size { @@ -185,7 +205,7 @@ mod stable_writer_tests { mod stable_reader_tests { use super::*; use rstest::rstest; - use std::io::Read; + use std::io::{Read, Seek}; #[rstest] #[case(None)] @@ -225,6 +245,31 @@ mod stable_reader_tests { assert_eq!(reader.offset(), READ_SIZE); } + #[test] + fn test_seek() { + const SIZE: usize = 1025; + let memory = Rc::new(Mutex::new((0..SIZE).map(|v| v as u8).collect::>())); + let mut reader = StableReader::with_memory(TestStableMemory::new(memory), 0); + let mut bytes = vec![0_u8; 1]; + + const OFFSET: usize = 200; + reader + .seek(std::io::SeekFrom::Start(OFFSET as u64)) + .unwrap(); + assert_eq!(reader.stream_position().unwrap() as usize, OFFSET); + assert_eq!(reader.read(&mut bytes).unwrap(), 1); + assert_eq!(&bytes, &[OFFSET as u8]); + assert_eq!( + reader.seek(std::io::SeekFrom::End(0)).unwrap() as usize, + WASM_PAGE_SIZE_IN_BYTES + ); + reader + .seek(std::io::SeekFrom::Start(WASM_PAGE_SIZE_IN_BYTES as u64 * 2)) + .unwrap(); + // out of bounds so should fail + assert!(reader.read(&mut bytes).is_err()); + } + fn build_reader(memory: TestStableMemory, buffer_size: Option) -> Box { let reader = StableReader::with_memory(memory, 0); if let Some(buffer_size) = buffer_size { From 14666cd5435a1c6c454b297da1d2f3caefa8b24f Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 10 Nov 2022 12:44:25 -0500 Subject: [PATCH 109/234] fix: ic0 can build on non-wasm (#338) * ic0 can build on non-wasm * fix lint * work.rs --- .github/workflows/ci.yml | 1 + src/ic0/Cargo.toml | 6 +- src/ic0/src/ic0.rs | 158 +++++++++++++++++++++++++++++++++++++++ src/ic0/util/ic0build.rs | 53 ++++++++++++- src/ic0/util/work.rs | 6 ++ 5 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 src/ic0/util/work.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f1c2d4e8..3b02a2f4a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,7 @@ jobs: run: | cargo build --workspace --exclude ic-cdk-e2e-tests --target wasm32-unknown-unknown cargo build --workspace --exclude ic-cdk-e2e-tests --target wasm32-unknown-unknown --release + cargo build --example=work test: name: cargo test diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml index ba0b05752..dbe873f4c 100644 --- a/src/ic0/Cargo.toml +++ b/src/ic0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic0" -version = "0.18.5" +version = "0.18.6" authors = ["DFINITY Stiftung "] edition = "2021" description = "Internet Computer System API Binding." @@ -20,3 +20,7 @@ syn = { version = "1.0", features = ["parsing", "full", "extra-traits"] } [[example]] name = "ic0build" path = "util/ic0build.rs" + +[[example]] +name = "work" +path = "util/work.rs" diff --git a/src/ic0/src/ic0.rs b/src/ic0/src/ic0.rs index 33375296f..c5cab172e 100644 --- a/src/ic0/src/ic0.rs +++ b/src/ic0/src/ic0.rs @@ -1,5 +1,6 @@ // This file is generated from ic0.txt. // Don't manually modify it. +#[cfg(target_arch = "wasm32")] #[link(wasm_import_module = "ic0")] extern "C" { pub fn msg_arg_data_size() -> i32; @@ -58,3 +59,160 @@ extern "C" { pub fn debug_print(src: i32, size: i32); pub fn trap(src: i32, size: i32); } + +#[cfg(not(target_arch = "wasm32"))] +#[allow(unused_variables)] +#[allow(clippy::missing_safety_doc)] +#[allow(clippy::too_many_arguments)] +mod non_wasm { + pub unsafe fn msg_arg_data_size() -> i32 { + panic!("msg_arg_data_size should only be called inside canisters."); + } + pub unsafe fn msg_arg_data_copy(dst: i32, offset: i32, size: i32) { + panic!("msg_arg_data_copy should only be called inside canisters."); + } + pub unsafe fn msg_caller_size() -> i32 { + panic!("msg_caller_size should only be called inside canisters."); + } + pub unsafe fn msg_caller_copy(dst: i32, offset: i32, size: i32) { + panic!("msg_caller_copy should only be called inside canisters."); + } + pub unsafe fn msg_reject_code() -> i32 { + panic!("msg_reject_code should only be called inside canisters."); + } + pub unsafe fn msg_reject_msg_size() -> i32 { + panic!("msg_reject_msg_size should only be called inside canisters."); + } + pub unsafe fn msg_reject_msg_copy(dst: i32, offset: i32, size: i32) { + panic!("msg_reject_msg_copy should only be called inside canisters."); + } + pub unsafe fn msg_reply_data_append(src: i32, size: i32) { + panic!("msg_reply_data_append should only be called inside canisters."); + } + pub unsafe fn msg_reply() { + panic!("msg_reply should only be called inside canisters."); + } + pub unsafe fn msg_reject(src: i32, size: i32) { + panic!("msg_reject should only be called inside canisters."); + } + pub unsafe fn msg_cycles_available() -> i64 { + panic!("msg_cycles_available should only be called inside canisters."); + } + pub unsafe fn msg_cycles_available128(dst: i32) { + panic!("msg_cycles_available128 should only be called inside canisters."); + } + pub unsafe fn msg_cycles_refunded() -> i64 { + panic!("msg_cycles_refunded should only be called inside canisters."); + } + pub unsafe fn msg_cycles_refunded128(dst: i32) { + panic!("msg_cycles_refunded128 should only be called inside canisters."); + } + pub unsafe fn msg_cycles_accept(max_amount: i64) -> i64 { + panic!("msg_cycles_accept should only be called inside canisters."); + } + pub unsafe fn msg_cycles_accept128(max_amount_high: i64, max_amount_low: i64, dst: i32) { + panic!("msg_cycles_accept128 should only be called inside canisters."); + } + pub unsafe fn canister_self_size() -> i32 { + panic!("canister_self_size should only be called inside canisters."); + } + pub unsafe fn canister_self_copy(dst: i32, offset: i32, size: i32) { + panic!("canister_self_copy should only be called inside canisters."); + } + pub unsafe fn canister_cycle_balance() -> i64 { + panic!("canister_cycle_balance should only be called inside canisters."); + } + pub unsafe fn canister_cycle_balance128(dst: i32) { + panic!("canister_cycle_balance128 should only be called inside canisters."); + } + pub unsafe fn canister_status() -> i32 { + panic!("canister_status should only be called inside canisters."); + } + pub unsafe fn msg_method_name_size() -> i32 { + panic!("msg_method_name_size should only be called inside canisters."); + } + pub unsafe fn msg_method_name_copy(dst: i32, offset: i32, size: i32) { + panic!("msg_method_name_copy should only be called inside canisters."); + } + pub unsafe fn accept_message() { + panic!("accept_message should only be called inside canisters."); + } + pub unsafe fn call_new( + callee_src: i32, + callee_size: i32, + name_src: i32, + name_size: i32, + reply_fun: i32, + reply_env: i32, + reject_fun: i32, + reject_env: i32, + ) { + panic!("call_new should only be called inside canisters."); + } + pub unsafe fn call_on_cleanup(fun: i32, env: i32) { + panic!("call_on_cleanup should only be called inside canisters."); + } + pub unsafe fn call_data_append(src: i32, size: i32) { + panic!("call_data_append should only be called inside canisters."); + } + pub unsafe fn call_cycles_add(amount: i64) { + panic!("call_cycles_add should only be called inside canisters."); + } + pub unsafe fn call_cycles_add128(amount_high: i64, amount_low: i64) { + panic!("call_cycles_add128 should only be called inside canisters."); + } + pub unsafe fn call_perform() -> i32 { + panic!("call_perform should only be called inside canisters."); + } + pub unsafe fn stable_size() -> i32 { + panic!("stable_size should only be called inside canisters."); + } + pub unsafe fn stable_grow(new_pages: i32) -> i32 { + panic!("stable_grow should only be called inside canisters."); + } + pub unsafe fn stable_write(offset: i32, src: i32, size: i32) { + panic!("stable_write should only be called inside canisters."); + } + pub unsafe fn stable_read(dst: i32, offset: i32, size: i32) { + panic!("stable_read should only be called inside canisters."); + } + pub unsafe fn stable64_size() -> i64 { + panic!("stable64_size should only be called inside canisters."); + } + pub unsafe fn stable64_grow(new_pages: i64) -> i64 { + panic!("stable64_grow should only be called inside canisters."); + } + pub unsafe fn stable64_write(offset: i64, src: i64, size: i64) { + panic!("stable64_write should only be called inside canisters."); + } + pub unsafe fn stable64_read(dst: i64, offset: i64, size: i64) { + panic!("stable64_read should only be called inside canisters."); + } + pub unsafe fn certified_data_set(src: i32, size: i32) { + panic!("certified_data_set should only be called inside canisters."); + } + pub unsafe fn data_certificate_present() -> i32 { + panic!("data_certificate_present should only be called inside canisters."); + } + pub unsafe fn data_certificate_size() -> i32 { + panic!("data_certificate_size should only be called inside canisters."); + } + pub unsafe fn data_certificate_copy(dst: i32, offset: i32, size: i32) { + panic!("data_certificate_copy should only be called inside canisters."); + } + pub unsafe fn time() -> i64 { + panic!("time should only be called inside canisters."); + } + pub unsafe fn performance_counter(counter_type: i32) -> i64 { + panic!("performance_counter should only be called inside canisters."); + } + pub unsafe fn debug_print(src: i32, size: i32) { + panic!("debug_print should only be called inside canisters."); + } + pub unsafe fn trap(src: i32, size: i32) { + panic!("trap should only be called inside canisters."); + } +} + +#[cfg(not(target_arch = "wasm32"))] +pub use non_wasm::*; diff --git a/src/ic0/util/ic0build.rs b/src/ic0/util/ic0build.rs index c32b71388..2d509730a 100644 --- a/src/ic0/util/ic0build.rs +++ b/src/ic0/util/ic0build.rs @@ -118,20 +118,21 @@ fn main() { f, r#"// This file is generated from ic0.txt. // Don't manually modify it. +#[cfg(target_arch = "wasm32")] #[link(wasm_import_module = "ic0")] extern "C" {{"#, ) .unwrap(); - for api in ic0.apis { - let fn_name = api.name; - let args = api.args; + for api in &ic0.apis { + let fn_name = &api.name; + let args = &api.args; let mut r = quote! { pub fn #fn_name(#(#args),*) }; - if let Some(output) = api.output { + if let Some(output) = &api.output { r = quote! { #r -> #output } @@ -143,6 +144,50 @@ extern "C" {{"#, writeln!(f, "}}").unwrap(); + writeln!( + f, + r#" +#[cfg(not(target_arch = "wasm32"))] +#[allow(unused_variables)] +#[allow(clippy::missing_safety_doc)] +#[allow(clippy::too_many_arguments)] +mod non_wasm{{"#, + ) + .unwrap(); + + for api in &ic0.apis { + let fn_name = &api.name; + let args = &api.args; + + let mut r = quote! { + pub unsafe fn #fn_name(#(#args),*) + }; + + if let Some(output) = &api.output { + r = quote! { + #r -> #output + } + } + + let panic_str = format!("{} should only be called inside canisters.", fn_name); + + r = quote! { + #r { + panic!(#panic_str); + }}; + writeln!(f, "{}", r).unwrap(); + } + + writeln!( + f, + r#"}} + +#[cfg(not(target_arch = "wasm32"))] +pub use non_wasm::*; +"# + ) + .unwrap(); + Command::new("cargo") .args(["fmt"]) .output() diff --git a/src/ic0/util/work.rs b/src/ic0/util/work.rs new file mode 100644 index 000000000..3e9253eb1 --- /dev/null +++ b/src/ic0/util/work.rs @@ -0,0 +1,6 @@ +// This file should compile on windows +fn main() { + unsafe { + ic0::trap(0, 0); + } +} From c6bab2f144bd7f344df7662f14aedd4479606fec Mon Sep 17 00:00:00 2001 From: Daniel Bloom <82895745+Daniel-Bloom-dfinity@users.noreply.github.com> Date: Thu, 10 Nov 2022 11:51:35 -0800 Subject: [PATCH 110/234] refactor: make `RbTree` more `const` (#337) * refactor: make `RbTree` more `const` * changelog * bump version Co-authored-by: Linwei Shang --- library/ic-certified-map/CHANGELOG.md | 6 ++++++ library/ic-certified-map/Cargo.toml | 2 +- library/ic-certified-map/src/rbtree.rs | 10 ++++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/library/ic-certified-map/CHANGELOG.md b/library/ic-certified-map/CHANGELOG.md index 4782c12d7..e2af8cc01 100644 --- a/library/ic-certified-map/CHANGELOG.md +++ b/library/ic-certified-map/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +## [0.3.2] - 2022-11-10 +### Changed +Make `RbTree::new` and `RbTree::is_empty` both `const`. + ## [0.3.1] - 2022-09-16 ### Changed - Updated `sha2` dependency. diff --git a/library/ic-certified-map/Cargo.toml b/library/ic-certified-map/Cargo.toml index dd3273ab7..57e2ccd19 100644 --- a/library/ic-certified-map/Cargo.toml +++ b/library/ic-certified-map/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-certified-map" -version = "0.3.1" +version = "0.3.2" edition = "2021" authors = ["DFINITY Stiftung "] description = "Merkleized map data structure." diff --git a/library/ic-certified-map/src/rbtree.rs b/library/ic-certified-map/src/rbtree.rs index 35549fe7c..18322f6ef 100644 --- a/library/ic-certified-map/src/rbtree.rs +++ b/library/ic-certified-map/src/rbtree.rs @@ -268,7 +268,7 @@ impl<'a, K, V> std::iter::Iterator for Iter<'a, K, V> { /// Implements mutable left-leaning red-black trees as defined in /// https://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf #[derive(Default, Clone)] -pub struct RbTree, V: AsHashTree + 'static> { +pub struct RbTree { root: NodeRef, } @@ -345,17 +345,19 @@ where } } -impl, V: AsHashTree + 'static> RbTree { +impl RbTree { /// Constructs a new empty tree. - pub fn new() -> Self { + pub const fn new() -> Self { Self { root: None } } /// Returns true if the map is empty. - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.root.is_none() } +} +impl, V: AsHashTree + 'static> RbTree { pub fn get(&self, key: &[u8]) -> Option<&V> { let mut root = self.root.as_ref(); while let Some(n) = root { From f7ed2ae46bff63e582f6608010608f857bda99fa Mon Sep 17 00:00:00 2001 From: Frederik Rothenberger Date: Wed, 16 Nov 2022 19:26:03 +0100 Subject: [PATCH 111/234] chore: Have a nicer error message on trap while decoding arguments (#339) * chore: Have a nicer error message on trap while decoding arguments I just ran into an issue related to that an it took me longer than necessary to figure out the trap came from code generated by cdk macros. * bump version & changelog Co-authored-by: Linwei Shang --- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 6 ++++++ src/ic-cdk/Cargo.toml | 2 +- src/ic-cdk/src/api/call.rs | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 1c8d319cc..7bb759024 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.6.6" +version = "0.6.7" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index b05a6908b..e468167cf 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.6.7] - 2022-11-16 + +### Changed + +- Improve error message on trap while decoding arguments. (#339) + ## [0.6.6] - 2022-11-09 ### Added diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 2404cfdec..2a8a3cee3 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.6.6" +version = "0.6.7" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 4a5af7ac5..72e8d9d49 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -599,7 +599,7 @@ pub fn arg_data ArgumentDecoder<'a>>() -> R { let bytes = arg_data_raw(); match decode_args(&bytes) { - Err(e) => trap(&format!("{:?}", e)), + Err(e) => trap(&format!("failed to decode call arguments: {:?}", e)), Ok(r) => r, } } From bf65dd5a8673bcd48c9c18f8f6fb2bb74d34d939 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Fri, 18 Nov 2022 19:01:41 -0800 Subject: [PATCH 112/234] feat: reverse dependency order (#343) This PR removes ic-cdk-macros's dependency on ic-cdk, which was only used for an intra-doc link and the reexported `Principal` more easily accessed from Candid. This enables ic-cdk to depend on ic-cdk-macros and reexport its macros; with this change, users no longer need to declare two dependencies for the full CDK. --- README.md | 3 +- .../examples/counter-tutorial/counter.rs | 3 +- .../profile-interoperation.rs | 2 +- .../rust-guide/examples/mul-deps/deps-main.rs | 3 +- .../examples/profile-tutorial/profile.rs | 2 +- .../rust-guide/pages/rust-quickstart.adoc | 2 +- e2e-tests/canisters/api_call.rs | 3 +- e2e-tests/canisters/async.rs | 3 +- e2e-tests/canisters/simple_kv_store.rs | 2 +- .../asset_storage/src/asset_storage_rs/lib.rs | 6 ++- examples/chess/src/chess_rs/lib.rs | 3 +- examples/counter/src/counter_rs/lib.rs | 2 +- examples/counter/src/inter2_rs/lib.rs | 3 +- examples/counter/src/inter_rs/lib.rs | 3 +- .../management_canister/src/caller/lib.rs | 2 +- examples/print/src/print_rs/lib.rs | 2 +- examples/profile/src/profile_inter_rs/lib.rs | 2 +- examples/profile/src/profile_rs/lib.rs | 2 +- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-macros/src/import.rs | 3 +- src/ic-cdk-macros/src/lib.rs | 44 +++++++++---------- ...fecycle_functions_should_have_no_return.rs | 2 +- .../tests/compile_fail/no_generic.rs | 2 +- .../tests/compile_fail/no_self.rs | 2 +- .../tests/compile_fail/only_function.rs | 2 +- src/ic-cdk-macros/tests/pass/blank_methods.rs | 2 +- src/ic-cdk/Cargo.toml | 1 + .../api/management_canister/http_request.rs | 16 ++++--- src/ic-cdk/src/lib.rs | 3 ++ 29 files changed, 64 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 78828c317..c5134335c 100644 --- a/README.md +++ b/README.md @@ -46,13 +46,12 @@ crate-type = ["cdylib"] [dependencies] candid = "0.8.0" # this is required if you want to use the `#[import]` macro ic-cdk = "0.6" -ic-cdk-macros = "0.6" ``` Then in your rust source code: ```rust -#[ic_cdk_macros::query] +#[ic_cdk::query] fn print() { ic_cdk::print("Hello World from DFINITY!"); } diff --git a/docs/modules/rust-guide/examples/counter-tutorial/counter.rs b/docs/modules/rust-guide/examples/counter-tutorial/counter.rs index b29154b18..cbfa47f8e 100644 --- a/docs/modules/rust-guide/examples/counter-tutorial/counter.rs +++ b/docs/modules/rust-guide/examples/counter-tutorial/counter.rs @@ -1,5 +1,4 @@ -use ic_cdk_macros::*; -use ic_cdk::export::candid; +use ic_cdk::{export::candid, init, query, update}; static mut COUNTER: Option = None; diff --git a/docs/modules/rust-guide/examples/intercanister-tutorial/profile-interoperation.rs b/docs/modules/rust-guide/examples/intercanister-tutorial/profile-interoperation.rs index 31078f647..09973919e 100644 --- a/docs/modules/rust-guide/examples/intercanister-tutorial/profile-interoperation.rs +++ b/docs/modules/rust-guide/examples/intercanister-tutorial/profile-interoperation.rs @@ -1,4 +1,4 @@ -use ic_cdk_macros::*; +use ic_cdk::{import, update}; #[import(canister = "rust_profile")] struct ProfileCanister; diff --git a/docs/modules/rust-guide/examples/mul-deps/deps-main.rs b/docs/modules/rust-guide/examples/mul-deps/deps-main.rs index 8f9ecbe02..34f2dc9a8 100644 --- a/docs/modules/rust-guide/examples/mul-deps/deps-main.rs +++ b/docs/modules/rust-guide/examples/mul-deps/deps-main.rs @@ -1,5 +1,4 @@ -use ic_cdk_macros::*; -use ic_cdk::export::candid; +use ic_cdk::{import, update, export::candid}; #[import(canister = "multiply_deps")] struct CounterCanister; diff --git a/docs/modules/rust-guide/examples/profile-tutorial/profile.rs b/docs/modules/rust-guide/examples/profile-tutorial/profile.rs index bed2c2e73..a0e98132a 100644 --- a/docs/modules/rust-guide/examples/profile-tutorial/profile.rs +++ b/docs/modules/rust-guide/examples/profile-tutorial/profile.rs @@ -4,8 +4,8 @@ use ic_cdk::{ candid::{CandidType, Deserialize}, Principal, }, + query, update, }; -use ic_cdk_macros::*; use std::cell::RefCell; use std::collections::BTreeMap; diff --git a/docs/modules/rust-guide/pages/rust-quickstart.adoc b/docs/modules/rust-guide/pages/rust-quickstart.adoc index aa71f3ac3..9f2fa7ded 100644 --- a/docs/modules/rust-guide/pages/rust-quickstart.adoc +++ b/docs/modules/rust-guide/pages/rust-quickstart.adoc @@ -148,7 +148,7 @@ The default project has a simple `+greet+` function that uses the {cdk-short-nam [source,rust] ---- -#[ic_cdk_macros::query] +#[ic_cdk::query] fn greet(name: String) -> String { format!("Hello, {}!", name) } diff --git a/e2e-tests/canisters/api_call.rs b/e2e-tests/canisters/api_call.rs index bff8b6fe6..7603147b1 100644 --- a/e2e-tests/canisters/api_call.rs +++ b/e2e-tests/canisters/api_call.rs @@ -1,5 +1,4 @@ -use ic_cdk::api::call::ManualReply; -use ic_cdk_macros::query; +use ic_cdk::{api::call::ManualReply, query}; #[query] fn instruction_counter() -> u64 { diff --git a/e2e-tests/canisters/async.rs b/e2e-tests/canisters/async.rs index c24db8df5..b3786382f 100644 --- a/e2e-tests/canisters/async.rs +++ b/e2e-tests/canisters/async.rs @@ -1,5 +1,4 @@ -use ic_cdk::export::Principal; -use ic_cdk_macros::{query, update}; +use ic_cdk::{export::Principal, query, update}; use lazy_static::lazy_static; use std::sync::RwLock; diff --git a/e2e-tests/canisters/simple_kv_store.rs b/e2e-tests/canisters/simple_kv_store.rs index 632ec861c..fe754ae1d 100644 --- a/e2e-tests/canisters/simple_kv_store.rs +++ b/e2e-tests/canisters/simple_kv_store.rs @@ -1,4 +1,4 @@ -use ic_cdk_macros::{post_upgrade, pre_upgrade, query, update}; +use ic_cdk::{post_upgrade, pre_upgrade, query, update}; use serde_bytes::ByteBuf; use std::cell::RefCell; use std::collections::BTreeMap; diff --git a/examples/asset_storage/src/asset_storage_rs/lib.rs b/examples/asset_storage/src/asset_storage_rs/lib.rs index 2e31e272c..a37feec57 100644 --- a/examples/asset_storage/src/asset_storage_rs/lib.rs +++ b/examples/asset_storage/src/asset_storage_rs/lib.rs @@ -1,5 +1,7 @@ -use ic_cdk::{api::call::ManualReply, export::Principal, storage}; -use ic_cdk_macros::*; +use ic_cdk::{ + api::call::ManualReply, export::Principal, init, post_upgrade, pre_upgrade, query, storage, + update, +}; use std::cell::RefCell; use std::collections::{BTreeMap, BTreeSet}; diff --git a/examples/chess/src/chess_rs/lib.rs b/examples/chess/src/chess_rs/lib.rs index 961d7606d..e5db890c9 100644 --- a/examples/chess/src/chess_rs/lib.rs +++ b/examples/chess/src/chess_rs/lib.rs @@ -1,5 +1,4 @@ -use ic_cdk::export::candid::CandidType; -use ic_cdk_macros::*; +use ic_cdk::{export::candid::CandidType, query, update}; use pleco::tools::Searcher; use serde::Serialize; use std::cell::RefCell; diff --git a/examples/counter/src/counter_rs/lib.rs b/examples/counter/src/counter_rs/lib.rs index 54571abe5..57afc8aa4 100644 --- a/examples/counter/src/counter_rs/lib.rs +++ b/examples/counter/src/counter_rs/lib.rs @@ -1,8 +1,8 @@ use ic_cdk::{ api::call::ManualReply, export::{candid, Principal}, + init, query, update, }; -use ic_cdk_macros::*; use std::cell::{Cell, RefCell}; thread_local! { diff --git a/examples/counter/src/inter2_rs/lib.rs b/examples/counter/src/inter2_rs/lib.rs index 664b9212b..946acc6b1 100644 --- a/examples/counter/src/inter2_rs/lib.rs +++ b/examples/counter/src/inter2_rs/lib.rs @@ -1,5 +1,4 @@ -use ic_cdk::export::candid; -use ic_cdk_macros::*; +use ic_cdk::{export::candid, import, update}; #[import(canister = "inter_mo")] struct CounterCanister; diff --git a/examples/counter/src/inter_rs/lib.rs b/examples/counter/src/inter_rs/lib.rs index bc400cc5a..b89dc49b6 100644 --- a/examples/counter/src/inter_rs/lib.rs +++ b/examples/counter/src/inter_rs/lib.rs @@ -1,5 +1,4 @@ -use ic_cdk::export::candid; -use ic_cdk_macros::*; +use ic_cdk::{export::candid, import, update}; #[import(canister = "counter_mo")] struct CounterCanister; diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index 49f42a0b2..8003e4212 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -1,4 +1,4 @@ -use ic_cdk_macros::*; +use ic_cdk::*; mod main { use super::*; diff --git a/examples/print/src/print_rs/lib.rs b/examples/print/src/print_rs/lib.rs index 160987650..c0fb4cfba 100644 --- a/examples/print/src/print_rs/lib.rs +++ b/examples/print/src/print_rs/lib.rs @@ -1,4 +1,4 @@ -#[ic_cdk_macros::query] +#[ic_cdk::query] fn print() { ic_cdk::print("Hello World"); } diff --git a/examples/profile/src/profile_inter_rs/lib.rs b/examples/profile/src/profile_inter_rs/lib.rs index ccb83c710..65e6e58b5 100644 --- a/examples/profile/src/profile_inter_rs/lib.rs +++ b/examples/profile/src/profile_inter_rs/lib.rs @@ -1,4 +1,4 @@ -use ic_cdk_macros::*; +use ic_cdk::{import, update}; #[import(canister = "profile_rs")] struct ProfileCanister; diff --git a/examples/profile/src/profile_rs/lib.rs b/examples/profile/src/profile_rs/lib.rs index d48ae68a0..64a4e2369 100644 --- a/examples/profile/src/profile_rs/lib.rs +++ b/examples/profile/src/profile_rs/lib.rs @@ -4,8 +4,8 @@ use ic_cdk::{ candid::{CandidType, Deserialize}, Principal, }, + query, update, }; -use ic_cdk_macros::*; use std::cell::RefCell; use std::collections::BTreeMap; diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 7bb759024..1f6f30d5e 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -19,7 +19,6 @@ proc-macro = true [dependencies] candid = "0.8.0" -ic-cdk = { path = "../ic-cdk", version = "0.6" } syn = { version = "1.0.58", features = ["fold", "full"] } quote = "1.0" proc-macro2 = "1.0" @@ -28,3 +27,4 @@ serde = "1.0.111" [dev-dependencies] trybuild = "1.0" +ic-cdk = { path = "../ic-cdk", version = "0.6" } diff --git a/src/ic-cdk-macros/src/import.rs b/src/ic-cdk-macros/src/import.rs index 4665b3735..044d27c03 100644 --- a/src/ic-cdk-macros/src/import.rs +++ b/src/ic-cdk-macros/src/import.rs @@ -82,8 +82,7 @@ impl candid::codegen::rust::RustBindings for RustLanguageBinding { // We check the validity of the canister_id early so it fails if the // ID isn't in the right text format. - let principal: ic_cdk::export::Principal = - ic_cdk::export::Principal::from_text(canister_id).unwrap(); + let principal: candid::Principal = candid::Principal::from_text(canister_id).unwrap(); Ok(format!( r#" diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index d38097117..0cb0cf0f2 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -71,7 +71,7 @@ where /// # Example /// /// ```rust -/// # use ic_cdk_macros::query; +/// # use ic_cdk::query; /// #[query] /// fn query_function() { /// // ... @@ -82,7 +82,7 @@ where /// You can also specify the name of the exported function. /// /// ```rust -/// # use ic_cdk_macros::*; +/// # use ic_cdk::query; /// #[query(name = "some_name")] /// fn query_function() { /// // ... @@ -94,7 +94,7 @@ where /// When the guard function returns an error, the query function will not proceed. /// /// ```rust -/// # use ic_cdk_macros::*; +/// # use ic_cdk::query; /// fn guard_function() -> Result<(), String> { /// // ... /// # unimplemented!() @@ -113,7 +113,7 @@ where /// ```rust /// # fn calculate_result() {} /// # type MyResult = (); -/// # use ic_cdk_macros::query; +/// # use ic_cdk::query; /// use ic_cdk::api::call::{self, ManualReply}; /// #[query(manual_reply = true)] /// fn query_function() -> ManualReply { @@ -122,7 +122,7 @@ where /// } /// ``` /// -/// [`call::reply`]: ic_cdk::api::call::reply +/// [`call::reply`]: https://docs.rs/ic-cdk/latest/ic_cdk/api/call/fn.reply.html #[proc_macro_attribute] pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_query, "ic_query", attr, item) @@ -136,7 +136,7 @@ pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { /// # Example /// /// ```rust -/// # use ic_cdk_macros::update; +/// # use ic_cdk::update; /// #[update] /// fn update_function() { /// // ... @@ -147,7 +147,7 @@ pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { /// You can also specify the name of the exported function. /// /// ```rust -/// # use ic_cdk_macros::*; +/// # use ic_cdk::update; /// #[update(name = "some_name")] /// fn update_function() { /// // ... @@ -159,7 +159,7 @@ pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { /// When the guard function returns an error, the update function will not proceed. /// /// ```rust -/// # use ic_cdk_macros::*; +/// # use ic_cdk::update; /// fn guard_function() -> Result<(), String> { /// // ... /// # unimplemented!() @@ -178,7 +178,7 @@ pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { /// ```rust /// # fn calculate_result() {} /// # type MyResult = (); -/// # use ic_cdk_macros::update; +/// # use ic_cdk::update; /// use ic_cdk::api::call::{self, ManualReply}; /// #[update(manual_reply = true)] /// fn update_function() -> ManualReply { @@ -205,7 +205,7 @@ pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream { /// # Example /// /// ```rust -/// # use ic_cdk_macros::init; +/// # use ic_cdk::init; /// #[init] /// fn init_function() { /// // ... @@ -217,7 +217,7 @@ pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream { /// When the guard function returns an error, the init function will not proceed. /// /// ```rust -/// # use ic_cdk_macros::*; +/// # use ic_cdk::init; /// fn guard_function() -> Result<(), String> { /// // ... /// # unimplemented!() @@ -232,7 +232,7 @@ pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream { /// The init function may accept an argument, if that argument is a `CandidType`: /// /// ```rust -/// # use ic_cdk_macros::*; +/// # use ic_cdk::init; /// # use candid::*; /// /// #[derive(Clone, Debug, CandidType, Deserialize)] @@ -267,7 +267,7 @@ pub fn init(attr: TokenStream, item: TokenStream) -> TokenStream { /// # Example /// /// ```rust -/// # use ic_cdk_macros::pre_upgrade; +/// # use ic_cdk::pre_upgrade; /// #[pre_upgrade] /// fn pre_upgrade_function() { /// // ... @@ -279,7 +279,7 @@ pub fn init(attr: TokenStream, item: TokenStream) -> TokenStream { /// When the guard function returns an error, the pre_upgrade function will not proceed. /// /// ```rust -/// # use ic_cdk_macros::*; +/// # use ic_cdk::pre_upgrade; /// fn guard_function() -> Result<(), String> { /// // ... /// # unimplemented!() @@ -307,7 +307,7 @@ pub fn pre_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { /// # Example /// /// ```rust -/// # use ic_cdk_macros::post_upgrade; +/// # use ic_cdk::post_upgrade; /// #[post_upgrade] /// fn post_upgrade_function() { /// // ... @@ -319,7 +319,7 @@ pub fn pre_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { /// When the guard function returns an error, the post_upgrade function will not proceed. /// /// ```rust -/// # use ic_cdk_macros::*; +/// # use ic_cdk::post_upgrade /// fn guard_function() -> Result<(), String> { /// // ... /// # unimplemented!() @@ -347,7 +347,7 @@ pub fn post_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { /// # Example /// /// ```rust -/// # use ic_cdk_macros::heartbeat; +/// # use ic_cdk::heartbeat; /// #[heartbeat] /// fn heartbeat_function() { /// // ... @@ -359,7 +359,7 @@ pub fn post_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { /// When the guard function returns an error, the heartbeat function will not proceed. /// /// ```rust -/// # use ic_cdk_macros::*; +/// # use ic_cdk::heartbeat; /// fn guard_function() -> Result<(), String> { /// // ... /// # unimplemented!() @@ -387,7 +387,7 @@ pub fn heartbeat(attr: TokenStream, item: TokenStream) -> TokenStream { /// # Example /// /// ```rust -/// # use ic_cdk_macros::inspect_message; +/// # use ic_cdk::inspect_message; /// #[inspect_message] /// fn inspect_message_function() { /// // ... @@ -399,7 +399,7 @@ pub fn heartbeat(attr: TokenStream, item: TokenStream) -> TokenStream { /// When the guard function returns an error, the inspect_message function will not proceed. /// /// ```rust -/// # use ic_cdk_macros::*; +/// # use ic_cdk::*; /// fn guard_function() -> Result<(), String> { /// // ... /// # unimplemented!() @@ -428,7 +428,7 @@ pub fn inspect_message(attr: TokenStream, item: TokenStream) -> TokenStream { /// During `dfx build`, the imported canister will be correctly resolved. /// /// ```rust,ignore -/// # use ic_cdk_macros::import; +/// # use ic_cdk::import; /// #[import(canister = "some_canister")] /// struct SomeCanister; /// ``` @@ -436,7 +436,7 @@ pub fn inspect_message(attr: TokenStream, item: TokenStream) -> TokenStream { /// Or you can specify both the `canister_id` and the `candid_path`. /// /// ```rust,ignore -/// # use ic_cdk_macros::import; +/// # use ic_cdk::import; /// #[import(canister_id = "abcde-cai", candid_path = "path/to/some_canister.did")] /// struct SomeCanister; /// ``` diff --git a/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_should_have_no_return.rs b/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_should_have_no_return.rs index 0e6a675ea..3d52f5cff 100644 --- a/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_should_have_no_return.rs +++ b/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_should_have_no_return.rs @@ -1,4 +1,4 @@ -use ic_cdk_macros::*; +use ic_cdk::{heartbeat, init, inspect_message, post_upgrade, pre_upgrade}; #[init] fn init() -> u32 {} diff --git a/src/ic-cdk-macros/tests/compile_fail/no_generic.rs b/src/ic-cdk-macros/tests/compile_fail/no_generic.rs index 7e79d1b79..2e72bd1b7 100644 --- a/src/ic-cdk-macros/tests/compile_fail/no_generic.rs +++ b/src/ic-cdk-macros/tests/compile_fail/no_generic.rs @@ -1,4 +1,4 @@ -use ic_cdk_macros::query; +use ic_cdk::query; #[query] fn method(_arg: T) {} diff --git a/src/ic-cdk-macros/tests/compile_fail/no_self.rs b/src/ic-cdk-macros/tests/compile_fail/no_self.rs index 4a76c86ae..72d806b65 100644 --- a/src/ic-cdk-macros/tests/compile_fail/no_self.rs +++ b/src/ic-cdk-macros/tests/compile_fail/no_self.rs @@ -1,4 +1,4 @@ -use ic_cdk_macros::query; +use ic_cdk::query; #[query] fn method(self) {} diff --git a/src/ic-cdk-macros/tests/compile_fail/only_function.rs b/src/ic-cdk-macros/tests/compile_fail/only_function.rs index a6585a28d..d995b7fe2 100644 --- a/src/ic-cdk-macros/tests/compile_fail/only_function.rs +++ b/src/ic-cdk-macros/tests/compile_fail/only_function.rs @@ -1,4 +1,4 @@ -use ic_cdk_macros::query; +use ic_cdk::query; #[query] struct S; diff --git a/src/ic-cdk-macros/tests/pass/blank_methods.rs b/src/ic-cdk-macros/tests/pass/blank_methods.rs index 911aad919..c27136ca1 100644 --- a/src/ic-cdk-macros/tests/pass/blank_methods.rs +++ b/src/ic-cdk-macros/tests/pass/blank_methods.rs @@ -1,4 +1,4 @@ -use ic_cdk_macros::*; +use ic_cdk::{heartbeat, init, inspect_message, post_upgrade, pre_upgrade, query, update}; #[init] fn init() {} diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 2a8a3cee3..b0ebb569d 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -20,6 +20,7 @@ cfg-if = "1.0.0" serde = "1.0.110" serde_bytes = "0.11.7" ic0 = { path = "../ic0", version = "0.18.4" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.6.7" } [dev-dependencies] rstest = "0.12.0" diff --git a/src/ic-cdk/src/api/management_canister/http_request.rs b/src/ic-cdk/src/api/management_canister/http_request.rs index 6b6beb52b..122d6a63a 100644 --- a/src/ic-cdk/src/api/management_canister/http_request.rs +++ b/src/ic-cdk/src/api/management_canister/http_request.rs @@ -58,17 +58,21 @@ pub struct TransformContext { } impl TransformContext { - /// Construct `TransformType` from a transform function. + /// Construct `TransformContext` from a transform function. /// /// # example /// - /// ```ignore - /// #[ic_cdk_macros::query] + /// ```no_run + /// # use ic_cdk::api::management_canister::http_request::{TransformContext, TransformArgs, HttpResponse}; + /// #[ic_cdk::query] /// fn my_transform(arg: TransformArgs) -> HttpResponse { - /// ... + /// // ... + /// # unimplemented!() /// } - /// - /// let transform = TransformType::from_transform_function(my_transform); + /// # fn main() { + /// # let context = vec![]; + /// let transform = TransformContext::new(my_transform, context); + /// # } /// ``` pub fn new(func: T, context: Vec) -> Self where diff --git a/src/ic-cdk/src/lib.rs b/src/ic-cdk/src/lib.rs index 0796f3528..43e4e78ef 100644 --- a/src/ic-cdk/src/lib.rs +++ b/src/ic-cdk/src/lib.rs @@ -9,6 +9,9 @@ #[cfg(target_feature = "atomics")] compile_error!("This version of the CDK does not support multithreading."); +#[doc(inline)] +pub use ic_cdk_macros::*; + pub mod api; mod futures; mod printer; From b8b0ff292435546dab9eb4d2f1aba7ab7b183d6b Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Tue, 22 Nov 2022 17:15:53 -0800 Subject: [PATCH 113/234] chore: Add safety comments (#248) It is good practice, with associated lints, to put `# Safety` on any unsafe function, prefix any unsafe block with `// SAFETY:`, and use explicit unsafe blocks even in unsafe functions, to document where unsafety is, and what true facts about the code are sufficient proof that the operation is safe. This PR adds safety docs to existing unsafe code (and marks some incorrect code to be fixed in a future PR). --- src/ic-cdk/src/api/call.rs | 95 +++++++++++++++++++++------ src/ic-cdk/src/api/mod.rs | 14 ++++ src/ic-cdk/src/api/stable/canister.rs | 8 +++ src/ic-cdk/src/api/stable/mod.rs | 3 + src/ic-cdk/src/futures.rs | 48 ++++++++++---- src/ic-cdk/src/lib.rs | 21 +++--- 6 files changed, 150 insertions(+), 39 deletions(-) diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 72e8d9d49..3dc23c142 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -9,7 +9,10 @@ use std::pin::Pin; use std::sync::atomic::Ordering; use std::task::{Context, Poll, Waker}; -#[cfg(target_arch = "wasm32-unknown-unknown")] +#[cfg(all( + target_arch = "wasm32-unknown-unknown", + not(target_feature = "atomics") +))] #[allow(dead_code)] mod rc { use std::cell::{RefCell, RefMut}; @@ -42,7 +45,8 @@ mod rc { pub fn into_raw(self) -> *const InnerCell { Rc::into_raw(self.0) } - #[allow(clippy::missing_safety_doc)] + /// # Safety + /// The pointer must have been created with [`into_raw`]. pub unsafe fn from_raw(ptr: *const InnerCell) -> Self { Self(Rc::from_raw(ptr)) } @@ -94,9 +98,11 @@ mod rc { pub fn into_raw(self) -> *const InnerCell { Arc::into_raw(self.0) } - #[allow(clippy::missing_safety_doc)] + /// # Safety + /// The pointer must have been created with [`into_raw`]. pub unsafe fn from_raw(ptr: *const InnerCell) -> Self { - Self(Arc::from_raw(ptr)) + // SAFETY: If the pointer was created from into_raw, it internally was created from Arc::into_raw. + Self(unsafe { Arc::from_raw(ptr) }) } pub fn borrow_mut(&self) -> MutexGuard<'_, T> { self.0.lock().unwrap() @@ -111,6 +117,7 @@ mod rc { #[allow(unused_mut)] fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { + // SAFETY: this is a projection of self, which is pinned unsafe { Pin::new_unchecked(&mut *self.0.lock().unwrap()) }.poll(ctx) } } @@ -199,7 +206,12 @@ impl Future for CallFuture { /// The callback from IC dereferences the future from a raw pointer, assigns the /// result and calls the waker. We cannot use a closure here because we pass raw /// pointers to the System and back. -fn callback(state_ptr: *const InnerCell>>) { +/// +/// # Safety +/// +/// This function must only be passed to the IC with a pointer from WasmCell::into_raw as userdata. +unsafe fn callback(state_ptr: *const InnerCell>>) { + // SAFETY: This function is only ever called by the IC, and we only ever pass a WasmCell as userdata. let state = unsafe { WasmCell::from_raw(state_ptr) }; // Make sure to un-borrow_mut the state. { @@ -219,7 +231,12 @@ fn callback(state_ptr: *const InnerCell>>) { /// This function is called when [callback] was just called with the same parameter, and trapped. /// We can't guarantee internal consistency at this point, but we can at least e.g. drop mutex guards. /// Waker is a very opaque API, so the best we can do is set a global flag and proceed normally. -fn cleanup(state_ptr: *const InnerCell>>) { +/// +/// # Safety +/// +/// This function must only be passed to the IC with a pointer from WasmCell::into_raw as userdata. +unsafe fn cleanup(state_ptr: *const InnerCell>>) { + // SAFETY: This function is only ever called by the IC, and we only ever pass a WasmCell as userdata. let state = unsafe { WasmCell::from_raw(state_ptr) }; // We set the call result, even though it won't be read on the // default executor, because we can't guarantee it was called on @@ -246,6 +263,7 @@ fn add_payment(payment: u128) { } let high = (payment >> 64) as u64; let low = (payment & u64::MAX as u128) as u64; + // SAFETY: ic0.call_cycles_add128 is always safe to call. unsafe { ic0::call_cycles_add128(high as i64, low as i64); } @@ -303,6 +321,14 @@ pub fn notify_raw( // is not a valid function. See // https://www.joachim-breitner.de/blog/789-Zero-downtime_upgrades_of_Internet_Computer_canisters#one-way-calls // for more context. + + // SAFETY: + // `callee`, being &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_new. + // `method`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.call_new. + // -1, i.e. usize::MAX, is a function pointer the wasm module cannot possibly contain, and therefore can be passed as both reply and reject fn for ic0.call_new. + // Since the callback function will never be called, any value can be passed as its context parameter, and therefore -1 can be passed for those values. + // `args`, being a &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_data_append. + // ic0.call_perform is always safe to call. let err_code = unsafe { ic0::call_new( callee.as_ptr() as i32, @@ -333,7 +359,9 @@ pub fn call_raw( ) -> impl Future>> { call_raw_internal(id, method, args_raw, move || { if payment > 0 { + // SAFETY: ic0.call_cycles_add is always safe to call. unsafe { + // This is called as part of the call_new lifecycle, and so will not trap. ic0::call_cycles_add(payment as i64); } } @@ -364,6 +392,15 @@ fn call_raw_internal( waker: None, }); let state_ptr = WasmCell::into_raw(state.clone()); + // SAFETY: + // `callee`, being &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_new. + // `method`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.call_new. + // `callback` is a function with signature (env : i32) -> () and therefore can be called as both reply and reject fn for ic0.call_new. + // `state_ptr` is a pointer created via WasmCell::into_raw, and can therefore be passed as the userdata for `callback`. + // `args`, being a &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_data_append. + // `cleanup` is a function with signature (env : i32) -> () and therefore can be called as a cleanup fn for ic0.call_on_cleanup. + // `state_ptr` is a pointer created via WasmCell::into_raw, and can therefore be passed as the userdata for `cleanup`. + // ic0.call_perform is always safe to call. let err_code = unsafe { ic0::call_new( callee.as_ptr() as i32, @@ -466,33 +503,38 @@ pub fn result ArgumentDecoder<'a>>() -> Result { /// Returns the rejection code for the call. pub fn reject_code() -> RejectionCode { + // SAFETY: ic0.msg_reject_code is always safe to call. let code = unsafe { ic0::msg_reject_code() }; RejectionCode::from(code) } /// Returns the rejection message. pub fn reject_message() -> String { + // SAFETY: ic0.msg_reject_msg_size is always safe to call. let len: u32 = unsafe { ic0::msg_reject_msg_size() as u32 }; let mut bytes = vec![0u8; len as usize]; + // SAFETY: `bytes`, being mutable and allocated to `len` bytes, is safe to pass to ic0.msg_reject_msg_copy with no offset unsafe { ic0::msg_reject_msg_copy(bytes.as_mut_ptr() as i32, 0, len as i32); } - String::from_utf8_lossy(&bytes).to_string() + String::from_utf8_lossy(&bytes).into_owned() } /// Rejects the current call with the message. pub fn reject(message: &str) { let err_message = message.as_bytes(); + // SAFETY: `err_message`, being &[u8], is a readable sequence of bytes, and therefore valid to pass to ic0.msg_reject. unsafe { ic0::msg_reject(err_message.as_ptr() as i32, err_message.len() as i32); } } -/// An io::Writer for message replies. +/// An io::Write for message replies. pub struct CallReplyWriter; impl std::io::Write for CallReplyWriter { fn write(&mut self, buf: &[u8]) -> std::io::Result { + // SAFETY: buf, being &[u8], is a readable sequence of bytes, and therefore valid to pass to ic0.msg_reply_data_append. unsafe { ic0::msg_reply_data_append(buf.as_ptr() as i32, buf.len() as i32); } @@ -507,6 +549,7 @@ impl std::io::Write for CallReplyWriter { /// Replies to the current call with a candid argument. pub fn reply(reply: T) { write_args(&mut CallReplyWriter, reply).expect("Could not encode reply."); + // SAFETY: ic0.msg_reply is always safe to call. unsafe { ic0::msg_reply(); } @@ -515,6 +558,7 @@ pub fn reply(reply: T) { /// Returns the amount of cycles that were transferred by the caller /// of the current call, and is still available in this message. pub fn msg_cycles_available() -> u64 { + // SAFETY: ic0.msg_cycles_available is always safe to call. unsafe { ic0::msg_cycles_available() as u64 } } @@ -522,6 +566,7 @@ pub fn msg_cycles_available() -> u64 { /// of the current call, and is still available in this message. pub fn msg_cycles_available128() -> u128 { let mut recv = 0u128; + // SAFETY: recv is writable and sixteen bytes wide, and therefore is safe to pass to ic0.msg_cycles_available128 unsafe { ic0::msg_cycles_available128(&mut recv as *mut u128 as i32); } @@ -532,6 +577,7 @@ pub fn msg_cycles_available128() -> u128 { /// /// The refund has already been added to the canister balance automatically. pub fn msg_cycles_refunded() -> u64 { + // SAFETY: ic0.msg_cycles_refunded is always safe to call unsafe { ic0::msg_cycles_refunded() as u64 } } @@ -540,6 +586,7 @@ pub fn msg_cycles_refunded() -> u64 { /// The refund has already been added to the canister balance automatically. pub fn msg_cycles_refunded128() -> u128 { let mut recv = 0u128; + // SAFETY: recv is writable and sixteen bytes wide, and therefore is safe to pass to ic0.msg_cycles_refunded128 unsafe { ic0::msg_cycles_refunded128(&mut recv as *mut u128 as i32); } @@ -550,7 +597,7 @@ pub fn msg_cycles_refunded128() -> u128 { /// /// The actual amount moved will be returned. pub fn msg_cycles_accept(max_amount: u64) -> u64 { - // TODO: should we assert the u64 input is within the range of i64? + // SAFETY: ic0.msg_cycles_accept is always safe to call. unsafe { ic0::msg_cycles_accept(max_amount as i64) as u64 } } @@ -561,6 +608,7 @@ pub fn msg_cycles_accept128(max_amount: u128) -> u128 { let high = (max_amount >> 64) as u64; let low = (max_amount & u64::MAX as u128) as u64; let mut recv = 0u128; + // SAFETY: `recv` is writable and sixteen bytes wide, and therefore safe to pass to ic0.msg_cycles_accept128 unsafe { ic0::msg_cycles_accept128(high as i64, low as i64, &mut recv as *mut u128 as i32); } @@ -569,28 +617,33 @@ pub fn msg_cycles_accept128(max_amount: u128) -> u128 { /// Returns the argument data as bytes. pub fn arg_data_raw() -> Vec { + // SAFETY: ic0.msg_arg_data_size is always safe to call. + let len: usize = unsafe { ic0::msg_arg_data_size() as usize }; + let mut bytes = Vec::with_capacity(len); + // SAFETY: + // `bytes`, being mutable and allocated to `len` bytes, is safe to pass to ic0.msg_arg_data_copy with no offset + // ic0.msg_arg_data_copy writes to all of `bytes[0..len]`, so `set_len` is safe to call with the new len. unsafe { - let len: usize = ic0::msg_arg_data_size() as usize; - let mut bytes = Vec::with_capacity(len); ic0::msg_arg_data_copy(bytes.as_mut_ptr() as i32, 0, len as i32); bytes.set_len(len); - bytes } + bytes } /// Get the len of the raw-argument-data-bytes. pub fn arg_data_raw_size() -> usize { + // SAFETY: ic0.msg_arg_data_size is always safe to call. unsafe { ic0::msg_arg_data_size() as usize } } /// Replies with the bytes passed pub fn reply_raw(buf: &[u8]) { - unsafe { - if !buf.is_empty() { - ic0::msg_reply_data_append(buf.as_ptr() as i32, buf.len() as i32) - }; - ic0::msg_reply(); - } + if !buf.is_empty() { + // SAFETY: `buf`, being &[u8], is a readable sequence of bytes, and therefore valid to pass to ic0.msg_reject. + unsafe { ic0::msg_reply_data_append(buf.as_ptr() as i32, buf.len() as i32) } + }; + // SAFETY: ic0.msg_reply is always safe to call. + unsafe { ic0::msg_reply() }; } /// Returns the argument data in the current call. Traps if the data cannot be @@ -606,6 +659,7 @@ pub fn arg_data ArgumentDecoder<'a>>() -> R { /// Accepts the ingress message. pub fn accept_message() { + // SAFETY: ic0.accept_message is always safe to call. unsafe { ic0::accept_message(); } @@ -613,12 +667,14 @@ pub fn accept_message() { /// Returns the name of current canister method. pub fn method_name() -> String { + // SAFETY: ic0.msg_method_name_size is always safe to call. let len: u32 = unsafe { ic0::msg_method_name_size() as u32 }; let mut bytes = vec![0u8; len as usize]; + // SAFETY: `bytes` is writable and allocated to `len` bytes, and therefore can be safely passed to ic0.msg_method_name_copy unsafe { ic0::msg_method_name_copy(bytes.as_mut_ptr() as i32, 0, len as i32); } - String::from_utf8_lossy(&bytes).to_string() + String::from_utf8_lossy(&bytes).into_owned() } /// Get the value of specified performance counter @@ -626,6 +682,7 @@ pub fn method_name() -> String { /// Supported counter type: /// 0 : instruction counter. The number of WebAssembly instructions the system has determined that the canister has executed. pub fn performance_counter(counter_type: u32) -> u64 { + // SAFETY: ic0.performance_counter is always safe to call. unsafe { ic0::performance_counter(counter_type as i32) as u64 } } diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index f80c41305..1395c646f 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -9,6 +9,7 @@ pub mod stable; /// Prints the given message. pub fn print>(s: S) { let s = s.as_ref(); + // SAFETY: `s`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.debug_print. unsafe { ic0::debug_print(s.as_ptr() as i32, s.len() as i32); } @@ -16,6 +17,7 @@ pub fn print>(s: S) { /// Traps with the given message. pub fn trap(message: &str) -> ! { + // SAFETY: `message`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.trap. unsafe { ic0::trap(message.as_ptr() as i32, message.len() as i32); } @@ -24,13 +26,16 @@ pub fn trap(message: &str) -> ! { /// Get current timestamp pub fn time() -> u64 { + // SAFETY: ic0.time is always safe to call. unsafe { ic0::time() as u64 } } /// Returns the caller of the current call. pub fn caller() -> Principal { + // SAFETY: ic0.msg_caller_size is always safe to call. let len: u32 = unsafe { ic0::msg_caller_size() as u32 }; let mut bytes = vec![0u8; len as usize]; + // SAFETY: Because `bytes` is mutable, and allocated to `len` bytes, it is safe to be passed to `ic0.msg_caller_copy` with a 0-offset. unsafe { ic0::msg_caller_copy(bytes.as_mut_ptr() as i32, 0, len as i32); } @@ -39,8 +44,10 @@ pub fn caller() -> Principal { /// Returns the canister id as a blob. pub fn id() -> Principal { + // SAFETY: ic0.canister_self_size is always safe to call. let len: u32 = unsafe { ic0::canister_self_size() as u32 }; let mut bytes = vec![0u8; len as usize]; + // SAFETY: Because `bytes` is mutable, and allocated to `len` bytes, it is safe to be passed to `ic0.canister_self_copy` with a 0-offset. unsafe { ic0::canister_self_copy(bytes.as_mut_ptr() as i32, 0, len as i32); } @@ -49,12 +56,14 @@ pub fn id() -> Principal { /// Get the amount of funds available in the canister. pub fn canister_balance() -> u64 { + // SAFETY: ic0.canister_cycle_balance is always safe to call. unsafe { ic0::canister_cycle_balance() as u64 } } /// Get the amount of funds available in the canister. pub fn canister_balance128() -> u128 { let mut recv = 0u128; + // SAFETY: recv is writable and the size expected by ic0.canister_cycle_balance128. unsafe { ic0::canister_cycle_balance128(&mut recv as *mut u128 as i32) } recv } @@ -78,6 +87,7 @@ pub fn canister_balance128() -> u128 { /// * This function traps if it's called from an illegal context /// (e.g., from a query call). pub fn set_certified_data(data: &[u8]) { + // SAFETY: because data is a slice ref, its pointer and length are valid to pass to ic0.certified_data_set. unsafe { ic0::certified_data_set(data.as_ptr() as i32, data.len() as i32) } } @@ -86,12 +96,15 @@ pub fn set_certified_data(data: &[u8]) { /// /// Returns None if called not from a query call. pub fn data_certificate() -> Option> { + // SAFETY: ic0.data_certificate_present is always safe to call. if unsafe { ic0::data_certificate_present() } == 0 { return None; } + // SAFETY: ic0.data_certificate_size is always safe to call. let n = unsafe { ic0::data_certificate_size() }; let mut buf = vec![0u8; n as usize]; + // SAFETY: Because `buf` is mutable and allocated to `n` bytes, it is valid to receive from ic0.data_certificate_bytes with no offset unsafe { ic0::data_certificate_copy(buf.as_mut_ptr() as i32, 0i32, n); } @@ -111,5 +124,6 @@ pub fn instruction_counter() -> u64 { /// 0 : instruction counter. The number of WebAssembly instructions the system has determined that the canister has executed. #[inline] pub fn performance_counter(counter_type: u32) -> u64 { + // SAFETY: ic0.performance_counter is always safe to call. unsafe { ic0::performance_counter(counter_type as i32) as u64 } } diff --git a/src/ic-cdk/src/api/stable/canister.rs b/src/ic-cdk/src/api/stable/canister.rs index 3189f5e61..020047eb9 100644 --- a/src/ic-cdk/src/api/stable/canister.rs +++ b/src/ic-cdk/src/api/stable/canister.rs @@ -8,14 +8,17 @@ pub struct CanisterStableMemory {} impl StableMemory for CanisterStableMemory { fn stable_size(&self) -> u32 { + // SAFETY: ic0.stable_size is always safe to call. unsafe { ic0::stable_size() as u32 } } fn stable64_size(&self) -> u64 { + // SAFETY: ic0.stable64_size is always safe to call. unsafe { ic0::stable64_size() as u64 } } fn stable_grow(&self, new_pages: u32) -> Result { + // SAFETY: ic0.stable_grow is always safe to call. unsafe { match ic0::stable_grow(new_pages as i32) { -1 => Err(StableMemoryError::OutOfMemory), @@ -25,6 +28,7 @@ impl StableMemory for CanisterStableMemory { } fn stable64_grow(&self, new_pages: u64) -> Result { + // SAFETY: ic0.stable64_grow is always safe to call. unsafe { match ic0::stable64_grow(new_pages as i64) { -1 => Err(StableMemoryError::OutOfMemory), @@ -34,24 +38,28 @@ impl StableMemory for CanisterStableMemory { } fn stable_write(&self, offset: u32, buf: &[u8]) { + // SAFETY: `buf`, being &[u8], is a readable sequence of bytes, and therefore valid to pass to ic0.stable_write. unsafe { ic0::stable_write(offset as i32, buf.as_ptr() as i32, buf.len() as i32); } } fn stable64_write(&self, offset: u64, buf: &[u8]) { + // SAFETY: `buf`, being &[u8], is a readable sequence of bytes, and therefore valid to pass to ic0.stable64_write. unsafe { ic0::stable64_write(offset as i64, buf.as_ptr() as i64, buf.len() as i64); } } fn stable_read(&self, offset: u32, buf: &mut [u8]) { + // SAFETY: `buf`, being &mut [u8], is a writable sequence of bytes, and therefore valid to pass to ic0.stable_read. unsafe { ic0::stable_read(buf.as_ptr() as i32, offset as i32, buf.len() as i32); } } fn stable64_read(&self, offset: u64, buf: &mut [u8]) { + // SAFETY: `buf`, being &mut [u8], is a writable sequence of bytes, and therefore valid to pass to ic0.stable64_read. unsafe { ic0::stable64_read(buf.as_ptr() as i64, offset as i64, buf.len() as i64); } diff --git a/src/ic-cdk/src/api/stable/mod.rs b/src/ic-cdk/src/api/stable/mod.rs index 5a988fe93..b544256ff 100644 --- a/src/ic-cdk/src/api/stable/mod.rs +++ b/src/ic-cdk/src/api/stable/mod.rs @@ -123,6 +123,9 @@ pub fn stable64_read(offset: u64, buf: &mut [u8]) { pub fn stable_bytes() -> Vec { let size = (stable_size() as usize) << 16; let mut vec = Vec::with_capacity(size); + // SAFETY: + // `vec`, being mutable and allocated to `size` bytes, is safe to pass to ic0.stable_read with no offset. + // ic0.stable_read writes to all of `vec[0..size]`, so `set_len` is safe to call with the new size. unsafe { ic0::stable_read(vec.as_ptr() as i32, 0, size as i32); vec.set_len(size); diff --git a/src/ic-cdk/src/futures.rs b/src/ic-cdk/src/futures.rs index 8da3896a1..a07eb5c8c 100644 --- a/src/ic-cdk/src/futures.rs +++ b/src/ic-cdk/src/futures.rs @@ -22,14 +22,19 @@ use std::task::Context; pub fn spawn>(future: F) { let future_ptr = Box::into_raw(Box::new(future)); let future_ptr_ptr: *mut *mut dyn Future = Box::into_raw(Box::new(future_ptr)); + // SAFETY: The pointer is to a Box, which satisfies the pinning requirement. let mut pinned_future = unsafe { Pin::new_unchecked(&mut *future_ptr) }; if pinned_future .as_mut() - .poll(&mut Context::from_waker(&waker::waker( - future_ptr_ptr as *const (), - ))) + // SAFETY: future_ptr_ptr was constructed from a boxed box. + // future_ptr_ptr is NOT unique (shared by pinned_future). This call is UNSOUND. + // FIXME + .poll(&mut Context::from_waker(&unsafe { + waker::waker(future_ptr_ptr as *const ()) + })) .is_ready() { + // SAFETY: These were created from boxes earlier in the function unsafe { let _ = Box::from_raw(future_ptr); let _ = Box::from_raw(future_ptr_ptr); @@ -55,12 +60,19 @@ mod waker { static MY_VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); - fn raw_waker(ptr: *const ()) -> RawWaker { + /// # Safety + /// + /// The pointer must be a unique Box-allocated pointer to a Box-allocated pointer to a `dyn Future`. + unsafe fn raw_waker(ptr: *const ()) -> RawWaker { + // SAFETY: All the function pointers in MY_VTABLE correctly operate on the pointer in question. RawWaker::new(ptr, &MY_VTABLE) } - fn clone(ptr: *const ()) -> RawWaker { - raw_waker(ptr) + /// # Safety + /// This function should only be called by a [Waker] created by [`waker`]. + unsafe fn clone(ptr: *const ()) -> RawWaker { + // SAFETY: The pointer attached via `waker` satisfies its own contract. + unsafe { raw_waker(ptr) } } // Our waker will be called only if one of the response callbacks is triggered. @@ -69,15 +81,22 @@ mod waker { // is pending, we leave it on the heap. If it's ready, we deallocate the // pointer. If CLEANUP is set, then we're recovering from a callback trap, and // want to drop the future without executing any more of it. + /// # Safety + /// This function should only be called by a [Waker] created by [`waker`]. unsafe fn wake(ptr: *const ()) { - let boxed_future_ptr_ptr = Box::from_raw(ptr as *mut FuturePtr); + // SAFETY: The function contract guarantees that the outer pointer is a Box of the FuturePtr. + let boxed_future_ptr_ptr = unsafe { Box::from_raw(ptr as *mut FuturePtr) }; let future_ptr: FuturePtr = *boxed_future_ptr_ptr; - let boxed_future = Box::from_raw(future_ptr); - let mut pinned_future = Pin::new_unchecked(&mut *future_ptr); + // SAFETY: The function contract guarantees that the inner pointer is a FuturePtr, and unique. + let mut boxed_future = unsafe { Box::from_raw(future_ptr) }; + // SAFETY: Boxes satisfy the pinning contract and are sound to use in new_unchecked. + // The box is never moved out of, but dropped in place. + let mut pinned_future = unsafe { Pin::new_unchecked(&mut *boxed_future) }; if !super::CLEANUP.load(Ordering::Relaxed) && pinned_future .as_mut() - .poll(&mut Context::from_waker(&waker::waker(ptr))) + // SAFETY: The pointer attached via `waker` satisfies its own contract. + .poll(&mut Context::from_waker(&unsafe { waker::waker(ptr) })) .is_pending() { Box::into_raw(boxed_future_ptr_ptr); @@ -89,7 +108,14 @@ mod waker { fn drop(_: *const ()) {} - pub fn waker(ptr: *const ()) -> Waker { + /// # Safety + /// + /// The pointer must be a unique Box-allocated pointer to a Box-allocated pointer to a `dyn Future`. + pub unsafe fn waker(ptr: *const ()) -> Waker { + // SAFETY: + // raw_waker has the same safety requirement on ptr as this function + // The functions in the vtable are passed the ptr that was passed to this function + // The functions in the vtable uphold RawWaker's contract unsafe { Waker::from_raw(raw_waker(ptr)) } } } diff --git a/src/ic-cdk/src/lib.rs b/src/ic-cdk/src/lib.rs index 43e4e78ef..cd05678da 100644 --- a/src/ic-cdk/src/lib.rs +++ b/src/ic-cdk/src/lib.rs @@ -1,6 +1,11 @@ -#![warn(missing_docs)] +#![warn( + missing_docs, + unsafe_op_in_unsafe_fn, + clippy::undocumented_unsafe_blocks, + clippy::missing_safety_doc +)] -//! This crate provides building blocks for developing Internet Computer Canister. +//! This crate provides building blocks for developing Internet Computer canisters. //! //! You can check the [Internet Computer Specification]( //! https://smartcontracts.org/docs/interface-spec/index.html#system-api-imports) @@ -17,11 +22,13 @@ mod futures; mod printer; pub mod storage; +use std::sync::atomic::{AtomicBool, Ordering}; + pub use api::call::call; pub use api::call::notify; pub use api::{caller, id, print, trap}; -static mut DONE: bool = false; +static DONE: AtomicBool = AtomicBool::new(false); /// Re-exports crates those are necessary for using ic-cdk pub mod export { @@ -32,13 +39,9 @@ pub mod export { /// Setup the stdlib hooks. pub fn setup() { - unsafe { - if DONE { - return; - } - DONE = true; + if !DONE.swap(true, Ordering::SeqCst) { + printer::hook() } - printer::hook() } /// See documentation for [spawn]. From 3eea10b13175bc8de51b0a28cc01556a6ac5a26c Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Mon, 28 Nov 2022 08:08:00 -0800 Subject: [PATCH 114/234] feat: Implement canister timers API (#342) * Implement canister timers API * Check for internal prefix * lint * Add e2e tests --- .github/workflows/ci.yml | 6 + e2e-tests/Cargo.toml | 10 +- e2e-tests/canisters/timers.rs | 63 +++++++++ e2e-tests/tests/e2e.rs | 44 +++++- src/ic-cdk-macros/src/export.rs | 15 +- src/ic-cdk/CHANGELOG.md | 4 + src/ic-cdk/Cargo.toml | 10 ++ src/ic-cdk/src/lib.rs | 12 +- src/ic-cdk/src/timer.rs | 235 ++++++++++++++++++++++++++++++++ src/ic0/ic0.txt | 2 + src/ic0/src/ic0.rs | 4 + 11 files changed, 390 insertions(+), 15 deletions(-) create mode 100644 e2e-tests/canisters/timers.rs create mode 100644 src/ic-cdk/src/timer.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b02a2f4a..01fb123ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,6 +67,9 @@ jobs: uses: dtolnay/rust-toolchain@v1 with: toolchain: ${{ env.rust-version }} + - name: Install protoc + run: | + sudo apt-get install -y protobuf-compiler - name: Run tests run: | cargo test --all-targets @@ -123,6 +126,9 @@ jobs: with: toolchain: ${{ env.rust-version }} components: clippy + - name: Install protoc + run: | + sudo apt-get install -y protobuf-compiler - name: Run clippy run: | cargo clippy --tests --benches -- -D clippy::all diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index a826deb1e..2d1c6e205 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/dfinity/cdk-rs" [dependencies] cargo_metadata = "0.14.2" escargot = { version = "0.5.7", features = ["print"] } -ic-cdk = { path = "../src/ic-cdk" } +ic-cdk = { path = "../src/ic-cdk", features = ["timers"] } ic-cdk-macros = { path = "../src/ic-cdk-macros" } lazy_static = "1.4.0" serde_bytes = "0.11" @@ -31,6 +31,10 @@ path = "canisters/reverse.rs" name = "api-call" path = "canisters/api_call.rs" +[[bin]] +name = "timers" +path = "canisters/timers.rs" + [dev-dependencies] -ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "02a4a828f2f4d3b1dcb93a84e60672a3f3fdb400" } -candid_legecy = { package = "candid", version = "0.7.18" } +ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "dcbf401f27d9b48354e68389c6d8293c4233b055" } +candid = { package = "candid", version = "0.8" } diff --git a/e2e-tests/canisters/timers.rs b/e2e-tests/canisters/timers.rs new file mode 100644 index 000000000..b24ab2972 --- /dev/null +++ b/e2e-tests/canisters/timers.rs @@ -0,0 +1,63 @@ +use ic_cdk::{ + query, + timer::{clear_timer, set_timer, set_timer_interval, TimerId}, + update, +}; +use std::{ + cell::{Cell, RefCell}, + time::Duration, +}; + +thread_local! { + static EVENTS: RefCell> = RefCell::default(); + static LONG: Cell = Cell::default(); + static REPEATING: Cell = Cell::default(); +} + +#[query] +fn get_events() -> Vec<&'static str> { + EVENTS.with(|events| events.borrow().clone()) +} + +#[update] +fn clear_events() { + EVENTS.with(|events| events.borrow_mut().clear()); +} + +#[update] +fn schedule() { + set_timer(Duration::from_secs(2), || add_event("2")); + set_timer(Duration::from_secs(1), || { + add_event("1"); + set_timer(Duration::from_secs(2), || add_event("3")); + }); + set_timer(Duration::from_secs(4), || add_event("4")); +} + +#[update] +fn schedule_long() { + let id = set_timer(Duration::from_secs(9), || add_event("long")); + LONG.with(|long| long.set(id)); +} + +#[update] +fn cancel_long() { + LONG.with(|long| clear_timer(long.get())); +} + +#[update] +fn start_repeating() { + let id = set_timer_interval(Duration::from_secs(1), || add_event("repeat")); + REPEATING.with(|repeating| repeating.set(id)); +} + +#[update] +fn stop_repeating() { + REPEATING.with(|repeating| clear_timer(repeating.get())); +} + +fn add_event(event: &'static str) { + EVENTS.with(|events| events.borrow_mut().push(event)); +} + +fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index a05764609..0b9d47ab0 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -1,7 +1,9 @@ +use std::time::{Duration, SystemTime}; + // use ic_cdk::export::candid::utils::{decode_args, encode_args, ArgumentDecoder, ArgumentEncoder}; // use ic_cdk::export::candid::Encode; -use candid_legecy::utils::{decode_args, encode_args, ArgumentDecoder, ArgumentEncoder}; -use candid_legecy::Encode; +use candid::utils::{decode_args, encode_args, ArgumentDecoder, ArgumentEncoder}; +use candid::Encode; use ic_cdk_e2e_tests::cargo_build_canister; use ic_state_machine_tests::{CanisterId, ErrorCode, StateMachine, UserError, WasmResult}; use serde_bytes::ByteBuf; @@ -180,3 +182,41 @@ fn test_api_call() { .unwrap(); assert_eq!(result, WasmResult::Reject("manual reject".to_string())); } + +#[test] +fn test_timers() { + let env = StateMachine::new(); + let time = SystemTime::now(); + env.set_time(time); + let wasm = cargo_build_canister("timers"); + let canister_id = env.install_canister(wasm, vec![], None).unwrap(); + call_candid::<(), ()>(&env, canister_id, "schedule", ()).expect("Failed to call schedule"); + advance_seconds(&env, 5); + + call_candid::<_, ()>(&env, canister_id, "schedule_long", ()) + .expect("Failed to call schedule_long"); + advance_seconds(&env, 5); + call_candid::<_, ()>(&env, canister_id, "cancel_long", ()).expect("Failed to call cancel_long"); + advance_seconds(&env, 5); + + call_candid::<_, ()>(&env, canister_id, "start_repeating", ()) + .expect("Failed to call start_repeating"); + advance_seconds(&env, 3); + call_candid::<_, ()>(&env, canister_id, "stop_repeating", ()) + .expect("Failed to call stop_repeating"); + advance_seconds(&env, 2); + + let (events,): (Vec,) = + query_candid(&env, canister_id, "get_events", ()).expect("Failed to call get_events"); + assert_eq!( + events[..], + ["1", "2", "3", "4", "repeat", "repeat", "repeat"] + ); +} + +fn advance_seconds(env: &StateMachine, seconds: u32) { + for _ in 0..seconds { + env.advance_time(Duration::from_secs(1)); + env.tick(); + } +} diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index 95d7dd6ef..1d01e707b 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -134,13 +134,16 @@ fn dfn_macro( let outer_function_ident = Ident::new(&format!("{}_{}_", name, crate::id()), Span::call_site()); let export_name = if method.is_lifecycle() { - format!("canister_{}", method) + format!("canister_{method}") } else { - format!( - "canister_{0} {1}", - method, - attrs.name.unwrap_or_else(|| name.to_string()) - ) + let function_name = attrs.name.unwrap_or_else(|| name.to_string()); + if function_name.starts_with("") { + return Err(Error::new( + Span::call_site(), + "Functions starting with `` are reserved for CDK internal use.", + )); + } + format!("canister_{method} {function_name}") }; let function_call = if is_async { diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index e468167cf..3f2497870 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Added + +- Implemented the canister timers API, located in module `ic_cdk::timer`. + ## [0.6.7] - 2022-11-16 ### Changed diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index b0ebb569d..059e00bfb 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -21,6 +21,16 @@ serde = "1.0.110" serde_bytes = "0.11.7" ic0 = { path = "../ic0", version = "0.18.4" } ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.6.7" } +slotmap = { version = "1.0.6", optional = true } +futures = { version = "0.3.25", optional = true } + +[features] +timers = ["dep:slotmap", "dep:futures"] [dev-dependencies] rstest = "0.12.0" + +[package.metadata.docs.rs] +all-features = true +default-target = "wasm32-unknown-unknown" +rustc-args = ["--cfg=docsrs"] diff --git a/src/ic-cdk/src/lib.rs b/src/ic-cdk/src/lib.rs index cd05678da..1af6554cf 100644 --- a/src/ic-cdk/src/lib.rs +++ b/src/ic-cdk/src/lib.rs @@ -4,6 +4,7 @@ clippy::undocumented_unsafe_blocks, clippy::missing_safety_doc )] +#![cfg_attr(docsrs, feature(doc_cfg))] //! This crate provides building blocks for developing Internet Computer canisters. //! @@ -21,6 +22,9 @@ pub mod api; mod futures; mod printer; pub mod storage; +#[cfg(feature = "timers")] +#[cfg_attr(docsrs, doc(cfg(feature = "timers")))] +pub mod timer; use std::sync::atomic::{AtomicBool, Ordering}; @@ -63,8 +67,8 @@ pub fn spawn>(future: F) { #[cfg(target_arch = "wasm32")] #[macro_export] macro_rules! println { - ($fmt:expr) => (ic_cdk::print(format!($fmt))); - ($fmt:expr, $($arg:tt)*) => (ic_cdk::print(format!($fmt, $($arg)*))); + ($fmt:expr) => ($crate::print(format!($fmt))); + ($fmt:expr, $($arg:tt)*) => ($crate::print(format!($fmt, $($arg)*))); } /// Format and then print the formatted message @@ -79,8 +83,8 @@ macro_rules! println { #[cfg(target_arch = "wasm32")] #[macro_export] macro_rules! eprintln { - ($fmt:expr) => (ic_cdk::print(format!($fmt))); - ($fmt:expr, $($arg:tt)*) => (ic_cdk::print(format!($fmt, $($arg)*))); + ($fmt:expr) => ($crate::print(format!($fmt))); + ($fmt:expr, $($arg:tt)*) => ($crate::print(format!($fmt, $($arg)*))); } /// Format and then print the formatted message diff --git a/src/ic-cdk/src/timer.rs b/src/ic-cdk/src/timer.rs new file mode 100644 index 000000000..2e6cd73fe --- /dev/null +++ b/src/ic-cdk/src/timer.rs @@ -0,0 +1,235 @@ +//! Provides simple timer functionality for executing a function in the future. + +use std::{cell::RefCell, cmp::Ordering, collections::BinaryHeap, mem, time::Duration}; + +use futures::{stream::FuturesUnordered, StreamExt}; +use slotmap::{new_key_type, KeyData, SlotMap}; + +// To ensure that tasks are removable seamlessly, there are two separate concepts here: tasks, for the actual function being called, +// and timers, the scheduled execution of tasks. As this is an implementation detail, this does not affect the exported name TimerId, +// which is more accurately a task ID. (The obvious solution to this, `pub use`, invokes a very silly compiler error.) + +thread_local! { + static TASKS: RefCell> = RefCell::default(); + static TIMERS: RefCell> = RefCell::default(); +} + +enum Task { + Repeated { + func: Box, + interval: Duration, + }, + Once(Box), +} + +impl Default for Task { + fn default() -> Self { + Self::Once(Box::new(|| ())) + } +} + +new_key_type! { + /// Type returned by the [`set_timer`] and [`set_timer_interval`] functions. Pass to [`clear_timer`] to remove the timer. + pub struct TimerId; +} + +struct Timer { + task: TimerId, + time: u64, +} + +// Timers are sorted such that x > y if x should be executed _before_ y. + +impl Ord for Timer { + fn cmp(&self, other: &Self) -> Ordering { + self.time.cmp(&other.time).reverse() + } +} + +impl PartialOrd for Timer { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for Timer { + fn eq(&self, other: &Self) -> bool { + self.time == other.time + } +} + +impl Eq for Timer {} + +// This function is called by the IC at or after the timestamp provided to `ic0.global_timer_set`. +#[export_name = "canister_global_timer"] +extern "C" fn global_timer() { + crate::setup(); + crate::spawn(async { + // All the calls are made first, according only to the timestamp we *started* with, and then all the results are awaited. + // This allows us to use the minimum number of execution rounds, as well as avoid any race conditions. + // The only thing that can happen interleavedly is canceling a task, which is seamless by design. + let mut call_futures = FuturesUnordered::new(); + let now = crate::api::time(); + TIMERS.with(|timers| { + // pop every timer that should have been completed by `now`, and get ready to run its task if it exists + loop { + let mut timers = timers.borrow_mut(); + if let Some(timer) = timers.peek() { + if timer.time <= now { + let timer = timers.pop().unwrap(); + if TASKS.with(|tasks| tasks.borrow().contains_key(timer.task)) { + // This is the biggest hack in this code. If a callback was called explicitly, and trapped, the rescheduling step wouldn't happen. + // The closest thing to a catch_unwind that's available here is performing an inter-canister call to ourselves; + // traps will be caught at the call boundary. This invokes a meaningful cycles cost, and should an alternative for catching traps + // become available, this code should be rewritten. + call_futures.push(async move { + ( + timer.task, + crate::call( + crate::api::id(), + " timer_executor", + (timer.task.0.as_ffi(),), + ) + .await, + ) + }); + } + continue; + } + } + break; + } + }); + // run all the collected tasks, and clean up after them if necessary + while let Some((task_id, res)) = call_futures.next().await { + match res { + Ok(()) => {} + Err((code, msg)) => { + crate::println!("in canister_global_timer: {code:?}: {msg}"); + } + } + TASKS.with(|tasks| { + let mut tasks = tasks.borrow_mut(); + if let Some(task) = tasks.get(task_id) { + match task { + // duplicated on purpose - it must be removed in the function call, to access self by value; + // and it must be removed here, because it may have trapped and not actually been removed. + // Luckily slotmap ops are equivalent to simple vector indexing. + Task::Once(_) => { + tasks.remove(task_id); + } + // reschedule any repeating tasks + Task::Repeated { interval, .. } => { + match now.checked_add(interval.as_nanos() as u64) { + Some(time) => TIMERS.with(|timers| { + timers.borrow_mut().push(Timer { + task: task_id, + time, + }) + }), + None => crate::println!( + "Failed to reschedule task (needed {interval}, currently {now}, and this would exceed u64::MAX)", + interval = interval.as_nanos(), + ), + } + } + } + } + }); + } + update_ic0_timer(); + }); +} + +/// Sets `func` to be executed later, after `delay`. Panics if `delay` + [`time()`][crate::api::time] is more than [`u64::MAX`] nanoseconds. +/// +/// To cancel the timer before it executes, pass the returned `TimerId` to [`clear_timer`]. +/// +/// Note that timers are not persisted across canister upgrades. +pub fn set_timer(delay: Duration, func: impl FnOnce() + 'static) -> TimerId { + let delay_ns = u64::try_from(delay.as_nanos()).expect( + "delay out of bounds (must be within `u64::MAX - ic_cdk::api::time()` nanoseconds)", + ); + let scheduled_time = crate::api::time().checked_add(delay_ns).expect( + "delay out of bounds (must be within `u64::MAX - ic_cdk::api::time()` nanoseconds)", + ); + let key = TASKS.with(|tasks| tasks.borrow_mut().insert(Task::Once(Box::new(func)))); + TIMERS.with(|timers| { + timers.borrow_mut().push(Timer { + task: key, + time: scheduled_time, + }); + }); + update_ic0_timer(); + key +} + +/// Sets `func` to be executed every `interval`. Panics if `interval` + [`time()`][crate::api::time] is more than [`u64::MAX`] nanoseconds. +/// +/// To cancel the interval timer, pass the returned `TimerId` to [`clear_timer`]. +/// +/// Note that timers are not persisted across canister upgrades. +pub fn set_timer_interval(interval: Duration, func: impl FnMut() + 'static) -> TimerId { + let interval_ns = u64::try_from(interval.as_nanos()).expect( + "delay out of bounds (must be within `u64::MAX - ic_cdk::api::time()` nanoseconds)", + ); + let scheduled_time = crate::api::time().checked_add(interval_ns).expect( + "delay out of bounds (must be within `u64::MAX - ic_cdk::api::time()` nanoseconds)", + ); + let key = TASKS.with(|tasks| { + tasks.borrow_mut().insert(Task::Repeated { + func: Box::new(func), + interval, + }) + }); + TIMERS.with(|timers| { + timers.borrow_mut().push(Timer { + task: key, + time: scheduled_time, + }) + }); + update_ic0_timer(); + key +} + +/// Cancels an existing timer. Does nothing if the timer has already been canceled. +pub fn clear_timer(id: TimerId) { + TASKS.with(|tasks| tasks.borrow_mut().remove(id)); +} + +/// Calls `ic0.global_timer_set` with the soonest timer in [`TIMERS`]. This is needed after inserting a timer, and after executing one. +fn update_ic0_timer() { + TIMERS.with(|timers| { + let timers = timers.borrow(); + let soonest_timer = timers.peek().map_or(0, |timer| timer.time); + unsafe { ic0::global_timer_set(soonest_timer as i64) }; + }); +} + +#[export_name = "canister_update timer_executor"] +extern "C" fn timer_executor() { + if crate::api::caller() != crate::api::id() { + crate::trap("This function is internal to ic-cdk and should not be called externally."); + } + let (task_id,) = crate::api::call::arg_data(); + let task_id = TimerId(KeyData::from_ffi(task_id)); + // We can't be holding `TASKS` when we call the function, because it may want to schedule more tasks. + // Instead, we swap the task out in order to call it, and then either swap it back in, or remove it. + let task = TASKS.with(|tasks| { + let mut tasks = tasks.borrow_mut(); + tasks.get_mut(task_id).map(mem::take) + }); + if let Some(mut task) = task { + match task { + Task::Once(func) => { + func(); + TASKS.with(|tasks| tasks.borrow_mut().remove(task_id)); + } + Task::Repeated { ref mut func, .. } => { + func(); + TASKS.with(|tasks| *tasks.borrow_mut().get_mut(task_id).unwrap() = task); + } + } + } + crate::api::call::reply(()); +} diff --git a/src/ic0/ic0.txt b/src/ic0/ic0.txt index 53e9d2716..994b0d602 100644 --- a/src/ic0/ic0.txt +++ b/src/ic0/ic0.txt @@ -44,6 +44,8 @@ ic0.call_cycles_add : (amount : i64) -> (); // U ic0.call_cycles_add128 : (amount_high : i64, amount_low: i64) -> (); // U Ry Rt H ic0.call_perform : () -> ( err_code : i32 ); // U Ry Rt H +ic0.global_timer_set : (timestamp : i64) -> i64; // I U Ry Rt C H + ic0.stable_size : () -> (page_count : i32); // * ic0.stable_grow : (new_pages : i32) -> (old_page_count : i32); // * ic0.stable_write : (offset : i32, src : i32, size : i32) -> (); // * diff --git a/src/ic0/src/ic0.rs b/src/ic0/src/ic0.rs index c5cab172e..3383f5a3f 100644 --- a/src/ic0/src/ic0.rs +++ b/src/ic0/src/ic0.rs @@ -42,6 +42,7 @@ extern "C" { pub fn call_cycles_add(amount: i64); pub fn call_cycles_add128(amount_high: i64, amount_low: i64); pub fn call_perform() -> i32; + pub fn global_timer_set(timestamp: i64) -> i64; pub fn stable_size() -> i32; pub fn stable_grow(new_pages: i32) -> i32; pub fn stable_write(offset: i32, src: i32, size: i32); @@ -164,6 +165,9 @@ mod non_wasm { pub unsafe fn call_perform() -> i32 { panic!("call_perform should only be called inside canisters."); } + pub unsafe fn global_timer_set(timestamp: i64) -> i64 { + panic!("global_timer_set should only be called inside canisters."); + } pub unsafe fn stable_size() -> i32 { panic!("stable_size should only be called inside canisters."); } From 2b13607f0344c5fd473303051d0c6e570f9c8554 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Mon, 28 Nov 2022 08:37:19 -0800 Subject: [PATCH 115/234] feat: Implement composite queries (#344) * Add composite functions * Add test case * Add composite query e2e test * fix prost:0.11 new dependency on protoc * --no-deps is not enough * lint * update after merge * Update changelog * bump versions Co-authored-by: Linwei Shang --- e2e-tests/Cargo.toml | 2 +- e2e-tests/canisters/async.rs | 8 ++++++++ e2e-tests/tests/e2e.rs | 15 +++++++++++++++ src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-macros/src/export.rs | 9 ++++++++- src/ic-cdk-macros/src/lib.rs | 11 +++++++++++ src/ic-cdk-macros/tests/pass/blank_methods.rs | 3 +++ src/ic-cdk/CHANGELOG.md | 8 +++++++- src/ic-cdk/Cargo.toml | 2 +- src/ic0/Cargo.toml | 2 +- 10 files changed, 56 insertions(+), 6 deletions(-) diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 2d1c6e205..c2f99f95d 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -37,4 +37,4 @@ path = "canisters/timers.rs" [dev-dependencies] ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "dcbf401f27d9b48354e68389c6d8293c4233b055" } -candid = { package = "candid", version = "0.8" } +candid = "0.8" diff --git a/e2e-tests/canisters/async.rs b/e2e-tests/canisters/async.rs index b3786382f..92b764467 100644 --- a/e2e-tests/canisters/async.rs +++ b/e2e-tests/canisters/async.rs @@ -57,6 +57,14 @@ fn greet(name: String) -> String { format!("Hello, {}", name) } +#[query(composite = true)] +async fn greet_self(greeter: Principal) -> String { + let (greeting,) = ic_cdk::api::call::call(greeter, "greet", ("myself",)) + .await + .unwrap(); + greeting +} + #[update] async fn invalid_reply_payload_does_not_trap() -> String { // We're decoding an integer instead of a string, decoding must fail. diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 0b9d47ab0..f16ef5463 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -167,6 +167,21 @@ fn test_notify_calls() { assert_eq!(n, 1); } +#[test] +fn test_composite_query() { + let env = StateMachine::new(); + let wasm = cargo_build_canister("async"); + let sender_id = env + .install_canister(wasm.clone(), vec![], None) + .expect("failed to install sender"); + let receiver_id = env + .install_canister(wasm, vec![], None) + .expect("failed to install sender"); + let (greeting,): (String,) = query_candid(&env, sender_id, "greet_self", (receiver_id,)) + .expect("failed to query 'greet_self'"); + assert_eq!(greeting, "Hello, myself"); +} + #[test] fn test_api_call() { let env = StateMachine::new(); diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 1f6f30d5e..0298b4e73 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.6.7" +version = "0.6.8" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index 1d01e707b..3e9e80f44 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -12,6 +12,8 @@ struct ExportAttributes { pub guard: Option, #[serde(default)] pub manual_reply: bool, + #[serde(default)] + pub composite: bool, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -134,7 +136,12 @@ fn dfn_macro( let outer_function_ident = Ident::new(&format!("{}_{}_", name, crate::id()), Span::call_site()); let export_name = if method.is_lifecycle() { - format!("canister_{method}") + format!("canister_{}", method) + } else if method == MethodType::Query && attrs.composite { + format!( + "canister_composite_query {}", + attrs.name.unwrap_or_else(|| name.to_string()) + ) } else { let function_name = attrs.name.unwrap_or_else(|| name.to_string()); if function_name.starts_with("") { diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index 0cb0cf0f2..bccf7f9f3 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -106,6 +106,17 @@ where /// } /// ``` /// +/// To be able to make inter-canister calls from a query call, it must be a *composite* query (which cannot be executed in replicated mode). +/// +/// ```rust +/// # use ic_cdk::query; +/// # fn wallet_canister_principal() -> ic_cdk::export::Principal { unimplemented!() } +/// #[query(composite = true)] +/// async fn composite_query_function() { +/// let (wallet_name,): (Option,) = ic_cdk::call(wallet_canister_principal(), "name", ()).await.unwrap(); +/// } +/// ``` +/// /// If you would rather call the [`call::reply`] function than return a value, /// you will need to set `manual_reply` to `true` so that the canister does not /// trap. diff --git a/src/ic-cdk-macros/tests/pass/blank_methods.rs b/src/ic-cdk-macros/tests/pass/blank_methods.rs index c27136ca1..9b9e502fd 100644 --- a/src/ic-cdk-macros/tests/pass/blank_methods.rs +++ b/src/ic-cdk-macros/tests/pass/blank_methods.rs @@ -15,6 +15,9 @@ fn update() {} #[query] fn query() {} +#[query(composite = true)] +fn composite_query() {} + #[heartbeat] fn heartbeat() {} diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 3f2497870..3686b7470 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,9 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.6.8] - 2022-11-28 + ### Added -- Implemented the canister timers API, located in module `ic_cdk::timer`. +- Added composite queries via `#[query(composite = true)]`. (#344) + + Composite queries cannot be run as update calls, but can make inter-canister calls to other query functions. + +- Implemented the canister timers API, located in module `ic_cdk::timer`. (#342) ## [0.6.7] - 2022-11-16 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 059e00bfb..a17abd54d 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.6.7" +version = "0.6.8" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml index dbe873f4c..248e0e156 100644 --- a/src/ic0/Cargo.toml +++ b/src/ic0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic0" -version = "0.18.6" +version = "0.18.7" authors = ["DFINITY Stiftung "] edition = "2021" description = "Internet Computer System API Binding." From fafb181453242debee33946d00c7fbf44bc6c539 Mon Sep 17 00:00:00 2001 From: Chase Manning Date: Mon, 28 Nov 2022 22:58:38 +0000 Subject: [PATCH 116/234] refactor: change from pleco to tanton (#345) * change from pleco to tanton * add tanton change to changelog * add webassembly support for getrandom * remove redundant imp dependency * clean * fix * custom getrandom Co-authored-by: Linwei Shang --- .../asset_storage/src/asset_storage_rs/Cargo.toml | 1 - examples/chess/src/chess_rs/Cargo.toml | 4 ++-- examples/chess/src/chess_rs/getrandom_fail.rs | 11 +++++++++++ examples/chess/src/chess_rs/lib.rs | 10 ++++++---- examples/counter/src/counter_rs/Cargo.toml | 1 - examples/counter/src/inter2_rs/Cargo.toml | 1 - examples/counter/src/inter_rs/Cargo.toml | 1 - examples/print/src/print_rs/Cargo.toml | 1 - examples/profile/src/profile_inter_rs/Cargo.toml | 1 - examples/profile/src/profile_rs/Cargo.toml | 1 - src/ic-cdk/CHANGELOG.md | 4 ++++ 11 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 examples/chess/src/chess_rs/getrandom_fail.rs diff --git a/examples/asset_storage/src/asset_storage_rs/Cargo.toml b/examples/asset_storage/src/asset_storage_rs/Cargo.toml index b6baf50de..d365ba543 100644 --- a/examples/asset_storage/src/asset_storage_rs/Cargo.toml +++ b/examples/asset_storage/src/asset_storage_rs/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "asset_storage_rs" version = "0.1.0" -authors = ["Hans Larsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/chess/src/chess_rs/Cargo.toml b/examples/chess/src/chess_rs/Cargo.toml index f1d0a01f1..c82931418 100644 --- a/examples/chess/src/chess_rs/Cargo.toml +++ b/examples/chess/src/chess_rs/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "chess_rs" version = "0.1.0" -authors = ["Hans Larsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -15,4 +14,5 @@ candid = "0.8.0" ic-cdk = { path = "../../../../src/ic-cdk" } ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } serde = "1.0.111" -pleco = "0.5.0" +tanton = "1.0.0" +getrandom = { version = "0.2", features = ["custom"] } # tanton requires this to compile on wasm target diff --git a/examples/chess/src/chess_rs/getrandom_fail.rs b/examples/chess/src/chess_rs/getrandom_fail.rs new file mode 100644 index 000000000..5d6225e41 --- /dev/null +++ b/examples/chess/src/chess_rs/getrandom_fail.rs @@ -0,0 +1,11 @@ +use core::num::NonZeroU32; +use getrandom::{register_custom_getrandom, Error}; + +// Some application-specific error code +const MY_CUSTOM_ERROR_CODE: u32 = Error::CUSTOM_START + 42; +pub fn always_fail(_buf: &mut [u8]) -> Result<(), Error> { + let code = NonZeroU32::new(MY_CUSTOM_ERROR_CODE).unwrap(); + Err(Error::from(code)) +} + +register_custom_getrandom!(always_fail); diff --git a/examples/chess/src/chess_rs/lib.rs b/examples/chess/src/chess_rs/lib.rs index e5db890c9..3b481ecb8 100644 --- a/examples/chess/src/chess_rs/lib.rs +++ b/examples/chess/src/chess_rs/lib.rs @@ -1,8 +1,10 @@ use ic_cdk::{export::candid::CandidType, query, update}; -use pleco::tools::Searcher; use serde::Serialize; use std::cell::RefCell; use std::collections::BTreeMap; +use tanton::tools::Searcher; + +mod getrandom_fail; type GameStore = BTreeMap; @@ -12,7 +14,7 @@ pub struct Game { } pub struct GameInternal { - pub board: pleco::Board, + pub board: tanton::Board, } thread_local! { @@ -25,7 +27,7 @@ fn new(name: String, white: bool) { game_store.borrow_mut().insert( name.clone(), GameInternal { - board: pleco::Board::start_pos(), + board: tanton::Board::start_pos(), }, ); }); @@ -62,7 +64,7 @@ fn ai_move(name: String) { .unwrap_or_else(|| panic!("Game {} does not exist.", name)); let b = game.board.shallow_clone(); - let m = pleco::bots::MiniMaxSearcher::best_move(b, 3); + let m = tanton::bots::MiniMaxSearcher::best_move(b, 3); game.board.apply_move(m); }); diff --git a/examples/counter/src/counter_rs/Cargo.toml b/examples/counter/src/counter_rs/Cargo.toml index 905b5a8e4..3ab795b28 100644 --- a/examples/counter/src/counter_rs/Cargo.toml +++ b/examples/counter/src/counter_rs/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "counter_rs" version = "0.1.0" -authors = ["Hans Larsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/counter/src/inter2_rs/Cargo.toml b/examples/counter/src/inter2_rs/Cargo.toml index 6aec3b5ae..3e2217f8a 100644 --- a/examples/counter/src/inter2_rs/Cargo.toml +++ b/examples/counter/src/inter2_rs/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "inter2_rs" version = "0.1.0" -authors = ["Hans Larsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/counter/src/inter_rs/Cargo.toml b/examples/counter/src/inter_rs/Cargo.toml index 8bed7e26b..a7b1ebc9e 100644 --- a/examples/counter/src/inter_rs/Cargo.toml +++ b/examples/counter/src/inter_rs/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "inter_rs" version = "0.1.0" -authors = ["Hans Larsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/print/src/print_rs/Cargo.toml b/examples/print/src/print_rs/Cargo.toml index a7b8a65ad..bd6d482f2 100644 --- a/examples/print/src/print_rs/Cargo.toml +++ b/examples/print/src/print_rs/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "print_rs" version = "0.1.0" -authors = ["Hans Larsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/profile/src/profile_inter_rs/Cargo.toml b/examples/profile/src/profile_inter_rs/Cargo.toml index 14bfa6245..6780a4bcb 100644 --- a/examples/profile/src/profile_inter_rs/Cargo.toml +++ b/examples/profile/src/profile_inter_rs/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "profile_inter_rs" version = "0.1.0" -authors = ["Hans Larsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/profile/src/profile_rs/Cargo.toml b/examples/profile/src/profile_rs/Cargo.toml index ec92c8c76..b88a89d89 100644 --- a/examples/profile/src/profile_rs/Cargo.toml +++ b/examples/profile/src/profile_rs/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "profile_rs" version = "0.1.0" -authors = ["Hans Larsen "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 3686b7470..82931e7dc 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Refactored + +- Change from pleco to tanton for the chess library in the chess example. (#345) + ## [0.6.8] - 2022-11-28 ### Added From 5df52cc536d14327f0e06da544ec8692e52f7e73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Dec 2022 08:32:58 +0100 Subject: [PATCH 117/234] chore(deps): bump decode-uri-component in /examples/chess (#347) Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2. - [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases) - [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2) --- updated-dependencies: - dependency-name: decode-uri-component dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/chess/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/chess/package-lock.json b/examples/chess/package-lock.json index b7981e1e6..c60f87be6 100644 --- a/examples/chess/package-lock.json +++ b/examples/chess/package-lock.json @@ -1941,9 +1941,9 @@ } }, "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true, "engines": { "node": ">=0.10" @@ -9917,9 +9917,9 @@ "dev": true }, "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true }, "deep-diff": { From bf054697a4fb8817a4d9c264343b6e91be7331ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Dec 2022 14:21:14 +0100 Subject: [PATCH 118/234] chore(deps): bump qs and express in /examples/chess (#349) Bumps [qs](https://github.com/ljharb/qs) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together. Updates `qs` from 6.7.0 to 6.11.0 - [Release notes](https://github.com/ljharb/qs/releases) - [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/qs/compare/v6.7.0...v6.11.0) Updates `express` from 4.17.1 to 4.18.2 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/4.17.1...4.18.2) --- updated-dependencies: - dependency-name: qs dependency-type: indirect - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/chess/package-lock.json | 660 ++++++++++++++++++++----------- 1 file changed, 421 insertions(+), 239 deletions(-) diff --git a/examples/chess/package-lock.json b/examples/chess/package-lock.json index c60f87be6..8d5bf9b62 100644 --- a/examples/chess/package-lock.json +++ b/examples/chess/package-lock.json @@ -398,13 +398,13 @@ "dev": true }, "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { "node": ">= 0.6" @@ -912,30 +912,33 @@ } }, "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "dev": true, "dependencies": { - "bytes": "3.1.0", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, "engines": { "node": ">= 0.8" @@ -950,10 +953,19 @@ "ms": "2.0.0" } }, + "node_modules/body-parser/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/bonjour": { @@ -1692,17 +1704,37 @@ } }, "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, "dependencies": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" }, "engines": { "node": ">= 0.6" } }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -1713,9 +1745,9 @@ } }, "node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "dev": true, "engines": { "node": ">= 0.6" @@ -2207,10 +2239,14 @@ } }, "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, "node_modules/detect-node": { "version": "2.1.0", @@ -2362,7 +2398,7 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true }, "node_modules/electron-to-chromium": { @@ -2389,7 +2425,7 @@ "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, "engines": { "node": ">= 0.8" @@ -2597,7 +2633,7 @@ "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, "engines": { "node": ">= 0.6" @@ -2791,38 +2827,39 @@ "dev": true }, "node_modules/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dev": true, "dependencies": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -2846,12 +2883,50 @@ "ms": "2.0.0" } }, + "node_modules/express/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", @@ -3010,17 +3085,17 @@ } }, "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dev": true, "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "engines": { @@ -3039,9 +3114,18 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/finalhandler/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/find-cache-dir": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", @@ -3131,7 +3215,7 @@ "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, "engines": { "node": ">= 0.6" @@ -3563,26 +3647,38 @@ "dev": true }, "node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/http-errors/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "node_modules/http-errors/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } }, "node_modules/http-parser-js": { "version": "0.5.3", @@ -4617,7 +4713,7 @@ "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, "engines": { "node": ">= 0.6" @@ -4689,21 +4785,21 @@ } }, "node_modules/mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "dependencies": { - "mime-db": "1.50.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -4884,9 +4980,9 @@ } }, "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, "engines": { "node": ">= 0.6" @@ -5145,9 +5241,9 @@ "dev": true }, "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "dependencies": { "ee-first": "1.1.1" @@ -5650,12 +5746,18 @@ } }, "node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/querystring": { @@ -5713,13 +5815,13 @@ } }, "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dev": true, "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.2", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -5728,9 +5830,9 @@ } }, "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, "engines": { "node": ">= 0.8" @@ -6327,24 +6429,24 @@ } }, "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, "dependencies": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "2.0.0", "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", + "ms": "2.1.3", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "engines": { "node": ">= 0.8.0" @@ -6362,15 +6464,33 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/send/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/serialize-javascript": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", @@ -6438,15 +6558,15 @@ "dev": true }, "node_modules/serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.18.0" }, "engines": { "node": ">= 0.8.0" @@ -6495,9 +6615,9 @@ } }, "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true }, "node_modules/shallow-clone": { @@ -7292,9 +7412,9 @@ } }, "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, "engines": { "node": ">=0.6" @@ -7417,7 +7537,7 @@ "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, "engines": { "node": ">= 0.8" @@ -8685,13 +8805,13 @@ "dev": true }, "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, "acorn": { @@ -9087,27 +9207,29 @@ } }, "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "dev": true, "requires": { - "bytes": "3.1.0", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "dependencies": { "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true }, "debug": { @@ -9119,10 +9241,16 @@ "ms": "2.0.0" } }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -9740,12 +9868,20 @@ "dev": true }, "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } } }, "content-type": { @@ -9755,9 +9891,9 @@ "dev": true }, "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "dev": true }, "cookie-signature": { @@ -10126,9 +10262,9 @@ "dev": true }, "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true }, "detect-node": { @@ -10262,7 +10398,7 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true }, "electron-to-chromium": { @@ -10286,7 +10422,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true }, "end-of-stream": { @@ -10447,7 +10583,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true }, "eventemitter3": { @@ -10602,38 +10738,39 @@ } }, "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dev": true, "requires": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -10654,11 +10791,29 @@ "ms": "2.0.0" } }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true } } }, @@ -10797,17 +10952,17 @@ } }, "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dev": true, "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "dependencies": { @@ -10823,7 +10978,13 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true } } @@ -10885,7 +11046,7 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true }, "fs-minipass": { @@ -11207,22 +11368,28 @@ "dev": true }, "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true } } @@ -12002,7 +12169,7 @@ "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true }, "memory-fs": { @@ -12056,18 +12223,18 @@ "dev": true }, "mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true }, "mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "requires": { - "mime-db": "1.50.0" + "mime-db": "1.52.0" } }, "mimic-fn": { @@ -12215,9 +12382,9 @@ } }, "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true }, "neo-async": { @@ -12419,9 +12586,9 @@ "dev": true }, "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "requires": { "ee-first": "1.1.1" @@ -12824,10 +12991,13 @@ "dev": true }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "dev": true + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } }, "querystring": { "version": "0.2.0", @@ -12863,21 +13033,21 @@ "dev": true }, "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dev": true, "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.2", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "dependencies": { "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true } } @@ -13366,24 +13536,24 @@ "dev": true }, "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "2.0.0", "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", + "ms": "2.1.3", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "dependencies": { "debug": { @@ -13398,15 +13568,27 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true } } @@ -13474,15 +13656,15 @@ } }, "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.18.0" } }, "set-blocking": { @@ -13521,9 +13703,9 @@ } }, "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true }, "shallow-clone": { @@ -14169,9 +14351,9 @@ } }, "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true }, "ts-loader": { @@ -14268,7 +14450,7 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true }, "unset-value": { From 5b622a815d905fedf493519897ed2be400051976 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jan 2023 09:49:20 +0100 Subject: [PATCH 119/234] chore(deps): bump json5 from 1.0.1 to 1.0.2 in /examples/chess (#358) Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2. - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2) --- updated-dependencies: - dependency-name: json5 dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/chess/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/chess/package-lock.json b/examples/chess/package-lock.json index 8d5bf9b62..ff4f8cc43 100644 --- a/examples/chess/package-lock.json +++ b/examples/chess/package-lock.json @@ -4540,9 +4540,9 @@ "dev": true }, "node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" @@ -12029,9 +12029,9 @@ "dev": true }, "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" From ae6771872d3eb2ca1141ecadadf604f1ab34d5a3 Mon Sep 17 00:00:00 2001 From: Nicolas Mattia Date: Wed, 11 Jan 2023 22:26:27 +0100 Subject: [PATCH 120/234] Add documentation for time() (#359) This mentions that the value returned by `time()` is nanoseconds, elapsed since the epoch. --- src/ic-cdk/src/api/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index 1395c646f..0108de1a1 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -24,7 +24,7 @@ pub fn trap(message: &str) -> ! { unreachable!() } -/// Get current timestamp +/// Get current timestamp, in nanoseconds since the epoch (1970-01-01) pub fn time() -> u64 { // SAFETY: ic0.time is always safe to call. unsafe { ic0::time() as u64 } From 37e9ad256398c25dc2169683623f6f6e445f4f23 Mon Sep 17 00:00:00 2001 From: Andriy Berestovskyy <91958447+dfinity-berestovskyy@users.noreply.github.com> Date: Wed, 18 Jan 2023 23:07:56 +0100 Subject: [PATCH 121/234] RUN-515: Allow timers to cancel themselves (#360) --- e2e-tests/canisters/timers.rs | 18 ++++++++++++++++++ e2e-tests/tests/e2e.rs | 21 +++++++++++++++++++++ src/ic-cdk/src/timer.rs | 2 +- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/e2e-tests/canisters/timers.rs b/e2e-tests/canisters/timers.rs index b24ab2972..0c9a8ff0f 100644 --- a/e2e-tests/canisters/timers.rs +++ b/e2e-tests/canisters/timers.rs @@ -40,6 +40,15 @@ fn schedule_long() { LONG.with(|long| long.set(id)); } +#[update] +fn set_self_cancelling_timer() { + let id = set_timer(Duration::from_secs(0), || { + cancel_long(); + add_event("timer cancelled self"); + }); + LONG.with(|long| long.set(id)); +} + #[update] fn cancel_long() { LONG.with(|long| clear_timer(long.get())); @@ -51,6 +60,15 @@ fn start_repeating() { REPEATING.with(|repeating| repeating.set(id)); } +#[update] +fn set_self_cancelling_periodic_timer() { + let id = set_timer_interval(Duration::from_secs(0), || { + stop_repeating(); + add_event("periodic timer cancelled self") + }); + REPEATING.with(|repeating| repeating.set(id)); +} + #[update] fn stop_repeating() { REPEATING.with(|repeating| clear_timer(repeating.get())); diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index f16ef5463..bd8e9abd8 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -229,6 +229,27 @@ fn test_timers() { ); } +#[test] +fn test_timers_can_cancel_themselves() { + let env = StateMachine::new(); + let wasm = cargo_build_canister("timers"); + let canister_id = env.install_canister(wasm, vec![], None).unwrap(); + + call_candid::<_, ()>(&env, canister_id, "set_self_cancelling_timer", ()) + .expect("Failed to call set_self_cancelling_timer"); + call_candid::<_, ()>(&env, canister_id, "set_self_cancelling_periodic_timer", ()) + .expect("Failed to call set_self_cancelling_periodic_timer"); + + advance_seconds(&env, 1); + + let (events,): (Vec,) = + query_candid(&env, canister_id, "get_events", ()).expect("Failed to call get_events"); + assert_eq!( + events, + ["timer cancelled self", "periodic timer cancelled self"] + ); +} + fn advance_seconds(env: &StateMachine, seconds: u32) { for _ in 0..seconds { env.advance_time(Duration::from_secs(1)); diff --git a/src/ic-cdk/src/timer.rs b/src/ic-cdk/src/timer.rs index 2e6cd73fe..7692d6f07 100644 --- a/src/ic-cdk/src/timer.rs +++ b/src/ic-cdk/src/timer.rs @@ -227,7 +227,7 @@ extern "C" fn timer_executor() { } Task::Repeated { ref mut func, .. } => { func(); - TASKS.with(|tasks| *tasks.borrow_mut().get_mut(task_id).unwrap() = task); + TASKS.with(|tasks| tasks.borrow_mut().get_mut(task_id).map(|slot| *slot = task)); } } } From 719625f1f465a3139814a95fc41c55fb13aeedd3 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 18 Jan 2023 22:20:18 -0500 Subject: [PATCH 122/234] chore: release ic-cdk v0.6.9 and ic0 v0.18.9 (#362) * ic0 0.18.9 * ic-cdk 0.6.9 --- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 6 ++++++ src/ic-cdk/Cargo.toml | 4 ++-- src/ic0/Cargo.toml | 2 +- src/ic0/ic0.txt | 18 +++++++++--------- src/ic0/src/ic0.rs | 12 ++++++++---- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 0298b4e73..32b04bd03 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.6.8" +version = "0.6.8" # no need to sync with ic-cdk authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 82931e7dc..4d34c858e 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.6.9] - 2023-01-18 + +### Fixed + +- Allow timers to cancel themselves. (#360) + ### Refactored - Change from pleco to tanton for the chess library in the chess example. (#345) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index a17abd54d..085f90f5d 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.6.8" +version = "0.6.9" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." @@ -19,7 +19,7 @@ candid = "0.8" cfg-if = "1.0.0" serde = "1.0.110" serde_bytes = "0.11.7" -ic0 = { path = "../ic0", version = "0.18.4" } +ic0 = { path = "../ic0", version = "0.18.9" } ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.6.7" } slotmap = { version = "1.0.6", optional = true } futures = { version = "0.3.25", optional = true } diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml index 248e0e156..c5b97979c 100644 --- a/src/ic0/Cargo.toml +++ b/src/ic0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic0" -version = "0.18.7" +version = "0.18.9" authors = ["DFINITY Stiftung "] edition = "2021" description = "Internet Computer System API Binding." diff --git a/src/ic0/ic0.txt b/src/ic0/ic0.txt index 994b0d602..0c9cae2ac 100644 --- a/src/ic0/ic0.txt +++ b/src/ic0/ic0.txt @@ -23,12 +23,13 @@ ic0.canister_self_copy : (dst : i32, offset : i32, size : i32) -> (); // * ic0.canister_cycle_balance : () -> i64; // * ic0.canister_cycle_balance128 : (dst : i32) -> (); // * ic0.canister_status : () -> i32; // * +ic0.canister_version : () -> i64; // * ic0.msg_method_name_size : () -> i32; // F ic0.msg_method_name_copy : (dst : i32, offset : i32, size : i32) -> (); // F ic0.accept_message : () -> (); // F -ic0.call_new : // U Ry Rt H +ic0.call_new : // U Ry Rt T ( callee_src : i32, callee_size : i32, name_src : i32, @@ -38,13 +39,11 @@ ic0.call_new : // U reject_fun : i32, reject_env : i32 ) -> (); -ic0.call_on_cleanup : (fun : i32, env : i32) -> (); // U Ry Rt H -ic0.call_data_append : (src : i32, size : i32) -> (); // U Ry Rt H -ic0.call_cycles_add : (amount : i64) -> (); // U Ry Rt H -ic0.call_cycles_add128 : (amount_high : i64, amount_low: i64) -> (); // U Ry Rt H -ic0.call_perform : () -> ( err_code : i32 ); // U Ry Rt H - -ic0.global_timer_set : (timestamp : i64) -> i64; // I U Ry Rt C H +ic0.call_on_cleanup : (fun : i32, env : i32) -> (); // U Ry Rt T +ic0.call_data_append : (src : i32, size : i32) -> (); // U Ry Rt T +ic0.call_cycles_add : (amount : i64) -> (); // U Ry Rt T +ic0.call_cycles_add128 : (amount_high : i64, amount_low: i64) -> (); // U Ry Rt T +ic0.call_perform : () -> ( err_code : i32 ); // U Ry Rt T ic0.stable_size : () -> (page_count : i32); // * ic0.stable_grow : (new_pages : i32) -> (old_page_count : i32); // * @@ -55,12 +54,13 @@ ic0.stable64_grow : (new_pages : i64) -> (old_page_count : i64); // * ic0.stable64_write : (offset : i64, src : i64, size : i64) -> (); // * ic0.stable64_read : (dst : i64, offset : i64, size : i64) -> (); // * -ic0.certified_data_set : (src: i32, size: i32) -> (); // I G U Ry Rt H +ic0.certified_data_set : (src: i32, size: i32) -> (); // I G U Ry Rt T ic0.data_certificate_present : () -> i32; // * ic0.data_certificate_size : () -> i32; // * ic0.data_certificate_copy : (dst: i32, offset: i32, size: i32) -> (); // * ic0.time : () -> (timestamp : i64); // * +ic0.global_timer_set : (timestamp : i64) -> i64; // I U Ry Rt C T ic0.performance_counter : (counter_type : i32) -> (counter : i64); // * s ic0.debug_print : (src : i32, size : i32) -> (); // * s diff --git a/src/ic0/src/ic0.rs b/src/ic0/src/ic0.rs index 3383f5a3f..bac978350 100644 --- a/src/ic0/src/ic0.rs +++ b/src/ic0/src/ic0.rs @@ -24,6 +24,7 @@ extern "C" { pub fn canister_cycle_balance() -> i64; pub fn canister_cycle_balance128(dst: i32); pub fn canister_status() -> i32; + pub fn canister_version() -> i64; pub fn msg_method_name_size() -> i32; pub fn msg_method_name_copy(dst: i32, offset: i32, size: i32); pub fn accept_message(); @@ -42,7 +43,6 @@ extern "C" { pub fn call_cycles_add(amount: i64); pub fn call_cycles_add128(amount_high: i64, amount_low: i64); pub fn call_perform() -> i32; - pub fn global_timer_set(timestamp: i64) -> i64; pub fn stable_size() -> i32; pub fn stable_grow(new_pages: i32) -> i32; pub fn stable_write(offset: i32, src: i32, size: i32); @@ -56,6 +56,7 @@ extern "C" { pub fn data_certificate_size() -> i32; pub fn data_certificate_copy(dst: i32, offset: i32, size: i32); pub fn time() -> i64; + pub fn global_timer_set(timestamp: i64) -> i64; pub fn performance_counter(counter_type: i32) -> i64; pub fn debug_print(src: i32, size: i32); pub fn trap(src: i32, size: i32); @@ -129,6 +130,9 @@ mod non_wasm { pub unsafe fn canister_status() -> i32 { panic!("canister_status should only be called inside canisters."); } + pub unsafe fn canister_version() -> i64 { + panic!("canister_version should only be called inside canisters."); + } pub unsafe fn msg_method_name_size() -> i32 { panic!("msg_method_name_size should only be called inside canisters."); } @@ -165,9 +169,6 @@ mod non_wasm { pub unsafe fn call_perform() -> i32 { panic!("call_perform should only be called inside canisters."); } - pub unsafe fn global_timer_set(timestamp: i64) -> i64 { - panic!("global_timer_set should only be called inside canisters."); - } pub unsafe fn stable_size() -> i32 { panic!("stable_size should only be called inside canisters."); } @@ -207,6 +208,9 @@ mod non_wasm { pub unsafe fn time() -> i64 { panic!("time should only be called inside canisters."); } + pub unsafe fn global_timer_set(timestamp: i64) -> i64 { + panic!("global_timer_set should only be called inside canisters."); + } pub unsafe fn performance_counter(counter_type: i32) -> i64 { panic!("performance_counter should only be called inside canisters."); } From 16dc6fe410066c1ae5b8bba6a9acc238aec376b9 Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Thu, 19 Jan 2023 16:16:54 +0000 Subject: [PATCH 123/234] feat: impl From for Subaccount (#361) --- library/ic-ledger-types/src/lib.rs | 21 +++++++++++++++++++++ src/ic-cdk/CHANGELOG.md | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/library/ic-ledger-types/src/lib.rs b/library/ic-ledger-types/src/lib.rs index 6b04ad877..64fbeb752 100644 --- a/library/ic-ledger-types/src/lib.rs +++ b/library/ic-ledger-types/src/lib.rs @@ -123,6 +123,16 @@ impl fmt::Display for Tokens { )] pub struct Subaccount(pub [u8; 32]); +impl From for Subaccount { + fn from(principal: Principal) -> Self { + let mut subaccount = [0; 32]; + let principal = principal.as_slice(); + subaccount[0] = principal.len().try_into().unwrap(); + subaccount[1..1 + principal.len()].copy_from_slice(principal); + Subaccount(subaccount) + } +} + /// AccountIdentifier is a 32-byte array. /// The first 4 bytes is big-endian encoding of a CRC32 checksum of the last 28 bytes. #[derive( @@ -556,4 +566,15 @@ mod tests { Principal::from_text("rkp4c-7iaaa-aaaaa-aaaca-cai").unwrap() ); } + + #[test] + fn principal_to_subaccount() { + // The account generated is the account used to top up canister 4bkt6-4aaaa-aaaaf-aaaiq-cai + let principal = Principal::from_text("4bkt6-4aaaa-aaaaf-aaaiq-cai").unwrap(); + let subaccount = Subaccount::from(principal); + assert_eq!( + AccountIdentifier::new(&MAINNET_CYCLES_MINTING_CANISTER_ID, &subaccount).to_string(), + "d8646d1cbe44002026fa3e0d86d51a560b1c31d669bc8b7f66421c1b2feaa59f" + ) + } } diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 4d34c858e..ee376d825 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Added + +- Implemented `From` for `Subaccount` (#361) + ## [0.6.9] - 2023-01-18 ### Fixed From 13278effa50d9e3514bd813c36cde5e811cbaf0b Mon Sep 17 00:00:00 2001 From: mraszyk <31483726+mraszyk@users.noreply.github.com> Date: Fri, 20 Jan 2023 15:42:32 +0100 Subject: [PATCH 124/234] feat: add ic0.canister_version to cdk-rs (#350) * add ic0.canister_version to cdk-rs * update CHANGELOG Co-authored-by: Martin Raszyk Co-authored-by: Linwei Shang --- src/ic-cdk/CHANGELOG.md | 1 + src/ic-cdk/src/api/mod.rs | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index ee376d825..9164578c6 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Implemented `From` for `Subaccount` (#361) +- Added `ic0.canister_version` as a public function. ## [0.6.9] - 2023-01-18 diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index 0108de1a1..f758231e2 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -127,3 +127,9 @@ pub fn performance_counter(counter_type: u32) -> u64 { // SAFETY: ic0.performance_counter is always safe to call. unsafe { ic0::performance_counter(counter_type as i32) as u64 } } + +/// Get the value of canister version. +pub fn canister_version() -> u64 { + // SAFETY: ic0.canister_version is always safe to call. + unsafe { ic0::canister_version() as u64 } +} From 70ecd3486563668a64b417e33b8ffb9ffa2073c4 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 20 Jan 2023 10:12:21 -0500 Subject: [PATCH 125/234] chore: release ic-cdk v0.6.10 and ic-ledger-types v0.2.1 (#363) --- library/ic-ledger-types/CHANGELOG.md | 8 ++++++++ library/ic-ledger-types/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 5 +++-- src/ic-cdk/Cargo.toml | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index 137fe6153..dfe35b2b9 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [unreleased] + +## [0.2.1] - 2023-01-20 + +### Added + +- Implemented `From` for `Subaccount` (#361) + ## [0.2.0] - 2022-11-04 ### Changed - Upgrade `ic-cdk` to v0.6 and `candid` to v0.8. diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 94d97f756..2972a5cfa 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.2.0" +version = "0.2.1" edition = "2021" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 9164578c6..25a7c563e 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,10 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.6.10] - 2023-01-20 + ### Added -- Implemented `From` for `Subaccount` (#361) -- Added `ic0.canister_version` as a public function. +- Added `ic0.canister_version` as a public function. (#350) ## [0.6.9] - 2023-01-18 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 085f90f5d..3b0700966 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.6.9" +version = "0.6.10" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." From 0ee7a3c630fb635b8c8a843317d68d439f4a5408 Mon Sep 17 00:00:00 2001 From: Andriy Berestovskyy <91958447+dfinity-berestovskyy@users.noreply.github.com> Date: Tue, 31 Jan 2023 19:05:02 +0100 Subject: [PATCH 126/234] chore: update the toolchain and `ic-state-machine-tests` (#365) * chore: Update the toolchain and `ic-state-machine-tests` Fix all the new `clippy` warnings. * More `clippy` fixes * bump rust ver in CI * Disable composite queries test --------- Co-authored-by: Linwei Shang --- .github/workflows/ci.yml | 2 +- .github/workflows/examples.yml | 2 +- e2e-tests/Cargo.toml | 2 +- e2e-tests/canisters/async.rs | 14 +++++++++----- e2e-tests/src/lib.rs | 2 +- e2e-tests/tests/e2e.rs | 2 ++ library/ic-certified-map/src/rbtree.rs | 2 +- library/ic-certified-map/src/rbtree/test.rs | 2 +- rust-toolchain.toml | 2 +- src/ic-cdk-macros/src/import.rs | 4 ++-- src/ic-cdk-macros/src/lib.rs | 2 +- src/ic-cdk/src/api/stable/tests.rs | 6 +++--- src/ic-cdk/src/timer.rs | 1 + src/ic0/src/lib.rs | 2 +- 14 files changed, 26 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 01fb123ab..21db968da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ concurrency: cancel-in-progress: true env: - rust-version: 1.60.0 + rust-version: 1.66.1 jobs: build: diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 47ccabbb2..039e68c46 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -11,7 +11,7 @@ concurrency: cancel-in-progress: true env: - rust-version: 1.60.0 + rust-version: 1.66.1 dfx-version: 0.12.0-beta.6 jobs: diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index c2f99f95d..8876bffb7 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -36,5 +36,5 @@ name = "timers" path = "canisters/timers.rs" [dev-dependencies] -ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "dcbf401f27d9b48354e68389c6d8293c4233b055" } +ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "467663a9d0dc6eac152bcd92df18850e2aed1632" } candid = "0.8" diff --git a/e2e-tests/canisters/async.rs b/e2e-tests/canisters/async.rs index 92b764467..0871433f3 100644 --- a/e2e-tests/canisters/async.rs +++ b/e2e-tests/canisters/async.rs @@ -22,11 +22,15 @@ fn invocation_count() -> u64 { #[update] async fn panic_after_async() { - let mut lock = RESOURCE - .write() - .unwrap_or_else(|_| ic_cdk::api::trap("failed to obtain a write lock")); - *lock += 1; - let _: (u64,) = ic_cdk::call(ic_cdk::api::id(), "inc", (*lock,)) + let value = { + let mut lock = RESOURCE + .write() + .unwrap_or_else(|_| ic_cdk::api::trap("failed to obtain a write lock")); + *lock += 1; + *lock + // Drop the lock before the await point. + }; + let _: (u64,) = ic_cdk::call(ic_cdk::api::id(), "inc", (value,)) .await .expect("failed to call self"); ic_cdk::api::trap("Goodbye, cruel world.") diff --git a/e2e-tests/src/lib.rs b/e2e-tests/src/lib.rs index baae339d2..5187448a0 100644 --- a/e2e-tests/src/lib.rs +++ b/e2e-tests/src/lib.rs @@ -25,7 +25,7 @@ pub fn cargo_build_canister(bin_name: &str) -> Vec { .bin(bin_name) .args(["--profile", "canister-release"]) .manifest_path(&cargo_toml_path) - .target_dir(&wasm_target_dir); + .target_dir(wasm_target_dir); let binary = cargo_build .run() diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index bd8e9abd8..ad004789c 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -167,7 +167,9 @@ fn test_notify_calls() { assert_eq!(n, 1); } +// Composite queries are not enabled yet. #[test] +#[ignore] fn test_composite_query() { let env = StateMachine::new(); let wasm = cargo_build_canister("async"); diff --git a/library/ic-certified-map/src/rbtree.rs b/library/ic-certified-map/src/rbtree.rs index 18322f6ef..38e65a3d3 100644 --- a/library/ic-certified-map/src/rbtree.rs +++ b/library/ic-certified-map/src/rbtree.rs @@ -509,7 +509,7 @@ impl, V: AsHashTree + 'static> RbTree { ) -> HashTree<'a> { match n { None => Empty, - Some(n) => match (*n).key.as_ref().cmp(lo.as_ref()) { + Some(n) => match (n).key.as_ref().cmp(lo.as_ref()) { Equal => three_way_fork( n.left_hash_tree(), match lo { diff --git a/library/ic-certified-map/src/rbtree/test.rs b/library/ic-certified-map/src/rbtree/test.rs index cdb62b836..206906757 100644 --- a/library/ic-certified-map/src/rbtree/test.rs +++ b/library/ic-certified-map/src/rbtree/test.rs @@ -36,7 +36,7 @@ fn get_leaf_values<'a>(ht: &'a HashTree<'a>) -> Vec<&'a [u8]> { go(&lr.1, values); } HashTree::Labeled(_, t) => { - go(&*t, values); + go(t, values); } _ => (), } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 9b31b1996..f86079475 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.60.0" +channel = "1.66.1" targets = ["wasm32-unknown-unknown"] components = ["rustfmt", "clippy"] diff --git a/src/ic-cdk-macros/src/import.rs b/src/ic-cdk-macros/src/import.rs index 044d27c03..ed3803941 100644 --- a/src/ic-cdk-macros/src/import.rs +++ b/src/ic-cdk-macros/src/import.rs @@ -21,7 +21,7 @@ fn get_env_id_and_candid(canister_name: &str) -> Result<(String, PathBuf), Error std::env::var(canister_id_var_name).map_err(|_| { Error::new( Span::call_site(), - &format!( + format!( "Could not find DFX bindings for canister named '{}'. Did you build using DFX?", canister_name ), @@ -199,7 +199,7 @@ pub(crate) fn ic_import(attr: TokenStream, item: TokenStream) -> Result TokenStream { /// When the guard function returns an error, the post_upgrade function will not proceed. /// /// ```rust -/// # use ic_cdk::post_upgrade +/// # use ic_cdk::post_upgrade; /// fn guard_function() -> Result<(), String> { /// // ... /// # unimplemented!() diff --git a/src/ic-cdk/src/api/stable/tests.rs b/src/ic-cdk/src/api/stable/tests.rs index 3371e3710..5141238e4 100644 --- a/src/ic-cdk/src/api/stable/tests.rs +++ b/src/ic-cdk/src/api/stable/tests.rs @@ -31,13 +31,13 @@ impl StableMemory for TestStableMemory { } fn stable_grow(&self, new_pages: u32) -> Result { - let new_bytes = new_pages as usize * WASM_PAGE_SIZE_IN_BYTES as usize; + let new_bytes = new_pages as usize * WASM_PAGE_SIZE_IN_BYTES; let mut vec = self.memory.lock().unwrap(); let previous_len = vec.len(); let new_len = vec.len() + new_bytes; vec.resize(new_len, 0); - Ok((previous_len / WASM_PAGE_SIZE_IN_BYTES as usize) as u32) + Ok((previous_len / WASM_PAGE_SIZE_IN_BYTES) as u32) } fn stable64_grow(&self, new_pages: u64) -> Result { @@ -73,7 +73,7 @@ impl StableMemory for TestStableMemory { } fn pages_required(bytes_len: usize) -> usize { - let page_size = WASM_PAGE_SIZE_IN_BYTES as usize; + let page_size = WASM_PAGE_SIZE_IN_BYTES; (bytes_len + page_size - 1) / page_size } diff --git a/src/ic-cdk/src/timer.rs b/src/ic-cdk/src/timer.rs index 7692d6f07..8c150c037 100644 --- a/src/ic-cdk/src/timer.rs +++ b/src/ic-cdk/src/timer.rs @@ -202,6 +202,7 @@ fn update_ic0_timer() { TIMERS.with(|timers| { let timers = timers.borrow(); let soonest_timer = timers.peek().map_or(0, |timer| timer.time); + // SAFETY: ic0::global_timer_set is always a safe call unsafe { ic0::global_timer_set(soonest_timer as i64) }; }); } diff --git a/src/ic0/src/lib.rs b/src/ic0/src/lib.rs index 6675c6b35..fc803c53a 100644 --- a/src/ic0/src/lib.rs +++ b/src/ic0/src/lib.rs @@ -1,2 +1,2 @@ mod ic0; -pub use ic0::*; +pub use crate::ic0::*; From 58791941b72471e09e3d9e733f2a3d4d54e52b5a Mon Sep 17 00:00:00 2001 From: Andriy Berestovskyy <91958447+dfinity-berestovskyy@users.noreply.github.com> Date: Wed, 1 Feb 2023 23:36:13 +0100 Subject: [PATCH 127/234] fix: RUN-527: retry timers execution (#366) # Description This MR retries timers execution after a transient system error. Fixes RUN-527 --- e2e-tests/canisters/timers.rs | 17 +++++++++++++++++ e2e-tests/tests/e2e.rs | 25 +++++++++++++++++++++++++ src/ic-cdk/CHANGELOG.md | 4 ++++ src/ic-cdk/src/timer.rs | 25 ++++++++++++++++++++++--- 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/e2e-tests/canisters/timers.rs b/e2e-tests/canisters/timers.rs index 0c9a8ff0f..a135bc7cc 100644 --- a/e2e-tests/canisters/timers.rs +++ b/e2e-tests/canisters/timers.rs @@ -5,6 +5,7 @@ use ic_cdk::{ }; use std::{ cell::{Cell, RefCell}, + sync::atomic::{AtomicU32, Ordering}, time::Duration, }; @@ -14,6 +15,8 @@ thread_local! { static REPEATING: Cell = Cell::default(); } +static EXECUTED_TIMERS: AtomicU32 = AtomicU32::new(0); + #[query] fn get_events() -> Vec<&'static str> { EVENTS.with(|events| events.borrow().clone()) @@ -34,6 +37,20 @@ fn schedule() { set_timer(Duration::from_secs(4), || add_event("4")); } +#[update] +fn schedule_n_timers(n: u32) { + for i in 0..n { + ic_cdk::timer::set_timer(Duration::from_nanos(i.into()), move || { + EXECUTED_TIMERS.fetch_add(1, Ordering::Relaxed); + }); + } +} + +#[query] +fn executed_timers() -> u32 { + EXECUTED_TIMERS.load(Ordering::Relaxed) +} + #[update] fn schedule_long() { let id = set_timer(Duration::from_secs(9), || add_event("long")); diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index ad004789c..4d17d97eb 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -252,6 +252,31 @@ fn test_timers_can_cancel_themselves() { ); } +#[test] +fn test_scheduling_many_timers() { + // Must be more than the queue limit (500) + let timers_to_schedule = 1_000; + let env = StateMachine::new(); + let wasm = cargo_build_canister("timers"); + let canister_id = env.install_canister(wasm, vec![], None).unwrap(); + + let () = call_candid( + &env, + canister_id, + "schedule_n_timers", + (timers_to_schedule,), + ) + .expect("Error calling schedule_n_timers"); + + // Up to 500 timers will be executed per round + advance_seconds(&env, timers_to_schedule / 500); + + let (executed_timers,): (u32,) = query_candid(&env, canister_id, "executed_timers", ()) + .expect("Error querying executed_timers"); + + assert_eq!(timers_to_schedule, executed_timers); +} + fn advance_seconds(env: &StateMachine, seconds: u32) { for _ in 0..seconds { env.advance_time(Duration::from_secs(1)); diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 25a7c563e..6c7adfaf6 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Fixed + +- Retry timers execution after a transient system error. + ## [0.6.10] - 2023-01-20 ### Added diff --git a/src/ic-cdk/src/timer.rs b/src/ic-cdk/src/timer.rs index 8c150c037..f967e3033 100644 --- a/src/ic-cdk/src/timer.rs +++ b/src/ic-cdk/src/timer.rs @@ -5,6 +5,8 @@ use std::{cell::RefCell, cmp::Ordering, collections::BinaryHeap, mem, time::Dura use futures::{stream::FuturesUnordered, StreamExt}; use slotmap::{new_key_type, KeyData, SlotMap}; +use crate::api::call::RejectionCode; + // To ensure that tasks are removable seamlessly, there are two separate concepts here: tasks, for the actual function being called, // and timers, the scheduled execution of tasks. As this is an implementation detail, this does not affect the exported name TimerId, // which is more accurately a task ID. (The obvious solution to this, `pub use`, invokes a very silly compiler error.) @@ -82,13 +84,14 @@ extern "C" fn global_timer() { // The closest thing to a catch_unwind that's available here is performing an inter-canister call to ourselves; // traps will be caught at the call boundary. This invokes a meaningful cycles cost, and should an alternative for catching traps // become available, this code should be rewritten. + let task_id = timer.task; call_futures.push(async move { ( - timer.task, + timer, crate::call( crate::api::id(), " timer_executor", - (timer.task.0.as_ffi(),), + (task_id.0.as_ffi(),), ) .await, ) @@ -101,11 +104,27 @@ extern "C" fn global_timer() { } }); // run all the collected tasks, and clean up after them if necessary - while let Some((task_id, res)) = call_futures.next().await { + while let Some((timer, res)) = call_futures.next().await { + let task_id = timer.task; match res { Ok(()) => {} Err((code, msg)) => { crate::println!("in canister_global_timer: {code:?}: {msg}"); + match code { + RejectionCode::SysTransient => { + // Try to execute the timer again later. + TIMERS.with(|timers| { + timers.borrow_mut().push(timer); + }); + continue; + } + RejectionCode::NoError + | RejectionCode::SysFatal + | RejectionCode::DestinationInvalid + | RejectionCode::CanisterReject + | RejectionCode::CanisterError + | RejectionCode::Unknown => {} + } } } TASKS.with(|tasks| { From c1aba15f898d2f75ffb2a3e0cf7af6731aaa50e9 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Fri, 3 Feb 2023 17:37:33 +0100 Subject: [PATCH 128/234] refactor(timers): move timers into a separate library (#368) * refactor(timers): move timers into a separate library This change removes the "timers" feature from ic-cdk package and moves the code into a separate library, ic-cdk-timers. There are a few benefits of this approach: 1. The code becomes a little cleaner and easier to maintain because there are no conditional compilation going on. 2. The clients can now mix canisters using the timers implementation with canisters that implement their own timers in the same workspace. This was not possible with the feature approach. * Update both changelogs * soft link license * changelog --------- Co-authored-by: Linwei Shang --- Cargo.toml | 1 + e2e-tests/Cargo.toml | 3 +- e2e-tests/canisters/timers.rs | 9 ++---- src/ic-cdk-timers/CHANGELOG.md | 11 ++++++++ src/ic-cdk-timers/Cargo.toml | 27 ++++++++++++++++++ src/ic-cdk-timers/LICENSE | 1 + .../src/timer.rs => ic-cdk-timers/src/lib.rs} | 28 +++++++++---------- src/ic-cdk/CHANGELOG.md | 4 +-- src/ic-cdk/Cargo.toml | 11 ++------ src/ic-cdk/src/lib.rs | 3 -- 10 files changed, 63 insertions(+), 35 deletions(-) create mode 100644 src/ic-cdk-timers/CHANGELOG.md create mode 100644 src/ic-cdk-timers/Cargo.toml create mode 120000 src/ic-cdk-timers/LICENSE rename src/{ic-cdk/src/timer.rs => ic-cdk-timers/src/lib.rs} (92%) diff --git a/Cargo.toml b/Cargo.toml index ed37aa922..aa3892b7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "src/ic0", "src/ic-cdk", "src/ic-cdk-macros", + "src/ic-cdk-timers", "library/ic-certified-map", "library/ic-ledger-types", "e2e-tests", diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 8876bffb7..69152d83a 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -10,8 +10,9 @@ repository = "https://github.com/dfinity/cdk-rs" [dependencies] cargo_metadata = "0.14.2" escargot = { version = "0.5.7", features = ["print"] } -ic-cdk = { path = "../src/ic-cdk", features = ["timers"] } +ic-cdk = { path = "../src/ic-cdk" } ic-cdk-macros = { path = "../src/ic-cdk-macros" } +ic-cdk-timers = { path = "../src/ic-cdk-timers" } lazy_static = "1.4.0" serde_bytes = "0.11" diff --git a/e2e-tests/canisters/timers.rs b/e2e-tests/canisters/timers.rs index a135bc7cc..ec277fa8f 100644 --- a/e2e-tests/canisters/timers.rs +++ b/e2e-tests/canisters/timers.rs @@ -1,8 +1,5 @@ -use ic_cdk::{ - query, - timer::{clear_timer, set_timer, set_timer_interval, TimerId}, - update, -}; +use ic_cdk::{query, update}; +use ic_cdk_timers::{clear_timer, set_timer, set_timer_interval, TimerId}; use std::{ cell::{Cell, RefCell}, sync::atomic::{AtomicU32, Ordering}, @@ -40,7 +37,7 @@ fn schedule() { #[update] fn schedule_n_timers(n: u32) { for i in 0..n { - ic_cdk::timer::set_timer(Duration::from_nanos(i.into()), move || { + ic_cdk_timers::set_timer(Duration::from_nanos(i.into()), move || { EXECUTED_TIMERS.fetch_add(1, Ordering::Relaxed); }); } diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md new file mode 100644 index 000000000..c5a14b706 --- /dev/null +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [unreleased] + +### Added + +- Initial release of the `ic-cdk-timers` library. diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml new file mode 100644 index 000000000..918365eb5 --- /dev/null +++ b/src/ic-cdk-timers/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "ic-cdk-timers" +version = "0.1.0" +authors = ["DFINITY Stiftung "] +edition = "2021" +description = "Timers library for the Rust CDK." +homepage = "https://docs.rs/ic-cdk" +documentation = "https://docs.rs/ic-cdk-timers" +license = "Apache-2.0" +readme = "README.md" +categories = ["api-bindings", "data-structures", "no-std", "development-tools::ffi"] +keywords = ["internet-computer", "dfinity", "canister", "cdk"] +include = ["src", "Cargo.toml", "LICENSE", "README.md"] +repository = "https://github.com/dfinity/cdk-rs" +rust-version = "1.60.0" + +[dependencies] +ic-cdk = { path = "../../src/ic-cdk", version = "0.6" } +serde = "1.0.110" +serde_bytes = "0.11.7" +ic0 = { path = "../ic0", version = "0.18.9" } +slotmap = { version = "1.0.6" } +futures = { version = "0.3.25" } + +[package.metadata.docs.rs] +default-target = "wasm32-unknown-unknown" +rustc-args = ["--cfg=docsrs"] diff --git a/src/ic-cdk-timers/LICENSE b/src/ic-cdk-timers/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/src/ic-cdk-timers/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/src/ic-cdk/src/timer.rs b/src/ic-cdk-timers/src/lib.rs similarity index 92% rename from src/ic-cdk/src/timer.rs rename to src/ic-cdk-timers/src/lib.rs index f967e3033..bf2eb6abb 100644 --- a/src/ic-cdk/src/timer.rs +++ b/src/ic-cdk-timers/src/lib.rs @@ -5,7 +5,7 @@ use std::{cell::RefCell, cmp::Ordering, collections::BinaryHeap, mem, time::Dura use futures::{stream::FuturesUnordered, StreamExt}; use slotmap::{new_key_type, KeyData, SlotMap}; -use crate::api::call::RejectionCode; +use ic_cdk::api::call::RejectionCode; // To ensure that tasks are removable seamlessly, there are two separate concepts here: tasks, for the actual function being called, // and timers, the scheduled execution of tasks. As this is an implementation detail, this does not affect the exported name TimerId, @@ -65,13 +65,13 @@ impl Eq for Timer {} // This function is called by the IC at or after the timestamp provided to `ic0.global_timer_set`. #[export_name = "canister_global_timer"] extern "C" fn global_timer() { - crate::setup(); - crate::spawn(async { + ic_cdk::setup(); + ic_cdk::spawn(async { // All the calls are made first, according only to the timestamp we *started* with, and then all the results are awaited. // This allows us to use the minimum number of execution rounds, as well as avoid any race conditions. // The only thing that can happen interleavedly is canceling a task, which is seamless by design. let mut call_futures = FuturesUnordered::new(); - let now = crate::api::time(); + let now = ic_cdk::api::time(); TIMERS.with(|timers| { // pop every timer that should have been completed by `now`, and get ready to run its task if it exists loop { @@ -88,8 +88,8 @@ extern "C" fn global_timer() { call_futures.push(async move { ( timer, - crate::call( - crate::api::id(), + ic_cdk::call( + ic_cdk::api::id(), " timer_executor", (task_id.0.as_ffi(),), ) @@ -109,7 +109,7 @@ extern "C" fn global_timer() { match res { Ok(()) => {} Err((code, msg)) => { - crate::println!("in canister_global_timer: {code:?}: {msg}"); + ic_cdk::println!("in canister_global_timer: {code:?}: {msg}"); match code { RejectionCode::SysTransient => { // Try to execute the timer again later. @@ -146,7 +146,7 @@ extern "C" fn global_timer() { time, }) }), - None => crate::println!( + None => ic_cdk::println!( "Failed to reschedule task (needed {interval}, currently {now}, and this would exceed u64::MAX)", interval = interval.as_nanos(), ), @@ -169,7 +169,7 @@ pub fn set_timer(delay: Duration, func: impl FnOnce() + 'static) -> TimerId { let delay_ns = u64::try_from(delay.as_nanos()).expect( "delay out of bounds (must be within `u64::MAX - ic_cdk::api::time()` nanoseconds)", ); - let scheduled_time = crate::api::time().checked_add(delay_ns).expect( + let scheduled_time = ic_cdk::api::time().checked_add(delay_ns).expect( "delay out of bounds (must be within `u64::MAX - ic_cdk::api::time()` nanoseconds)", ); let key = TASKS.with(|tasks| tasks.borrow_mut().insert(Task::Once(Box::new(func)))); @@ -192,7 +192,7 @@ pub fn set_timer_interval(interval: Duration, func: impl FnMut() + 'static) -> T let interval_ns = u64::try_from(interval.as_nanos()).expect( "delay out of bounds (must be within `u64::MAX - ic_cdk::api::time()` nanoseconds)", ); - let scheduled_time = crate::api::time().checked_add(interval_ns).expect( + let scheduled_time = ic_cdk::api::time().checked_add(interval_ns).expect( "delay out of bounds (must be within `u64::MAX - ic_cdk::api::time()` nanoseconds)", ); let key = TASKS.with(|tasks| { @@ -228,10 +228,10 @@ fn update_ic0_timer() { #[export_name = "canister_update timer_executor"] extern "C" fn timer_executor() { - if crate::api::caller() != crate::api::id() { - crate::trap("This function is internal to ic-cdk and should not be called externally."); + if ic_cdk::api::caller() != ic_cdk::api::id() { + ic_cdk::trap("This function is internal to ic-cdk and should not be called externally."); } - let (task_id,) = crate::api::call::arg_data(); + let (task_id,) = ic_cdk::api::call::arg_data(); let task_id = TimerId(KeyData::from_ffi(task_id)); // We can't be holding `TASKS` when we call the function, because it may want to schedule more tasks. // Instead, we swap the task out in order to call it, and then either swap it back in, or remove it. @@ -251,5 +251,5 @@ extern "C" fn timer_executor() { } } } - crate::api::call::reply(()); + ic_cdk::api::call::reply(()); } diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 6c7adfaf6..11af8b591 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,9 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -### Fixed +### Changed -- Retry timers execution after a transient system error. +- The timers API is not a feature anymore, it moved into a separate library, `ic-cdk-timers`. (#368) ## [0.6.10] - 2023-01-20 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 3b0700966..4340c091d 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -16,21 +16,14 @@ rust-version = "1.60.0" [dependencies] candid = "0.8" -cfg-if = "1.0.0" -serde = "1.0.110" -serde_bytes = "0.11.7" ic0 = { path = "../ic0", version = "0.18.9" } ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.6.7" } -slotmap = { version = "1.0.6", optional = true } -futures = { version = "0.3.25", optional = true } - -[features] -timers = ["dep:slotmap", "dep:futures"] +serde = "1.0.110" +serde_bytes = "0.11.7" [dev-dependencies] rstest = "0.12.0" [package.metadata.docs.rs] -all-features = true default-target = "wasm32-unknown-unknown" rustc-args = ["--cfg=docsrs"] diff --git a/src/ic-cdk/src/lib.rs b/src/ic-cdk/src/lib.rs index 1af6554cf..f57bf0417 100644 --- a/src/ic-cdk/src/lib.rs +++ b/src/ic-cdk/src/lib.rs @@ -22,9 +22,6 @@ pub mod api; mod futures; mod printer; pub mod storage; -#[cfg(feature = "timers")] -#[cfg_attr(docsrs, doc(cfg(feature = "timers")))] -pub mod timer; use std::sync::atomic::{AtomicBool, Ordering}; From f7a0d98d8ff1ad1776197af0285631266fc4c841 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 3 Feb 2023 13:10:38 -0500 Subject: [PATCH 129/234] bump version and changelog (#369) --- library/ic-ledger-types/CHANGELOG.md | 4 ++++ library/ic-ledger-types/Cargo.toml | 2 +- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-timers/CHANGELOG.md | 2 ++ src/ic-cdk-timers/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 2 ++ src/ic-cdk/Cargo.toml | 2 +- 7 files changed, 12 insertions(+), 4 deletions(-) diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index dfe35b2b9..08f3eb710 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.3.0] - 2023-02-03 +### Changed +- Upgrade `ic-cdk` to v0.7. + ## [0.2.1] - 2023-01-20 ### Added diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 2972a5cfa..0e0316ce7 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -17,7 +17,7 @@ rust-version = "1.60.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ic-cdk = { path = "../../src/ic-cdk", version = "0.6" } +ic-cdk = { path = "../../src/ic-cdk", version = "0.7" } candid = "0.8.0" crc32fast = "1.2.0" hex = "0.4" diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 32b04bd03..6afcfabc2 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -27,4 +27,4 @@ serde = "1.0.111" [dev-dependencies] trybuild = "1.0" -ic-cdk = { path = "../ic-cdk", version = "0.6" } +ic-cdk = { path = "../ic-cdk", version = "0.7" } diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index c5a14b706..c75c788cd 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.1.0] - 2023-02-03 + ### Added - Initial release of the `ic-cdk-timers` library. diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index 918365eb5..da1e72515 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -15,7 +15,7 @@ repository = "https://github.com/dfinity/cdk-rs" rust-version = "1.60.0" [dependencies] -ic-cdk = { path = "../../src/ic-cdk", version = "0.6" } +ic-cdk = { path = "../../src/ic-cdk", version = "0.7" } serde = "1.0.110" serde_bytes = "0.11.7" ic0 = { path = "../ic0", version = "0.18.9" } diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 11af8b591..7104d86eb 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.7.0] - 2023-02-03 + ### Changed - The timers API is not a feature anymore, it moved into a separate library, `ic-cdk-timers`. (#368) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 4340c091d..9d13faf9a 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.6.10" +version = "0.7.0" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." From 43c1dacbd40b1ecec6010a32d8911d6715df649e Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 3 Feb 2023 15:20:56 -0500 Subject: [PATCH 130/234] chore: release continue (#370) * fix * bump ver * Add readme to ic-cdk-timers --------- Co-authored-by: Adam Spofford --- library/ic-ledger-types/Cargo.toml | 2 +- src/ic-cdk-timers/README.md | 9 +++++++++ src/ic-cdk-timers/src/lib.rs | 11 ++++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 src/ic-cdk-timers/README.md diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 0e0316ce7..36e241e06 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.2.1" +version = "0.3.0" edition = "2021" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." diff --git a/src/ic-cdk-timers/README.md b/src/ic-cdk-timers/README.md new file mode 100644 index 000000000..4539f98f7 --- /dev/null +++ b/src/ic-cdk-timers/README.md @@ -0,0 +1,9 @@ +# ic-cdk-timers + +A library for Internet Computer canisters to schedule one-shot or repeating timers, to execute a function at some point in the future. + +## Example + +```rust +ic_cdk_timers::set_timer(Duration::from_secs(1), || ic_cdk::println!("Hello from the future!")); +``` diff --git a/src/ic-cdk-timers/src/lib.rs b/src/ic-cdk-timers/src/lib.rs index bf2eb6abb..fbeac8011 100644 --- a/src/ic-cdk-timers/src/lib.rs +++ b/src/ic-cdk-timers/src/lib.rs @@ -1,4 +1,13 @@ -//! Provides simple timer functionality for executing a function in the future. +//! A library for Internet Computer canisters to schedule one-shot or repeating timers, to execute a function at some point in the future. +//! +//! # Example +//! +//! ```rust,no_run +//! # use std::time::Duration; +//! # fn main() { +//! ic_cdk_timers::set_timer(Duration::from_secs(1), || ic_cdk::println!("Hello from the future!")); +//! # } +//! ``` use std::{cell::RefCell, cmp::Ordering, collections::BinaryHeap, mem, time::Duration}; From 75e84bc9cf8df154e569f725698d3e73fc1feaef Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Mon, 6 Feb 2023 23:24:49 +0100 Subject: [PATCH 131/234] feat: add ICRC-2 transaction types (#364) This change introduces new transaction type variants corresponding to transaction types released in https://dashboard.internetcomputer.org/proposal/104111. See the ICP ledger change https://github.com/dfinity/ic/commit/5f14bf893590686cc6ae8621d57db9f3e1583b61#diff-a90c98102eace573acbc16996024115de6324cbe5df9c56f78ef8046536ba016R612-R625 for more detail. Co-authored-by: Severin Siffert --- library/ic-ledger-types/src/lib.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/ic-ledger-types/src/lib.rs b/library/ic-ledger-types/src/lib.rs index 64fbeb752..fe0972ff1 100644 --- a/library/ic-ledger-types/src/lib.rs +++ b/library/ic-ledger-types/src/lib.rs @@ -273,6 +273,20 @@ pub enum Operation { amount: Tokens, fee: Tokens, }, + Approve { + from: AccountIdentifier, + spender: AccountIdentifier, + // TODO: add the allowance_e8s field after the official ICRC-2 release. + expires_at: Option, + fee: Tokens, + }, + TransferFrom { + from: AccountIdentifier, + to: AccountIdentifier, + spender: AccountIdentifier, + amount: Tokens, + fee: Tokens, + }, } #[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] From fb32fa0eeb9eb4307a7c72f9b9f389f74e367768 Mon Sep 17 00:00:00 2001 From: Roman Kashitsyn Date: Mon, 13 Feb 2023 21:46:31 +0100 Subject: [PATCH 132/234] chore(ic-ledger-types): release version 0.4.0 (#371) --- library/ic-ledger-types/CHANGELOG.md | 4 ++++ library/ic-ledger-types/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index 08f3eb710..0625b6fab 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.4.0] - 2023-02-13 +### Changed +- Extend the Operation type to support approve/transfer_from transactions. + ## [0.3.0] - 2023-02-03 ### Changed - Upgrade `ic-cdk` to v0.7. diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 36e241e06..3a988b5e7 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.3.0" +version = "0.4.0" edition = "2021" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." From b730f82f3d1504f1ef6e2a600c871a22e68368b0 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 22 Feb 2023 14:19:00 -0500 Subject: [PATCH 133/234] chore: fix documents and release affected crates (#372) * fix docs * bump and changelog * remove chess frontend * update ic rev * date --- e2e-tests/Cargo.toml | 2 +- examples/chess/dfx.json | 12 - examples/chess/package-lock.json | 15156 ---------------- examples/chess/package.json | 39 - examples/chess/src/chess_rs_assets/chess.tsx | 26 - examples/chess/src/chess_rs_assets/index.css | 5 - examples/chess/src/chess_rs_assets/index.html | 10 - examples/chess/src/chess_rs_assets/index.tsx | 6 - .../chess/src/chess_rs_assets/integration.tsx | 281 - examples/chess/tests/basic.bats | 2 - examples/chess/tsconfig.json | 73 - examples/chess/webpack.config.js | 110 - library/ic-certified-map/CHANGELOG.md | 6 +- library/ic-certified-map/Cargo.toml | 2 +- library/ic-certified-map/src/hashtree.rs | 2 +- library/ic-certified-map/src/rbtree.rs | 2 +- library/ic-ledger-types/CHANGELOG.md | 4 + library/ic-ledger-types/Cargo.toml | 2 +- library/ic-ledger-types/src/lib.rs | 2 +- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-macros/src/lib.rs | 2 +- src/ic-cdk-timers/CHANGELOG.md | 6 + src/ic-cdk-timers/Cargo.toml | 2 +- src/ic-cdk-timers/src/lib.rs | 4 +- src/ic-cdk/CHANGELOG.md | 6 + src/ic-cdk/Cargo.toml | 2 +- .../api/management_canister/http_request.rs | 8 +- .../src/api/management_canister/main/mod.rs | 2 +- 28 files changed, 38 insertions(+), 15738 deletions(-) delete mode 100644 examples/chess/package-lock.json delete mode 100644 examples/chess/package.json delete mode 100644 examples/chess/src/chess_rs_assets/chess.tsx delete mode 100644 examples/chess/src/chess_rs_assets/index.css delete mode 100644 examples/chess/src/chess_rs_assets/index.html delete mode 100644 examples/chess/src/chess_rs_assets/index.tsx delete mode 100644 examples/chess/src/chess_rs_assets/integration.tsx delete mode 100644 examples/chess/tsconfig.json delete mode 100644 examples/chess/webpack.config.js diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 69152d83a..3edb91efe 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -37,5 +37,5 @@ name = "timers" path = "canisters/timers.rs" [dev-dependencies] -ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "467663a9d0dc6eac152bcd92df18850e2aed1632" } +ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "1612a202d030faa496e1694eed98be4179fca856" } candid = "0.8" diff --git a/examples/chess/dfx.json b/examples/chess/dfx.json index 1bb58ccc3..0c26e6535 100644 --- a/examples/chess/dfx.json +++ b/examples/chess/dfx.json @@ -6,18 +6,6 @@ "candid": "src/chess_rs/chess.did", "wasm": "target/wasm32-unknown-unknown/release/chess_rs-opt.wasm", "build": "sh ../build.sh chess chess_rs" - }, - "chess_rs_assets": { - "dependencies": [ - "chess_rs" - ], - "frontend": { - "entrypoint": "src/chess_rs_assets/index.tsx" - }, - "source": [ - "dist/" - ], - "type": "assets" } } } diff --git a/examples/chess/package-lock.json b/examples/chess/package-lock.json deleted file mode 100644 index ff4f8cc43..000000000 --- a/examples/chess/package-lock.json +++ /dev/null @@ -1,15156 +0,0 @@ -{ - "name": "new_project", - "version": "0.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "new_project", - "version": "0.1.0", - "dependencies": { - "@dfinity/agent": "^0.9.2", - "@dfinity/candid": "^0.9.2", - "@dfinity/principal": "^0.9.2" - }, - "devDependencies": { - "@types/chess.js": "^0.10.1", - "@types/react": "^16.9.23", - "@types/react-dom": "^16.9.5", - "assert": "^2.0.0", - "buffer": "^6.0.3", - "chess.js": "0.10.3", - "chessboardjsx": "2.4.2", - "copy-webpack-plugin": "^9.0.1", - "css-loader": "^3.6.0", - "html-webpack-plugin": "^5.3.2", - "process": "^0.11.10", - "react": "^16.13.0", - "react-dom": "^16.13.0", - "stream-browserify": "^3.0.0", - "style-loader": "^3.1.0", - "terser-webpack-plugin": "2.2.2", - "ts-loader": "^6.2.1", - "typescript": "^3.8.3", - "webpack": "^5.45.1", - "webpack-cli": "^4.7.2", - "webpack-dev-server": "^3.11.2" - } - }, - "node_modules/@dfinity/agent": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-0.9.3.tgz", - "integrity": "sha512-vR0t5Uf+srbUHTdGunJxek3a4jCmBKU+B2yYEX0/aSGQfJmEf5X5snuNcnrIDOCfHeK7uxmOqs65BdI8Lhn4fg==", - "dependencies": { - "base64-arraybuffer": "^0.2.0", - "bignumber.js": "^9.0.0", - "borc": "^2.1.1", - "buffer": "^6.0.3", - "buffer-pipe": "^0.0.4", - "js-sha256": "0.9.0", - "simple-cbor": "^0.4.1" - }, - "peerDependencies": { - "@dfinity/candid": "^0.9.3", - "@dfinity/principal": "^0.9.3" - } - }, - "node_modules/@dfinity/candid": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-0.9.3.tgz", - "integrity": "sha512-VMovKFrExqN0mwcn1/aut4Ou4cA9IA2+QrBjV+Ro4eVCpVvGpVRqn4jizlV9QnJjcuEBG1yImIG5RKMdZ2ejQQ==", - "dependencies": { - "buffer": "^6.0.3", - "buffer-pipe": "^0.0.4" - } - }, - "node_modules/@dfinity/principal": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-0.9.3.tgz", - "integrity": "sha512-DSL3b/gGm+f57+3XkFjlK4DigtKXe9MVO8UYXDQWkVIhy0UF1KYjRNGs6awc1GTQoOTxeQ8UTFwXuvnEvJ1hpQ==" - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz", - "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@types/chess.js": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@types/chess.js/-/chess.js-0.10.1.tgz", - "integrity": "sha512-cuFMyrUYOWpKm5PRayvk22jLV3BOuWs7iJ7Q4PZJXMWoF7uhjWEojMS4GPk441gn4Ki9BHxbKsll7mrwJ3KT3g==", - "dev": true - }, - "node_modules/@types/eslint": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.0.tgz", - "integrity": "sha512-07XlgzX0YJUn4iG1ocY4IX9DzKSmMGUs6ESKlxWhZRaa0fatIWaHWUVapcuGa8r5HFnTqzj+4OCjd5f7EZ/i/A==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "0.0.50", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", - "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", - "dev": true - }, - "node_modules/@types/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", - "dev": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/html-minifier-terser": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", - "integrity": "sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "16.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.2.tgz", - "integrity": "sha512-zCclL4/rx+W5SQTzFs9wyvvyCwoK9QtBpratqz2IYJ3O8Umrn0m3nsTv0wQBk9sRGpvUe9CwPDrQFB10f1FIjQ==", - "dev": true - }, - "node_modules/@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", - "dev": true - }, - "node_modules/@types/react": { - "version": "16.9.36", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.36.tgz", - "integrity": "sha512-mGgUb/Rk/vGx4NCvquRuSH0GHBQKb1OqpGS9cT9lFxlTLHZgkksgI60TuIxubmn7JuCb+sENHhQciqa0npm0AQ==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "csstype": "^2.2.0" - } - }, - "node_modules/@types/react-dom": { - "version": "16.9.8", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.8.tgz", - "integrity": "sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webpack-cli/configtest": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.4.tgz", - "integrity": "sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ==", - "dev": true, - "peerDependencies": { - "webpack": "4.x.x || 5.x.x", - "webpack-cli": "4.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.3.0.tgz", - "integrity": "sha512-ASiVB3t9LOKHs5DyVUcxpraBXDOKubYu/ihHhU+t1UPpxsivg6Od2E2qU4gJCekfEddzRBzHhzA/Acyw/mlK/w==", - "dev": true, - "dependencies": { - "envinfo": "^7.7.3" - }, - "peerDependencies": { - "webpack-cli": "4.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.2.tgz", - "integrity": "sha512-vgJ5OLWadI8aKjDlOH3rb+dYyPd2GTZuQC/Tihjct6F9GpXGZINo3Y/IVuZVTM1eDQB+/AOsjPUWH/WySDaXvw==", - "dev": true, - "peerDependencies": { - "webpack-cli": "4.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/aggregate-error": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", - "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "dev": true, - "peerDependencies": { - "ajv": ">=5.0.0" - } - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-html": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/anymatch/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, - "node_modules/assert": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", - "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", - "dev": true, - "dependencies": { - "es6-object-assign": "^1.1.0", - "is-nan": "^1.2.1", - "object-is": "^1.0.1", - "util": "^0.12.0" - } - }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "node_modules/async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/autobind-decorator": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/autobind-decorator/-/autobind-decorator-2.4.0.tgz", - "integrity": "sha512-OGYhWUO72V6DafbF8PM8rm3EPbfuyMZcJhtm5/n26IDwO18pohE4eNazLoCGhPiXOCD0gEGmrbU3849QvM8bbw==", - "dev": true, - "engines": { - "node": ">=8.10", - "npm": ">=6.4.1" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base64-arraybuffer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz", - "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/bignumber.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", - "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==", - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dev": true, - "dependencies": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "node_modules/borc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/borc/-/borc-2.1.2.tgz", - "integrity": "sha512-Sy9eoUi4OiKzq7VovMn246iTo17kzuyHJKomCfpWMlI6RpfN1gk95w7d7gH264nApVLg0HZfcpz62/g4VH1Y4w==", - "dependencies": { - "bignumber.js": "^9.0.0", - "buffer": "^5.5.0", - "commander": "^2.15.0", - "ieee754": "^1.1.13", - "iso-url": "~0.4.7", - "json-text-sequence": "~0.1.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/borc/node_modules/buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "node_modules/borc/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz", - "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", - "dev": true, - "dependencies": { - "caniuse-lite": "^1.0.30001264", - "electron-to-chromium": "^1.3.857", - "escalade": "^3.1.1", - "node-releases": "^1.1.77", - "picocolors": "^0.2.1" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "node_modules/buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true - }, - "node_modules/buffer-pipe": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/buffer-pipe/-/buffer-pipe-0.0.4.tgz", - "integrity": "sha512-8cHio1V6wgX+LIX6+af4tCn0+Ljl2vQd9JZdZ8vDJZdDf8x5p2DneKaq1dWxSswJG+sK4Inok9aqoqILG5kQVQ==", - "dependencies": { - "safe-buffer": "^5.1.2" - } - }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacache": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", - "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", - "dev": true, - "dependencies": { - "chownr": "^1.1.2", - "figgy-pudding": "^3.5.1", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.2", - "infer-owner": "^1.0.4", - "lru-cache": "^5.1.1", - "minipass": "^3.0.0", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "p-map": "^3.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^2.7.1", - "ssri": "^7.0.0", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dev": true, - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "node_modules/camel-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001264", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001264.tgz", - "integrity": "sha512-Ftfqqfcs/ePiUmyaySsQ4PUsdcYyXG2rfoBVsk3iY1ahHaJEw65vfb7Suzqm+cEkwwPIv/XWkg27iCpRavH4zA==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chess.js": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/chess.js/-/chess.js-0.10.3.tgz", - "integrity": "sha512-i51JgVM0ksFMbLJYKoDpfrcFxJHq/XQQx8NltCdfMyDv7vpU5JVzsZz1EOw7nA27eGA5t8tSxodAN+Wc704BoQ==", - "dev": true - }, - "node_modules/chessboardjsx": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chessboardjsx/-/chessboardjsx-2.4.2.tgz", - "integrity": "sha512-nVPRmE/peE5e+Pscz0DJVWPli2Q7fg6d8YQfqMfr21oIzOwswX5kUF+Fl1ZthKk6KD5qey0YJ0v+LTLmxCTtRQ==", - "dev": true, - "dependencies": { - "deep-diff": "1.0.1", - "lodash.isequal": "4.5.0", - "react-dnd": "2.6.0", - "react-dnd-html5-backend": "4.0.5", - "react-dnd-multi-backend": "3.1.2" - }, - "peerDependencies": { - "react": ">= 16.3.2", - "react-dom": ">= 16.3.2" - } - }, - "node_modules/chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", - "dev": true, - "dependencies": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "optionalDependencies": { - "fsevents": "^1.2.7" - } - }, - "node_modules/chokidar/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chokidar/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chokidar/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "node_modules/chokidar/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chokidar/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chokidar/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chokidar/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chokidar/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "node_modules/chrome-trace-event": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", - "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/clean-css": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", - "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", - "dev": true, - "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "dev": true - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "node_modules/copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "dev": true, - "dependencies": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/copy-webpack-plugin": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.0.1.tgz", - "integrity": "sha512-14gHKKdYIxF84jCEgPgYXCPpldbwpxxLbCmA7LReY7gvbaT555DgeBWBgBZM116tv/fO6RRJrsivBqRyRlukhw==", - "dev": true, - "dependencies": { - "fast-glob": "^3.2.5", - "glob-parent": "^6.0.0", - "globby": "^11.0.3", - "normalize-path": "^3.0.0", - "p-limit": "^3.1.0", - "schema-utils": "^3.0.0", - "serialize-javascript": "^6.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - } - }, - "node_modules/copy-webpack-plugin/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/copy-webpack-plugin/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/copy-webpack-plugin/node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-loader": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", - "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "cssesc": "^3.0.0", - "icss-utils": "^4.1.1", - "loader-utils": "^1.2.3", - "normalize-path": "^3.0.0", - "postcss": "^7.0.32", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.2.0", - "postcss-modules-values": "^3.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^2.7.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", - "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.10.tgz", - "integrity": "sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/deep-diff": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-1.0.1.tgz", - "integrity": "sha512-Vkn+eQK6H63gObVi3KWmPMb4RdzMpfdp5t0HNppq8Oc7xbwmvBy5BIHsEYSXOiS9Lr/W+3lF020zyPTsGfea4g==", - "dev": true - }, - "node_modules/deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, - "dependencies": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/default-gateway": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", - "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", - "dev": true, - "dependencies": { - "execa": "^1.0.0", - "ip-regex": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/default-gateway/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/default-gateway/node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/default-gateway/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/default-gateway/node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway/node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/default-gateway/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/default-gateway/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/default-gateway/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", - "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", - "dev": true, - "dependencies": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/del/node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, - "dependencies": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/globby/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/delimit-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz", - "integrity": "sha1-m4MZR3wOX4rrPONXrjBfwl6hzSs=" - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/disposables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/disposables/-/disposables-1.0.2.tgz", - "integrity": "sha1-NsamdEdfVaLWkTVnpgFETkh7S24=", - "dev": true - }, - "node_modules/dnd-core": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-2.6.0.tgz", - "integrity": "sha1-ErrWbVh0LG5ffPKUP7aFlED4CcQ=", - "dev": true, - "dependencies": { - "asap": "^2.0.6", - "invariant": "^2.0.0", - "lodash": "^4.2.0", - "redux": "^3.7.1" - } - }, - "node_modules/dnd-multi-backend": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/dnd-multi-backend/-/dnd-multi-backend-3.2.1.tgz", - "integrity": "sha512-A783JbrONpeufxX+jDMHOxR2AWh+gFv5Z/lLpDB3vdON6t0bb2fHSh8fKH2h8gOLRAJGD08m9xYXAJIWreTI5A==", - "dev": true - }, - "node_modules/dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true - }, - "node_modules/dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "dev": true, - "dependencies": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, - "dependencies": { - "buffer-indexof": "^1.0.0" - } - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "dependencies": { - "utila": "~0.4" - } - }, - "node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", - "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/dot-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "node_modules/electron-to-chromium": { - "version": "1.3.858", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.858.tgz", - "integrity": "sha512-EZ0dTXxTX+rgZC8YDVqKNMyp1Ty3hi1LyQwVBBioV7iiYYjFakokumRsIUhNz5ho+QlNKf7iNY5KLdpdH3yqBw==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", - "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/enhanced-resolve/node_modules/memory-fs": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", - "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", - "dev": true, - "dependencies": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - }, - "engines": { - "node": ">=4.3.0 <5.0.0 || >=5.10" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", - "dev": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-module-lexer": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.2.tgz", - "integrity": "sha512-YkAGWqxZq2B4FxQ5y687UwywDwvLQhIMCZ+SDU7ZW729SDHOEI6wVFXwTRecz+yiwJzCsVwC6V7bxyNbZSB1rg==", - "dev": true - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es6-object-assign": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/eventsource": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", - "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", - "dev": true, - "dependencies": { - "original": "^1.0.0" - }, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/express/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/express/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", - "dev": true - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/finalhandler/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/follow-redirects": { - "version": "1.14.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", - "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hoist-non-react-statics": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", - "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==", - "dev": true - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/html-entities": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", - "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==", - "dev": true - }, - "node_modules/html-minifier-terser": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", - "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", - "dev": true, - "dependencies": { - "camel-case": "^4.1.1", - "clean-css": "^4.2.3", - "commander": "^4.1.1", - "he": "^1.2.0", - "param-case": "^3.0.3", - "relateurl": "^0.2.7", - "terser": "^4.6.3" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/html-minifier-terser/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/html-webpack-plugin": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.3.2.tgz", - "integrity": "sha512-HvB33boVNCz2lTyBsSiMffsJ+m0YLIQ+pskblXgN9fnjS1BgEcuAfdInfXfGrkdXV406k9FiDi86eVCDBgJOyQ==", - "dev": true, - "dependencies": { - "@types/html-minifier-terser": "^5.0.0", - "html-minifier-terser": "^5.0.1", - "lodash": "^4.17.21", - "pretty-error": "^3.0.4", - "tapable": "^2.0.0" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "webpack": "^5.20.0" - } - }, - "node_modules/html-webpack-plugin/node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", - "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-middleware": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", - "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", - "dev": true, - "dependencies": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", - "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.14" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true - }, - "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-local": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", - "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/internal-ip": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", - "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", - "dev": true, - "dependencies": { - "default-gateway": "^4.2.0", - "ipaddr.js": "^1.9.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, - "node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-absolute-url": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", - "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "dependencies": { - "binary-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.7.0.tgz", - "integrity": "sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-nan": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", - "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", - "dev": true, - "dependencies": { - "is-path-inside": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", - "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", - "dev": true, - "dependencies": { - "path-is-inside": "^1.0.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", - "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/iso-url": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-0.4.7.tgz", - "integrity": "sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog==", - "engines": { - "node": ">=10" - } - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "dev": true, - "dependencies": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/js-sha256": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", - "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-text-sequence": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz", - "integrity": "sha1-py8hfcSvxGKf/1/rME3BvVGi89I=", - "dependencies": { - "delimit-stream": "0.1.0" - } - }, - "node_modules/json3": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", - "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", - "dev": true - }, - "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/killable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", - "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", - "dev": true - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash-es": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz", - "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==", - "dev": true - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", - "dev": true - }, - "node_modules/loglevel": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", - "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - }, - "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/loglevel" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/lower-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lru-cache/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "dev": true, - "dependencies": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.3.tgz", - "integrity": "sha512-cFOknTvng5vqnwOpDsZTWhNll6Jf8o2x+/diplafmxpuIymAjzoOolZG0VvQf3V2HgqzJNhnuKHYp2BqDgz8IQ==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "dev": true, - "dependencies": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "dev": true, - "dependencies": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true - }, - "node_modules/nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", - "dev": true, - "optional": true - }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/no-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", - "dev": true, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/node-releases": { - "version": "1.1.77", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", - "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/opn": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", - "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", - "dev": true, - "dependencies": { - "is-wsl": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/original": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", - "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", - "dev": true, - "dependencies": { - "url-parse": "^1.4.3" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-retry": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", - "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", - "dev": true, - "dependencies": { - "retry": "^0.12.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/param-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dev": true, - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/pascal-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dev": true, - "dependencies": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/portfinder/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", - "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", - "dev": true, - "dependencies": { - "postcss": "^7.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz", - "integrity": "sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ==", - "dev": true, - "dependencies": { - "icss-utils": "^4.1.1", - "postcss": "^7.0.16", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-modules-scope": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", - "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", - "dev": true, - "dependencies": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-modules-values": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", - "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", - "dev": true, - "dependencies": { - "icss-utils": "^4.0.0", - "postcss": "^7.0.6" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", - "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", - "dev": true - }, - "node_modules/pretty-error": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-3.0.4.tgz", - "integrity": "sha512-ytLFLfv1So4AO1UkoBF6GXQgJRaKbiSiGFICaOPNwQ3CMvBvXpLRubeQWyPGnsbV/t9ml9qto6IeCsho0aEvwQ==", - "dev": true, - "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^2.0.6" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true - }, - "node_modules/prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "dev": true, - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz", - "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==", - "dev": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dnd": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-2.6.0.tgz", - "integrity": "sha1-f6JWds+CfViokSk+PBq1naACVFo=", - "dev": true, - "dependencies": { - "disposables": "^1.0.1", - "dnd-core": "^2.6.0", - "hoist-non-react-statics": "^2.1.0", - "invariant": "^2.1.0", - "lodash": "^4.2.0", - "prop-types": "^15.5.10" - }, - "peerDependencies": { - "react": "*" - } - }, - "node_modules/react-dnd-html5-backend": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-4.0.5.tgz", - "integrity": "sha1-NmMqLVz6+KXUPFhmhfbdaWtQzN4=", - "dev": true, - "dependencies": { - "autobind-decorator": "^2.1.0", - "dnd-core": "^4.0.5", - "lodash": "^4.17.10", - "shallowequal": "^1.0.2" - }, - "peerDependencies": { - "react": ">= 16.3" - } - }, - "node_modules/react-dnd-html5-backend/node_modules/dnd-core": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-4.0.5.tgz", - "integrity": "sha1-O4PRONDV4mXHPsl43sXh7UQdxmU=", - "dev": true, - "dependencies": { - "asap": "^2.0.6", - "invariant": "^2.2.4", - "lodash": "^4.17.10", - "redux": "^4.0.0" - } - }, - "node_modules/react-dnd-html5-backend/node_modules/redux": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", - "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "symbol-observable": "^1.2.0" - } - }, - "node_modules/react-dnd-multi-backend": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/react-dnd-multi-backend/-/react-dnd-multi-backend-3.1.2.tgz", - "integrity": "sha512-6dzxVcK6T7WEHP9Q/IDVZkp3S7yVPg+6kzC3XzWDCcrJLyfTnlrz3G9KWGy52gdXxVVqBKS295LUbE9E79CnIw==", - "dev": true, - "dependencies": { - "dnd-multi-backend": "^3.1.0", - "prop-types": "^15.5.8", - "react": "*", - "react-dnd-html5-backend": "*", - "react-dnd-preview": "^3.0.7", - "react-dnd-touch-backend": "^0.3.13" - } - }, - "node_modules/react-dnd-preview": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/react-dnd-preview/-/react-dnd-preview-3.2.2.tgz", - "integrity": "sha512-IuuU9X4cX7b0xahnbOcj+Ec2VGBlPJHogZXUCtfp/JfVdvoW8M1M/jA8rx28BlIJ7BAc0YY24TxHk5Rm4faExQ==", - "dev": true, - "dependencies": { - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": "*", - "react-dnd": "< 9.0.0" - } - }, - "node_modules/react-dnd-touch-backend": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/react-dnd-touch-backend/-/react-dnd-touch-backend-0.3.21.tgz", - "integrity": "sha512-ZFnk+NbllEVKE2Puq8411+SZe2UFgfFPlz7EfFBhfZHsSx+rjRhX0JnMtqZWlGL5uDXl5uELzOsFXloi/sGKNw==", - "dev": true, - "dependencies": { - "invariant": "^2.2.2", - "react-dnd": "^2.5.4" - } - }, - "node_modules/react-dom": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", - "integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==", - "dev": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" - }, - "peerDependencies": { - "react": "^16.13.1" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/readdirp/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", - "dev": true, - "dependencies": { - "resolve": "^1.9.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/redux": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", - "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", - "dev": true, - "dependencies": { - "lodash": "^4.2.1", - "lodash-es": "^4.2.1", - "loose-envify": "^1.1.0", - "symbol-observable": "^1.0.3" - } - }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "node_modules/renderkid": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", - "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", - "dev": true, - "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^3.0.1" - } - }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", - "dev": true - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "dev": true, - "dependencies": { - "aproba": "^1.1.1" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "dependencies": { - "ret": "~0.1.10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", - "dev": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true - }, - "node_modules/selfsigned": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz", - "integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==", - "dev": true, - "dependencies": { - "node-forge": "^0.10.0" - } - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/send/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/send/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serialize-javascript": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", - "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", - "dev": true - }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", - "dev": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", - "dev": true - }, - "node_modules/simple-cbor": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/simple-cbor/-/simple-cbor-0.4.1.tgz", - "integrity": "sha512-rijcxtwx2b4Bje3sqeIqw5EeW7UlOIC4YfOdwqIKacpvRQ/D78bWg/4/0m5e0U91oKvlGh7LlJuZCu07ISCC7w==" - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sockjs": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", - "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", - "dev": true, - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^3.4.0", - "websocket-driver": "^0.7.4" - } - }, - "node_modules/sockjs-client": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.2.tgz", - "integrity": "sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ==", - "dev": true, - "dependencies": { - "debug": "^3.2.6", - "eventsource": "^1.0.7", - "faye-websocket": "^0.11.3", - "inherits": "^2.0.4", - "json3": "^3.3.3", - "url-parse": "^1.5.3" - } - }, - "node_modules/sockjs-client/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.20", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "node_modules/spdy-transport/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ssri": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", - "integrity": "sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g==", - "dev": true, - "dependencies": { - "figgy-pudding": "^3.5.1", - "minipass": "^3.1.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "dev": true, - "dependencies": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, - "node_modules/stream-browserify/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/style-loader": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.0.tgz", - "integrity": "sha512-szANub7ksJtQioJYtpbWwh1hUl99uK15n5HDlikeCRil/zYMZgSxucHddyF/4A3qJMUiAjPhFowrrQuNMA7jwQ==", - "dev": true, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.7.0.tgz", - "integrity": "sha512-Lfb0RiZcjRDXCC3OSHJpEkxJ9Qeqs6mp2v4jf2MHfy8vGERmVDuvjXdd/EnP5Deme5F2yBRBymKmKHCBg2echw==", - "dev": true, - "dependencies": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.2.2.tgz", - "integrity": "sha512-/CHMNswPMAwuD2kd++qys8UmBRmsshPSzHw4BlDwurPtK9YjeK93OV89YWkJulHk972cs07K/7Z92V6PNjWF8A==", - "dev": true, - "dependencies": { - "cacache": "^13.0.1", - "find-cache-dir": "^3.1.0", - "jest-worker": "^24.9.0", - "schema-utils": "^2.6.1", - "serialize-javascript": "^2.1.1", - "source-map": "^0.6.1", - "terser": "^4.4.2", - "webpack-sources": "^1.4.3" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/ts-loader": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-6.2.2.tgz", - "integrity": "sha512-HDo5kXZCBml3EUPcc7RlZOV/JGlLHwppTLEHb3SHnr5V7NXD4klMEkrhJe5wgRbaWsSXi+Y1SIBN/K9B6zWGWQ==", - "dev": true, - "dependencies": { - "chalk": "^2.3.0", - "enhanced-resolve": "^4.0.0", - "loader-utils": "^1.0.2", - "micromatch": "^4.0.0", - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8.6" - }, - "peerDependencies": { - "typescript": "*" - } - }, - "node_modules/tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", - "dev": true - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "3.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", - "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/union-value/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dev": true, - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", - "dev": true - }, - "node_modules/url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz", - "integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/util": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", - "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", - "which-typed-array": "^1.1.2" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", - "dev": true - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/watchpack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", - "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/webpack": { - "version": "5.56.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.56.1.tgz", - "integrity": "sha512-MRbTPooHJuSAfbx7Lh/qEMRUe/d0p4cRj2GPo/fq+4JUeR/+Q1EfLvS1lexslbMcJZyPXxxz/k/NzVepkA5upA==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.50", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.3", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.4", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.2.0", - "webpack-sources": "^3.2.0" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-cli": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.8.0.tgz", - "integrity": "sha512-+iBSWsX16uVna5aAYN6/wjhJy1q/GKk4KjKvfg90/6hykCTSgozbfz5iRgDTSJt/LgSbYxdBX3KBHeobIs+ZEw==", - "dev": true, - "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.0.4", - "@webpack-cli/info": "^1.3.0", - "@webpack-cli/serve": "^1.5.2", - "colorette": "^1.2.1", - "commander": "^7.0.0", - "execa": "^5.0.0", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "v8-compile-cache": "^2.2.0", - "webpack-merge": "^5.7.3" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "webpack": "4.x.x || 5.x.x" - }, - "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "@webpack-cli/migrate": { - "optional": true - }, - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/webpack-dev-middleware": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", - "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", - "dev": true, - "dependencies": { - "memory-fs": "^0.4.1", - "mime": "^2.4.4", - "mkdirp": "^0.5.1", - "range-parser": "^1.2.1", - "webpack-log": "^2.0.0" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/webpack-dev-middleware/node_modules/mime": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/webpack-dev-server": { - "version": "3.11.2", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz", - "integrity": "sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ==", - "dev": true, - "dependencies": { - "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.1.8", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "debug": "^4.1.1", - "del": "^4.1.1", - "express": "^4.17.1", - "html-entities": "^1.3.1", - "http-proxy-middleware": "0.19.1", - "import-local": "^2.0.0", - "internal-ip": "^4.3.0", - "ip": "^1.1.5", - "is-absolute-url": "^3.0.3", - "killable": "^1.0.1", - "loglevel": "^1.6.8", - "opn": "^5.5.0", - "p-retry": "^3.0.1", - "portfinder": "^1.0.26", - "schema-utils": "^1.0.0", - "selfsigned": "^1.10.8", - "semver": "^6.3.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.21", - "sockjs-client": "^1.5.0", - "spdy": "^4.0.2", - "strip-ansi": "^3.0.1", - "supports-color": "^6.1.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.2", - "webpack-log": "^2.0.0", - "ws": "^6.2.1", - "yargs": "^13.3.2" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 6.11.5" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dev": true, - "dependencies": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/webpack-dev-server/node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "dependencies": { - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/webpack-dev-server/node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, - "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/webpack-log": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", - "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", - "dev": true, - "dependencies": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "dependencies": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "node_modules/webpack/node_modules/enhanced-resolve": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", - "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/webpack/node_modules/jest-worker": { - "version": "27.2.4", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.4.tgz", - "integrity": "sha512-Zq9A2Pw59KkVjBBKD1i3iE2e22oSjXhUKKuAK1HGX8flGwkm6NMozyEYzKd41hXc64dbd/0eWFeEEuxqXyhM+g==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/webpack/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack/node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/webpack/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/webpack/node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack/node_modules/terser": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz", - "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", - "dev": true, - "dependencies": { - "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/webpack/node_modules/terser-webpack-plugin": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz", - "integrity": "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==", - "dev": true, - "dependencies": { - "jest-worker": "^27.0.6", - "p-limit": "^3.1.0", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/webpack/node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/webpack/node_modules/webpack-sources": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.1.tgz", - "integrity": "sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "node_modules/which-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", - "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/ws": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", - "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", - "dev": true, - "dependencies": { - "async-limiter": "~1.0.0" - } - }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/yargs/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@dfinity/agent": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-0.9.3.tgz", - "integrity": "sha512-vR0t5Uf+srbUHTdGunJxek3a4jCmBKU+B2yYEX0/aSGQfJmEf5X5snuNcnrIDOCfHeK7uxmOqs65BdI8Lhn4fg==", - "requires": { - "base64-arraybuffer": "^0.2.0", - "bignumber.js": "^9.0.0", - "borc": "^2.1.1", - "buffer": "^6.0.3", - "buffer-pipe": "^0.0.4", - "js-sha256": "0.9.0", - "simple-cbor": "^0.4.1" - } - }, - "@dfinity/candid": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-0.9.3.tgz", - "integrity": "sha512-VMovKFrExqN0mwcn1/aut4Ou4cA9IA2+QrBjV+Ro4eVCpVvGpVRqn4jizlV9QnJjcuEBG1yImIG5RKMdZ2ejQQ==", - "requires": { - "buffer": "^6.0.3", - "buffer-pipe": "^0.0.4" - } - }, - "@dfinity/principal": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-0.9.3.tgz", - "integrity": "sha512-DSL3b/gGm+f57+3XkFjlK4DigtKXe9MVO8UYXDQWkVIhy0UF1KYjRNGs6awc1GTQoOTxeQ8UTFwXuvnEvJ1hpQ==" - }, - "@discoveryjs/json-ext": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz", - "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==", - "dev": true - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@types/chess.js": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@types/chess.js/-/chess.js-0.10.1.tgz", - "integrity": "sha512-cuFMyrUYOWpKm5PRayvk22jLV3BOuWs7iJ7Q4PZJXMWoF7uhjWEojMS4GPk441gn4Ki9BHxbKsll7mrwJ3KT3g==", - "dev": true - }, - "@types/eslint": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.0.tgz", - "integrity": "sha512-07XlgzX0YJUn4iG1ocY4IX9DzKSmMGUs6ESKlxWhZRaa0fatIWaHWUVapcuGa8r5HFnTqzj+4OCjd5f7EZ/i/A==", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "0.0.50", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", - "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", - "dev": true - }, - "@types/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", - "dev": true, - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/html-minifier-terser": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", - "integrity": "sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true - }, - "@types/node": { - "version": "16.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.2.tgz", - "integrity": "sha512-zCclL4/rx+W5SQTzFs9wyvvyCwoK9QtBpratqz2IYJ3O8Umrn0m3nsTv0wQBk9sRGpvUe9CwPDrQFB10f1FIjQ==", - "dev": true - }, - "@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", - "dev": true - }, - "@types/react": { - "version": "16.9.36", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.36.tgz", - "integrity": "sha512-mGgUb/Rk/vGx4NCvquRuSH0GHBQKb1OqpGS9cT9lFxlTLHZgkksgI60TuIxubmn7JuCb+sENHhQciqa0npm0AQ==", - "dev": true, - "requires": { - "@types/prop-types": "*", - "csstype": "^2.2.0" - } - }, - "@types/react-dom": { - "version": "16.9.8", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.8.tgz", - "integrity": "sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==", - "dev": true, - "requires": { - "@types/react": "*" - } - }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webpack-cli/configtest": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.4.tgz", - "integrity": "sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ==", - "dev": true, - "requires": {} - }, - "@webpack-cli/info": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.3.0.tgz", - "integrity": "sha512-ASiVB3t9LOKHs5DyVUcxpraBXDOKubYu/ihHhU+t1UPpxsivg6Od2E2qU4gJCekfEddzRBzHhzA/Acyw/mlK/w==", - "dev": true, - "requires": { - "envinfo": "^7.7.3" - } - }, - "@webpack-cli/serve": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.2.tgz", - "integrity": "sha512-vgJ5OLWadI8aKjDlOH3rb+dYyPd2GTZuQC/Tihjct6F9GpXGZINo3Y/IVuZVTM1eDQB+/AOsjPUWH/WySDaXvw==", - "dev": true, - "requires": {} - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", - "dev": true - }, - "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "requires": {} - }, - "aggregate-error": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", - "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "dev": true, - "requires": {} - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, - "ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", - "dev": true - }, - "ansi-html": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, - "assert": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", - "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", - "dev": true, - "requires": { - "es6-object-assign": "^1.1.0", - "is-nan": "^1.2.1", - "object-is": "^1.0.1", - "util": "^0.12.0" - } - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "autobind-decorator": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/autobind-decorator/-/autobind-decorator-2.4.0.tgz", - "integrity": "sha512-OGYhWUO72V6DafbF8PM8rm3EPbfuyMZcJhtm5/n26IDwO18pohE4eNazLoCGhPiXOCD0gEGmrbU3849QvM8bbw==", - "dev": true - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - } - } - }, - "base64-arraybuffer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz", - "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==" - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "bignumber.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", - "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dev": true, - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dev": true, - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "borc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/borc/-/borc-2.1.2.tgz", - "integrity": "sha512-Sy9eoUi4OiKzq7VovMn246iTo17kzuyHJKomCfpWMlI6RpfN1gk95w7d7gH264nApVLg0HZfcpz62/g4VH1Y4w==", - "requires": { - "bignumber.js": "^9.0.0", - "buffer": "^5.5.0", - "commander": "^2.15.0", - "ieee754": "^1.1.13", - "iso-url": "~0.4.7", - "json-text-sequence": "~0.1.0", - "readable-stream": "^3.6.0" - }, - "dependencies": { - "buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz", - "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001264", - "electron-to-chromium": "^1.3.857", - "escalade": "^3.1.1", - "node-releases": "^1.1.77", - "picocolors": "^0.2.1" - } - }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true - }, - "buffer-pipe": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/buffer-pipe/-/buffer-pipe-0.0.4.tgz", - "integrity": "sha512-8cHio1V6wgX+LIX6+af4tCn0+Ljl2vQd9JZdZ8vDJZdDf8x5p2DneKaq1dWxSswJG+sK4Inok9aqoqILG5kQVQ==", - "requires": { - "safe-buffer": "^5.1.2" - } - }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true - }, - "cacache": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", - "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", - "dev": true, - "requires": { - "chownr": "^1.1.2", - "figgy-pudding": "^3.5.1", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.2", - "infer-owner": "^1.0.4", - "lru-cache": "^5.1.1", - "minipass": "^3.0.0", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "p-map": "^3.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^2.7.1", - "ssri": "^7.0.0", - "unique-filename": "^1.1.1" - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dev": true, - "requires": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001264", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001264.tgz", - "integrity": "sha512-Ftfqqfcs/ePiUmyaySsQ4PUsdcYyXG2rfoBVsk3iY1ahHaJEw65vfb7Suzqm+cEkwwPIv/XWkg27iCpRavH4zA==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "chess.js": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/chess.js/-/chess.js-0.10.3.tgz", - "integrity": "sha512-i51JgVM0ksFMbLJYKoDpfrcFxJHq/XQQx8NltCdfMyDv7vpU5JVzsZz1EOw7nA27eGA5t8tSxodAN+Wc704BoQ==", - "dev": true - }, - "chessboardjsx": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chessboardjsx/-/chessboardjsx-2.4.2.tgz", - "integrity": "sha512-nVPRmE/peE5e+Pscz0DJVWPli2Q7fg6d8YQfqMfr21oIzOwswX5kUF+Fl1ZthKk6KD5qey0YJ0v+LTLmxCTtRQ==", - "dev": true, - "requires": { - "deep-diff": "1.0.1", - "lodash.isequal": "4.5.0", - "react-dnd": "2.6.0", - "react-dnd-html5-backend": "4.0.5", - "react-dnd-multi-backend": "3.1.2" - } - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "dependencies": { - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "chrome-trace-event": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", - "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "clean-css": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", - "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", - "dev": true, - "requires": { - "source-map": "~0.6.0" - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "requires": { - "mime-db": ">= 1.43.0 < 2" - } - }, - "compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", - "dev": true - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "requires": { - "safe-buffer": "5.2.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "copy-webpack-plugin": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.0.1.tgz", - "integrity": "sha512-14gHKKdYIxF84jCEgPgYXCPpldbwpxxLbCmA7LReY7gvbaT555DgeBWBgBZM116tv/fO6RRJrsivBqRyRlukhw==", - "dev": true, - "requires": { - "fast-glob": "^3.2.5", - "glob-parent": "^6.0.0", - "globby": "^11.0.3", - "normalize-path": "^3.0.0", - "p-limit": "^3.1.0", - "schema-utils": "^3.0.0", - "serialize-javascript": "^6.0.0" - }, - "dependencies": { - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - } - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "css-loader": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", - "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "cssesc": "^3.0.0", - "icss-utils": "^4.1.1", - "loader-utils": "^1.2.3", - "normalize-path": "^3.0.0", - "postcss": "^7.0.32", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.2.0", - "postcss-modules-values": "^3.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^2.7.0", - "semver": "^6.3.0" - } - }, - "css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" - } - }, - "css-what": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", - "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", - "dev": true - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true - }, - "csstype": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.10.tgz", - "integrity": "sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==", - "dev": true - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true - }, - "deep-diff": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-1.0.1.tgz", - "integrity": "sha512-Vkn+eQK6H63gObVi3KWmPMb4RdzMpfdp5t0HNppq8Oc7xbwmvBy5BIHsEYSXOiS9Lr/W+3lF020zyPTsGfea4g==", - "dev": true - }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, - "default-gateway": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", - "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "ip-regex": "^2.1.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "del": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", - "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - }, - "dependencies": { - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true - } - } - }, - "delimit-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz", - "integrity": "sha1-m4MZR3wOX4rrPONXrjBfwl6hzSs=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true - }, - "detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "disposables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/disposables/-/disposables-1.0.2.tgz", - "integrity": "sha1-NsamdEdfVaLWkTVnpgFETkh7S24=", - "dev": true - }, - "dnd-core": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-2.6.0.tgz", - "integrity": "sha1-ErrWbVh0LG5ffPKUP7aFlED4CcQ=", - "dev": true, - "requires": { - "asap": "^2.0.6", - "invariant": "^2.0.0", - "lodash": "^4.2.0", - "redux": "^3.7.1" - } - }, - "dnd-multi-backend": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/dnd-multi-backend/-/dnd-multi-backend-3.2.1.tgz", - "integrity": "sha512-A783JbrONpeufxX+jDMHOxR2AWh+gFv5Z/lLpDB3vdON6t0bb2fHSh8fKH2h8gOLRAJGD08m9xYXAJIWreTI5A==", - "dev": true - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true - }, - "dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "dev": true, - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, - "requires": { - "buffer-indexof": "^1.0.0" - } - }, - "dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "requires": { - "utila": "~0.4" - } - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - }, - "domhandler": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", - "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", - "dev": true, - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.858", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.858.tgz", - "integrity": "sha512-EZ0dTXxTX+rgZC8YDVqKNMyp1Ty3hi1LyQwVBBioV7iiYYjFakokumRsIUhNz5ho+QlNKf7iNY5KLdpdH3yqBw==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", - "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" - }, - "dependencies": { - "memory-fs": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", - "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - } - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true - }, - "envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", - "dev": true - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, - "requires": { - "prr": "~1.0.1" - } - }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-module-lexer": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.2.tgz", - "integrity": "sha512-YkAGWqxZq2B4FxQ5y687UwywDwvLQhIMCZ+SDU7ZW729SDHOEI6wVFXwTRecz+yiwJzCsVwC6V7bxyNbZSB1rg==", - "dev": true - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-object-assign": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true - }, - "eventsource": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", - "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", - "dev": true, - "requires": { - "original": "^1.0.0" - } - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "dev": true, - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - } - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - } - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", - "dev": true - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - } - } - }, - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "follow-redirects": { - "version": "1.14.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", - "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hoist-non-react-statics": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", - "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==", - "dev": true - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "html-entities": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", - "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==", - "dev": true - }, - "html-minifier-terser": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", - "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", - "dev": true, - "requires": { - "camel-case": "^4.1.1", - "clean-css": "^4.2.3", - "commander": "^4.1.1", - "he": "^1.2.0", - "param-case": "^3.0.3", - "relateurl": "^0.2.7", - "terser": "^4.6.3" - }, - "dependencies": { - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true - } - } - }, - "html-webpack-plugin": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.3.2.tgz", - "integrity": "sha512-HvB33boVNCz2lTyBsSiMffsJ+m0YLIQ+pskblXgN9fnjS1BgEcuAfdInfXfGrkdXV406k9FiDi86eVCDBgJOyQ==", - "dev": true, - "requires": { - "@types/html-minifier-terser": "^5.0.0", - "html-minifier-terser": "^5.0.1", - "lodash": "^4.17.21", - "pretty-error": "^3.0.4", - "tapable": "^2.0.0" - }, - "dependencies": { - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true - } - } - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - } - } - }, - "http-parser-js": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", - "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", - "dev": true - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-proxy-middleware": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", - "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", - "dev": true, - "requires": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" - }, - "dependencies": { - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "icss-utils": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", - "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", - "dev": true, - "requires": { - "postcss": "^7.0.14" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true - }, - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "import-local": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", - "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, - "infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "internal-ip": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", - "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", - "dev": true, - "requires": { - "default-gateway": "^4.2.0", - "ipaddr.js": "^1.9.0" - } - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true - }, - "is-absolute-url": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", - "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", - "dev": true - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true - }, - "is-core-module": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.7.0.tgz", - "integrity": "sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-nan": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", - "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - } - }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true - }, - "is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", - "dev": true, - "requires": { - "is-path-inside": "^2.1.0" - } - }, - "is-path-inside": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", - "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", - "dev": true, - "requires": { - "path-is-inside": "^1.0.2" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", - "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", - "has-tostringtag": "^1.0.0" - } - }, - "is-weakref": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0" - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "iso-url": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-0.4.7.tgz", - "integrity": "sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog==" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "dev": true, - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - } - }, - "js-sha256": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", - "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-text-sequence": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz", - "integrity": "sha1-py8hfcSvxGKf/1/rME3BvVGi89I=", - "requires": { - "delimit-stream": "0.1.0" - } - }, - "json3": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", - "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", - "dev": true - }, - "json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "killable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", - "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", - "dev": true - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true - }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "lodash-es": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz", - "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==", - "dev": true - }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", - "dev": true - }, - "loglevel": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", - "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "requires": { - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - }, - "dependencies": { - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - } - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-pipeline": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.3.tgz", - "integrity": "sha512-cFOknTvng5vqnwOpDsZTWhNll6Jf8o2x+/diplafmxpuIymAjzoOolZG0VvQf3V2HgqzJNhnuKHYp2BqDgz8IQ==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "dev": true, - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true - }, - "nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "requires": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", - "dev": true - }, - "node-releases": { - "version": "1.1.77", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", - "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "dev": true - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "opn": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", - "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", - "dev": true, - "requires": { - "is-wsl": "^1.1.0" - } - }, - "original": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", - "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", - "dev": true, - "requires": { - "url-parse": "^1.4.3" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-retry": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", - "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", - "dev": true, - "requires": { - "retry": "^0.12.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, - "requires": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true - }, - "pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dev": true, - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dev": true, - "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "postcss-modules-extract-imports": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", - "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", - "dev": true, - "requires": { - "postcss": "^7.0.5" - } - }, - "postcss-modules-local-by-default": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz", - "integrity": "sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ==", - "dev": true, - "requires": { - "icss-utils": "^4.1.1", - "postcss": "^7.0.16", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.0" - } - }, - "postcss-modules-scope": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", - "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", - "dev": true, - "requires": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0" - } - }, - "postcss-modules-values": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", - "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", - "dev": true, - "requires": { - "icss-utils": "^4.0.0", - "postcss": "^7.0.6" - } - }, - "postcss-selector-parser": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", - "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", - "dev": true - }, - "pretty-error": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-3.0.4.tgz", - "integrity": "sha512-ytLFLfv1So4AO1UkoBF6GXQgJRaKbiSiGFICaOPNwQ3CMvBvXpLRubeQWyPGnsbV/t9ml9qto6IeCsho0aEvwQ==", - "dev": true, - "requires": { - "lodash": "^4.17.20", - "renderkid": "^2.0.6" - } - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true - }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dev": true, - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true - } - } - }, - "react": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz", - "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - } - }, - "react-dnd": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-2.6.0.tgz", - "integrity": "sha1-f6JWds+CfViokSk+PBq1naACVFo=", - "dev": true, - "requires": { - "disposables": "^1.0.1", - "dnd-core": "^2.6.0", - "hoist-non-react-statics": "^2.1.0", - "invariant": "^2.1.0", - "lodash": "^4.2.0", - "prop-types": "^15.5.10" - } - }, - "react-dnd-html5-backend": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-4.0.5.tgz", - "integrity": "sha1-NmMqLVz6+KXUPFhmhfbdaWtQzN4=", - "dev": true, - "requires": { - "autobind-decorator": "^2.1.0", - "dnd-core": "^4.0.5", - "lodash": "^4.17.10", - "shallowequal": "^1.0.2" - }, - "dependencies": { - "dnd-core": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-4.0.5.tgz", - "integrity": "sha1-O4PRONDV4mXHPsl43sXh7UQdxmU=", - "dev": true, - "requires": { - "asap": "^2.0.6", - "invariant": "^2.2.4", - "lodash": "^4.17.10", - "redux": "^4.0.0" - } - }, - "redux": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", - "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "symbol-observable": "^1.2.0" - } - } - } - }, - "react-dnd-multi-backend": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/react-dnd-multi-backend/-/react-dnd-multi-backend-3.1.2.tgz", - "integrity": "sha512-6dzxVcK6T7WEHP9Q/IDVZkp3S7yVPg+6kzC3XzWDCcrJLyfTnlrz3G9KWGy52gdXxVVqBKS295LUbE9E79CnIw==", - "dev": true, - "requires": { - "dnd-multi-backend": "^3.1.0", - "prop-types": "^15.5.8", - "react": "*", - "react-dnd-html5-backend": "*", - "react-dnd-preview": "^3.0.7", - "react-dnd-touch-backend": "^0.3.13" - } - }, - "react-dnd-preview": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/react-dnd-preview/-/react-dnd-preview-3.2.2.tgz", - "integrity": "sha512-IuuU9X4cX7b0xahnbOcj+Ec2VGBlPJHogZXUCtfp/JfVdvoW8M1M/jA8rx28BlIJ7BAc0YY24TxHk5Rm4faExQ==", - "dev": true, - "requires": { - "prop-types": "^15.6.2" - } - }, - "react-dnd-touch-backend": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/react-dnd-touch-backend/-/react-dnd-touch-backend-0.3.21.tgz", - "integrity": "sha512-ZFnk+NbllEVKE2Puq8411+SZe2UFgfFPlz7EfFBhfZHsSx+rjRhX0JnMtqZWlGL5uDXl5uELzOsFXloi/sGKNw==", - "dev": true, - "requires": { - "invariant": "^2.2.2", - "react-dnd": "^2.5.4" - } - }, - "react-dom": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", - "integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, - "rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", - "dev": true, - "requires": { - "resolve": "^1.9.0" - } - }, - "redux": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", - "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", - "dev": true, - "requires": { - "lodash": "^4.2.1", - "lodash-es": "^4.2.1", - "loose-envify": "^1.1.0", - "symbol-observable": "^1.0.3" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "renderkid": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", - "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", - "dev": true, - "requires": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^3.0.1" - } - }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "dev": true, - "requires": { - "aproba": "^1.1.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true - }, - "selfsigned": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz", - "integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==", - "dev": true, - "requires": { - "node-forge": "^0.10.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - } - } - }, - "serialize-javascript": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", - "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", - "dev": true - }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - } - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - } - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, - "shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", - "dev": true - }, - "simple-cbor": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/simple-cbor/-/simple-cbor-0.4.1.tgz", - "integrity": "sha512-rijcxtwx2b4Bje3sqeIqw5EeW7UlOIC4YfOdwqIKacpvRQ/D78bWg/4/0m5e0U91oKvlGh7LlJuZCu07ISCC7w==" - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "sockjs": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", - "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", - "dev": true, - "requires": { - "faye-websocket": "^0.11.3", - "uuid": "^3.4.0", - "websocket-driver": "^0.7.4" - } - }, - "sockjs-client": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.2.tgz", - "integrity": "sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ==", - "dev": true, - "requires": { - "debug": "^3.2.6", - "eventsource": "^1.0.7", - "faye-websocket": "^0.11.3", - "inherits": "^2.0.4", - "json3": "^3.3.3", - "url-parse": "^1.5.3" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.20", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - } - }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "ssri": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", - "integrity": "sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g==", - "dev": true, - "requires": { - "figgy-pudding": "^3.5.1", - "minipass": "^3.1.1" - } - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - }, - "stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "dev": true, - "requires": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "style-loader": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.0.tgz", - "integrity": "sha512-szANub7ksJtQioJYtpbWwh1hUl99uK15n5HDlikeCRil/zYMZgSxucHddyF/4A3qJMUiAjPhFowrrQuNMA7jwQ==", - "dev": true, - "requires": {} - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true - }, - "terser": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.7.0.tgz", - "integrity": "sha512-Lfb0RiZcjRDXCC3OSHJpEkxJ9Qeqs6mp2v4jf2MHfy8vGERmVDuvjXdd/EnP5Deme5F2yBRBymKmKHCBg2echw==", - "dev": true, - "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - } - }, - "terser-webpack-plugin": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.2.2.tgz", - "integrity": "sha512-/CHMNswPMAwuD2kd++qys8UmBRmsshPSzHw4BlDwurPtK9YjeK93OV89YWkJulHk972cs07K/7Z92V6PNjWF8A==", - "dev": true, - "requires": { - "cacache": "^13.0.1", - "find-cache-dir": "^3.1.0", - "jest-worker": "^24.9.0", - "schema-utils": "^2.6.1", - "serialize-javascript": "^2.1.1", - "source-map": "^0.6.1", - "terser": "^4.4.2", - "webpack-sources": "^1.4.3" - } - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true - }, - "ts-loader": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-6.2.2.tgz", - "integrity": "sha512-HDo5kXZCBml3EUPcc7RlZOV/JGlLHwppTLEHb3SHnr5V7NXD4klMEkrhJe5wgRbaWsSXi+Y1SIBN/K9B6zWGWQ==", - "dev": true, - "requires": { - "chalk": "^2.3.0", - "enhanced-resolve": "^4.0.0", - "loader-utils": "^1.0.2", - "micromatch": "^4.0.0", - "semver": "^6.0.0" - } - }, - "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typescript": { - "version": "3.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", - "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==", - "dev": true - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - } - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dev": true, - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } - } - }, - "url-parse": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz", - "integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "util": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", - "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", - "which-typed-array": "^1.1.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", - "dev": true - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "watchpack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", - "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", - "dev": true, - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "webpack": { - "version": "5.56.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.56.1.tgz", - "integrity": "sha512-MRbTPooHJuSAfbx7Lh/qEMRUe/d0p4cRj2GPo/fq+4JUeR/+Q1EfLvS1lexslbMcJZyPXxxz/k/NzVepkA5upA==", - "dev": true, - "requires": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.50", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.3", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.4", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.2.0", - "webpack-sources": "^3.2.0" - }, - "dependencies": { - "enhanced-resolve": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", - "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-worker": { - "version": "27.2.4", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.4.tgz", - "integrity": "sha512-Zq9A2Pw59KkVjBBKD1i3iE2e22oSjXhUKKuAK1HGX8flGwkm6NMozyEYzKd41hXc64dbd/0eWFeEEuxqXyhM+g==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true - }, - "terser": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz", - "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", - "dev": true, - "requires": { - "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } - } - }, - "terser-webpack-plugin": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz", - "integrity": "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==", - "dev": true, - "requires": { - "jest-worker": "^27.0.6", - "p-limit": "^3.1.0", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - } - }, - "webpack-sources": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.1.tgz", - "integrity": "sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==", - "dev": true - } - } - }, - "webpack-cli": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.8.0.tgz", - "integrity": "sha512-+iBSWsX16uVna5aAYN6/wjhJy1q/GKk4KjKvfg90/6hykCTSgozbfz5iRgDTSJt/LgSbYxdBX3KBHeobIs+ZEw==", - "dev": true, - "requires": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.0.4", - "@webpack-cli/info": "^1.3.0", - "@webpack-cli/serve": "^1.5.2", - "colorette": "^1.2.1", - "commander": "^7.0.0", - "execa": "^5.0.0", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "v8-compile-cache": "^2.2.0", - "webpack-merge": "^5.7.3" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true - } - } - }, - "webpack-dev-middleware": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", - "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", - "dev": true, - "requires": { - "memory-fs": "^0.4.1", - "mime": "^2.4.4", - "mkdirp": "^0.5.1", - "range-parser": "^1.2.1", - "webpack-log": "^2.0.0" - }, - "dependencies": { - "mime": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", - "dev": true - } - } - }, - "webpack-dev-server": { - "version": "3.11.2", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz", - "integrity": "sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ==", - "dev": true, - "requires": { - "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.1.8", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "debug": "^4.1.1", - "del": "^4.1.1", - "express": "^4.17.1", - "html-entities": "^1.3.1", - "http-proxy-middleware": "0.19.1", - "import-local": "^2.0.0", - "internal-ip": "^4.3.0", - "ip": "^1.1.5", - "is-absolute-url": "^3.0.3", - "killable": "^1.0.1", - "loglevel": "^1.6.8", - "opn": "^5.5.0", - "p-retry": "^3.0.1", - "portfinder": "^1.0.26", - "schema-utils": "^1.0.0", - "selfsigned": "^1.10.8", - "semver": "^6.3.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.21", - "sockjs-client": "^1.5.0", - "spdy": "^4.0.2", - "strip-ansi": "^3.0.1", - "supports-color": "^6.1.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.2", - "webpack-log": "^2.0.0", - "ws": "^6.2.1", - "yargs": "^13.3.2" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dev": true, - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, - "webpack-log": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", - "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", - "dev": true, - "requires": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" - } - }, - "webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dev": true, - "requires": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - } - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "requires": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "which-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", - "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.7" - } - }, - "wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "ws": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", - "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - } -} diff --git a/examples/chess/package.json b/examples/chess/package.json deleted file mode 100644 index 884c44bdc..000000000 --- a/examples/chess/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "new_project", - "version": "0.1.0", - "description": "", - "keywords": [], - "scripts": { - "build": "webpack", - "start": "webpack serve --mode development --env development", - "copy:types": "rsync -avr .dfx/$(echo ${DFX_NETWORK:-'**'})/canisters/** --exclude='assets/' --exclude='idl/' --exclude='*.wasm' --delete src/declarations" - }, - "devDependencies": { - "@types/chess.js": "^0.10.1", - "@types/react": "^16.9.23", - "@types/react-dom": "^16.9.5", - "assert": "^2.0.0", - "buffer": "^6.0.3", - "chess.js": "0.10.3", - "chessboardjsx": "2.4.2", - "copy-webpack-plugin": "^9.0.1", - "css-loader": "^3.6.0", - "html-webpack-plugin": "^5.3.2", - "process": "^0.11.10", - "react": "^16.13.0", - "react-dom": "^16.13.0", - "stream-browserify": "^3.0.0", - "style-loader": "^3.1.0", - "terser-webpack-plugin": "2.2.2", - "ts-loader": "^6.2.1", - "typescript": "^3.8.3", - "webpack": "^5.45.1", - "webpack-cli": "^4.7.2", - "webpack-dev-server": "^3.11.2" - }, - "dependencies": { - "@dfinity/agent": "^0.9.2", - "@dfinity/candid": "^0.9.2", - "@dfinity/principal": "^0.9.2" - } -} diff --git a/examples/chess/src/chess_rs_assets/chess.tsx b/examples/chess/src/chess_rs_assets/chess.tsx deleted file mode 100644 index 839a8c666..000000000 --- a/examples/chess/src/chess_rs_assets/chess.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React, { Component } from "react"; -import HumanVsActor from "./integration"; - -class Chess extends Component { - render() { - return ( -
-
- -
-
- ); - } -} - -export default Chess; - -const boardsContainer = { - display: "flex", - justifyContent: "space-around", - alignItems: "center", - flexWrap: undefined, //"wrap", - width: "100vw", - marginTop: 30, - marginBottom: 50 -}; diff --git a/examples/chess/src/chess_rs_assets/index.css b/examples/chess/src/chess_rs_assets/index.css deleted file mode 100644 index 22f8f1897..000000000 --- a/examples/chess/src/chess_rs_assets/index.css +++ /dev/null @@ -1,5 +0,0 @@ -body { - margin: 0; - padding: 0; - font-family: sans-serif; -} diff --git a/examples/chess/src/chess_rs_assets/index.html b/examples/chess/src/chess_rs_assets/index.html deleted file mode 100644 index 0f8d37eaa..000000000 --- a/examples/chess/src/chess_rs_assets/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Chess App - - -
- - \ No newline at end of file diff --git a/examples/chess/src/chess_rs_assets/index.tsx b/examples/chess/src/chess_rs_assets/index.tsx deleted file mode 100644 index 8208bf2b6..000000000 --- a/examples/chess/src/chess_rs_assets/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import "./index.css"; -import Chess from "./chess"; - -ReactDOM.render(, document.getElementById("app")); diff --git a/examples/chess/src/chess_rs_assets/integration.tsx b/examples/chess/src/chess_rs_assets/integration.tsx deleted file mode 100644 index 2d4d474ec..000000000 --- a/examples/chess/src/chess_rs_assets/integration.tsx +++ /dev/null @@ -1,281 +0,0 @@ -import React, { ChangeEvent, Component } from "react"; -import PropTypes from "prop-types"; -import Chess, { ChessInstance } from "chess.js"; // import Chess from "chess.js"(default) if recieving an error about new Chess() not being a constructor -import { chess_rs as chessActor } from "../declarations/chess_rs"; -import Chessboard from "chessboardjsx"; - -type Props = { children: (...args: any[]) => any }; -interface State { - name: string, - pieceSquare: any, - history: any, - squareStyles: any, - fen: string, - square: string, - dropSquareStyle: any, - disabled: boolean, -} - -class HumanVsActor extends Component { - static propTypes = { children: PropTypes.func }; - - private game: ChessInstance | undefined = undefined; - - state = { - name: "default", - disabled: false, - - fen: "start", - // square styles for active drop square - dropSquareStyle: {}, - // custom square styles - squareStyles: {}, - // square with the currently clicked piece - pieceSquare: "", - // currently clicked square - square: "", - // array of past game moves - history: [] - }; - - componentDidMount() { - this.game = new (Chess as any)(); - this.reload(); - } - - // keep clicked square style and remove hint squares - removeHighlightSquare = () => { - this.setState(({ pieceSquare, history }) => ({ - squareStyles: squareStyling({ pieceSquare, history }) - })); - }; - - // show possible moves - highlightSquare = (sourceSquare: any, squaresToHighlight: any) => { - const highlightStyles = [sourceSquare, ...squaresToHighlight].reduce( - (a, c) => { - return { - ...a, - ...{ - [c]: { - background: - "radial-gradient(circle, #fffc00 36%, transparent 40%)", - borderRadius: "50%" - } - }, - ...squareStyling({ - history: this.state.history, - pieceSquare: this.state.pieceSquare - }) - }; - }, - {} - ); - - this.setState(({ squareStyles }) => ({ - squareStyles: { ...squareStyles, ...highlightStyles } - })); - }; - - doMove = ({ sourceSquare, targetSquare }: any) => { - // see if the move is legal - let move = this.game!.move({ - from: sourceSquare, - to: targetSquare, - promotion: "q" // always promote to a queen for example simplicity - }); - - // illegal move - if (move === null) return; - - // Block any moves until we save on the canister. - this.setState(({}) => ({ - disabled: true, - })); - - let uci = move.from + move.to + (move.promotion || ""); - - chessActor.move(this.state.name, uci).then((valid: boolean) => { - if (!valid) { - this.setState(({}) => ({ disabled: false })); - return; - } - - chessActor.getFen(this.state.name).then(([fen]) => { - this.setState(({ history, pieceSquare }) => ({ - fen: fen ? ('' + fen) : "start", - history: this.game!.history({ verbose: true }), - squareStyles: squareStyling({ pieceSquare, history }) - })); - }); - }); - }; - - onDrop = ({ sourceSquare, targetSquare }: any) => { - this.doMove({ sourceSquare, targetSquare }); - }; - - onMouseOverSquare = (square: any) => { - // get list of possible moves for this square - let moves = this.game!.moves({ - square: square, - verbose: true - }); - - // exit if there are no moves available for this square - if (moves.length === 0) return; - - let squaresToHighlight = []; - for (var i = 0; i < moves.length; i++) { - squaresToHighlight.push(moves[i].to); - } - - this.highlightSquare(square, squaresToHighlight); - }; - - onMouseOutSquare = (square: any) => this.removeHighlightSquare(); - - // central squares get diff dropSquareStyles - onDragOverSquare = (square: any) => { - this.setState({ - dropSquareStyle: - square === "e4" || square === "d4" || square === "e5" || square === "d5" - ? { backgroundColor: "cornFlowerBlue" } - : { boxShadow: "inset 0 0 1px 4px rgb(255, 255, 0)" } - }); - }; - - onSquareClick = (square: any) => { - this.setState(({ history }) => ({ - squareStyles: squareStyling({ pieceSquare: square, history }), - pieceSquare: square - })); - - this.doMove({ sourceSquare: this.state.pieceSquare as any, targetSquare: square }); - }; - - onSquareRightClick = (square: any) => - this.setState({ - squareStyles: { [square]: { backgroundColor: "deepPink" } } - }); - - reload = () => { - this.setState({ disabled: true }); - - chessActor.getFen(this.state.name).then(([fen]) => { - this.game!.load(fen || "start"); - this.setState({ - disabled: false, - fen: fen ? ('' + fen) : "start", - history: this.game!.history({ verbose: true }), - }); - }); - }; - - ai = () => { - this.setState({ disabled: true }); - chessActor.aiMove(this.state.name).then(() => this.reload()); - }; - - reset = () => { - this.setState({ disabled: true }); - chessActor.new(this.state.name, true).then(() => this.reload()); - }; - - changeName = (ev: ChangeEvent) => { - this.setState({ disabled: true, name: (ev.target as any).value }); - this.reload(); - }; - - render() { - const { fen, dropSquareStyle, squareStyles } = this.state; - - return this.props.children({ - squareStyles, - position: fen, - ai: this.ai, - name: this.state.name, - changeName: this.changeName, - reload: this.reload, - reset: this.reset, - onMouseOverSquare: this.onMouseOverSquare, - onMouseOutSquare: this.onMouseOutSquare, - onDrop: this.onDrop, - dropSquareStyle, - onDragOverSquare: this.onDragOverSquare, - onSquareClick: this.onSquareClick, - onSquareRightClick: this.onSquareRightClick - }); - } -} - -export default function WithMoveValidation() { - return ( -
- - {({ - position, - ai, - name, - changeName, - reset, - reload, - onDrop, - onMouseOverSquare, - onMouseOutSquare, - squareStyles, - disabled, - dropSquareStyle, - onDragOverSquare, - onSquareClick, - onSquareRightClick - }) => ( -
-
Game:
- - - - - -
- )} -
-
- ); -} - -const squareStyling = ({ pieceSquare, history }: any) => { - const sourceSquare = history.length && history[history.length - 1].from; - const targetSquare = history.length && history[history.length - 1].to; - - return { - [pieceSquare]: { backgroundColor: "rgba(255, 255, 0, 0.4)" }, - ...(history.length && { - [sourceSquare]: { - backgroundColor: "rgba(255, 255, 0, 0.4)" - } - }), - ...(history.length && { - [targetSquare]: { - backgroundColor: "rgba(255, 255, 0, 0.4)" - } - }) - }; -}; diff --git a/examples/chess/tests/basic.bats b/examples/chess/tests/basic.bats index 9adc19f0c..36706ff2b 100644 --- a/examples/chess/tests/basic.bats +++ b/examples/chess/tests/basic.bats @@ -1,8 +1,6 @@ # Executed before each test. setup() { cd examples/chess - # Make sure the directory is clean. - npm install dfx start --clean --background } diff --git a/examples/chess/tsconfig.json b/examples/chess/tsconfig.json deleted file mode 100644 index b3e6aa385..000000000 --- a/examples/chess/tsconfig.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "compilerOptions": { - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "es2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ - // "lib": [], /* Specify library files to be included in the compilation. */ - "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - // "declaration": true, /* Generates corresponding '.d.ts' file. */ - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - // "outDir": "./", /* Redirect output structure to the directory. */ - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - - /* Module Resolution Options */ - // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - "paths": { - "ic:canisters/*": [ - "canisters/*/main.js" - ], - "idl:canisters/*": [ - "canisters/*/main.did.js" - ] - }, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - - /* Experimental Options */ - // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - - /* Advanced Options */ - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ - } -} diff --git a/examples/chess/webpack.config.js b/examples/chess/webpack.config.js deleted file mode 100644 index 604f6ffbc..000000000 --- a/examples/chess/webpack.config.js +++ /dev/null @@ -1,110 +0,0 @@ -const path = require("path"); -const webpack = require("webpack"); -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const TerserPlugin = require("terser-webpack-plugin"); -const CopyPlugin = require("copy-webpack-plugin"); - -let localCanisters, prodCanisters, canisters; - -try { - localCanisters = require(path.resolve(".dfx", "local", "canister_ids.json")); -} catch (error) { - console.log("No local canister_ids.json found. Continuing production"); -} - -function initCanisterIds() { - try { - prodCanisters = require(path.resolve("canister_ids.json")); - } catch (error) { - console.log("No production canister_ids.json found. Continuing with local"); - } - - const network = - process.env.DFX_NETWORK || - (process.env.NODE_ENV === "production" ? "ic" : "local"); - - canisters = network === "local" ? localCanisters : prodCanisters; - - for (const canister in canisters) { - process.env[canister.toUpperCase() + "_CANISTER_ID"] = - canisters[canister][network]; - } -} -initCanisterIds(); - -const isDevelopment = process.env.NODE_ENV !== "production"; -const asset_entry = path.join( - "src", - "chess_rs_assets", - "index.tsx" -); - -module.exports = { - target: "web", - mode: isDevelopment ? "development" : "production", - entry: { - // The frontend.entrypoint points to the HTML file for this build, so we need - // to replace the extension to `.js`. - index: path.join(__dirname, asset_entry), - }, - devtool: isDevelopment ? "source-map" : false, - optimization: { - minimize: !isDevelopment, - minimizer: [new TerserPlugin()], - }, - resolve: { - extensions: [".js", ".ts", ".jsx", ".tsx"], - fallback: { - assert: require.resolve("assert/"), - buffer: require.resolve("buffer/"), - events: require.resolve("events/"), - stream: require.resolve("stream-browserify/"), - util: require.resolve("util/"), - }, - }, - output: { - filename: "index.js", - path: path.join(__dirname, "dist", "chess_rs_assets"), - }, - - // Depending in the language or framework you are using for - // front-end development, add module loaders to the default - // webpack configuration. For example, if you are using React - // modules and CSS as described in the "Adding a stylesheet" - // tutorial, uncomment the following lines: - module: { - rules: [ - { test: /\.(ts|tsx|jsx)$/, loader: "ts-loader" }, - { test: /\.css$/, use: ['style-loader','css-loader'] } - ] - }, - plugins: [ - new HtmlWebpackPlugin({ - template: path.join(__dirname, asset_entry).replace(/\.tsx$/, ".html"), - cache: false - }), - new webpack.EnvironmentPlugin({ - NODE_ENV: 'development', - CHESS_RS_CANISTER_ID: canisters["chess_rs"] - }), - new webpack.ProvidePlugin({ - Buffer: [require.resolve("buffer/"), "Buffer"], - process: require.resolve("process/browser"), - }), - ], - // proxy /api to port 8000 during development - devServer: { - proxy: { - "/api": { - target: "http://localhost:8000", - changeOrigin: true, - pathRewrite: { - "^/api": "/api", - }, - }, - }, - hot: true, - contentBase: path.resolve(__dirname, "./src/chess_rs_assets"), - watchContentBase: true - }, -}; diff --git a/library/ic-certified-map/CHANGELOG.md b/library/ic-certified-map/CHANGELOG.md index e2af8cc01..da7b6dfde 100644 --- a/library/ic-certified-map/CHANGELOG.md +++ b/library/ic-certified-map/CHANGELOG.md @@ -6,9 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [0.3.3] - 2023-02-22 +### Fixed +- Update links in doc. + ## [0.3.2] - 2022-11-10 ### Changed -Make `RbTree::new` and `RbTree::is_empty` both `const`. +- Make `RbTree::new` and `RbTree::is_empty` both `const`. ## [0.3.1] - 2022-09-16 ### Changed diff --git a/library/ic-certified-map/Cargo.toml b/library/ic-certified-map/Cargo.toml index 57e2ccd19..65639b386 100644 --- a/library/ic-certified-map/Cargo.toml +++ b/library/ic-certified-map/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-certified-map" -version = "0.3.2" +version = "0.3.3" edition = "2021" authors = ["DFINITY Stiftung "] description = "Merkleized map data structure." diff --git a/library/ic-certified-map/src/hashtree.rs b/library/ic-certified-map/src/hashtree.rs index 66531ea79..1363a2c18 100644 --- a/library/ic-certified-map/src/hashtree.rs +++ b/library/ic-certified-map/src/hashtree.rs @@ -10,7 +10,7 @@ use std::borrow::Cow; pub type Hash = [u8; 32]; /// HashTree as defined in the interfaces spec. -/// https://sdk.dfinity.org/docs/interface-spec/index.html#_certificate +/// #[derive(Debug)] pub enum HashTree<'a> { Empty, diff --git a/library/ic-certified-map/src/rbtree.rs b/library/ic-certified-map/src/rbtree.rs index 38e65a3d3..92e1fccfe 100644 --- a/library/ic-certified-map/src/rbtree.rs +++ b/library/ic-certified-map/src/rbtree.rs @@ -266,7 +266,7 @@ impl<'a, K, V> std::iter::Iterator for Iter<'a, K, V> { } /// Implements mutable left-leaning red-black trees as defined in -/// https://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf +/// #[derive(Default, Clone)] pub struct RbTree { root: NodeRef, diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index 0625b6fab..f41af406a 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.4.1] - 2023-02-22 +### Fixed +- Use automatic link in document. + ## [0.4.0] - 2023-02-13 ### Changed - Extend the Operation type to support approve/transfer_from transactions. diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 3a988b5e7..a44c5e494 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.4.0" +version = "0.4.1" edition = "2021" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." diff --git a/library/ic-ledger-types/src/lib.rs b/library/ic-ledger-types/src/lib.rs index fe0972ff1..e948667fe 100644 --- a/library/ic-ledger-types/src/lib.rs +++ b/library/ic-ledger-types/src/lib.rs @@ -317,7 +317,7 @@ pub struct GetBlocksArgs { #[derive(CandidType, Deserialize, Clone, Debug)] pub struct QueryBlocksResponse { pub chain_length: u64, - /// The replica certificate for the last block hash (see https://internetcomputer.org/docs/current/references/ic-interface-spec#certification-encoding). + /// The replica certificate for the last block hash (see ). /// Not available when querying blocks from a canister. pub certificate: Option, pub blocks: Vec, diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 6afcfabc2..05a4d51a4 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.6.8" # no need to sync with ic-cdk +version = "0.6.9" # no need to sync with ic-cdk authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index 4f460abf8..00410db42 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -198,7 +198,7 @@ pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { /// } /// ``` /// -/// [`call::reply`]: ic_cdk::api::call::reply +/// [`call::reply`]: https://docs.rs/ic-cdk/latest/ic_cdk/api/call/fn.reply.html #[proc_macro_attribute] pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_update, "ic_update", attr, item) diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index c75c788cd..a9c09a3d9 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.1.1] - 2023-02-22 + +### Fixed + +- Broken references to `ic_cdk::api::time`. + ## [0.1.0] - 2023-02-03 ### Added diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index da1e72515..942f027f0 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.1.0" +version = "0.1.1" authors = ["DFINITY Stiftung "] edition = "2021" description = "Timers library for the Rust CDK." diff --git a/src/ic-cdk-timers/src/lib.rs b/src/ic-cdk-timers/src/lib.rs index fbeac8011..28041d6e4 100644 --- a/src/ic-cdk-timers/src/lib.rs +++ b/src/ic-cdk-timers/src/lib.rs @@ -169,7 +169,7 @@ extern "C" fn global_timer() { }); } -/// Sets `func` to be executed later, after `delay`. Panics if `delay` + [`time()`][crate::api::time] is more than [`u64::MAX`] nanoseconds. +/// Sets `func` to be executed later, after `delay`. Panics if `delay` + [`time()`][ic_cdk::api::time] is more than [`u64::MAX`] nanoseconds. /// /// To cancel the timer before it executes, pass the returned `TimerId` to [`clear_timer`]. /// @@ -192,7 +192,7 @@ pub fn set_timer(delay: Duration, func: impl FnOnce() + 'static) -> TimerId { key } -/// Sets `func` to be executed every `interval`. Panics if `interval` + [`time()`][crate::api::time] is more than [`u64::MAX`] nanoseconds. +/// Sets `func` to be executed every `interval`. Panics if `interval` + [`time()`][ic_cdk::api::time] is more than [`u64::MAX`] nanoseconds. /// /// To cancel the interval timer, pass the returned `TimerId` to [`clear_timer`]. /// diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 7104d86eb..f842d1b72 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.7.1] - 2023-02-22 + +### Fixed + +- Update document for http_request. (#372) + ## [0.7.0] - 2023-02-03 ### Changed diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 9d13faf9a..cb9760e63 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.7.0" +version = "0.7.1" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic-cdk/src/api/management_canister/http_request.rs b/src/ic-cdk/src/api/management_canister/http_request.rs index 122d6a63a..802aafda2 100644 --- a/src/ic-cdk/src/api/management_canister/http_request.rs +++ b/src/ic-cdk/src/api/management_canister/http_request.rs @@ -9,7 +9,7 @@ use candid::{ use core::hash::Hash; use serde::{Deserialize, Serialize}; -/// "transform" function of type: `func (http_response) -> (http_response) query` +/// "transform" function of type: `func (http_request) -> (http_response) query` #[derive(Deserialize, Debug, PartialEq, Clone)] pub struct TransformFunc(pub candid::Func); @@ -44,9 +44,9 @@ pub struct TransformArgs { /// Type used for encoding/decoding: /// `record { -// function : func (record {response : http_response; context : blob}) -> (http_response) query; -// context : blob; -// }` +/// function : func (record {response : http_response; context : blob}) -> (http_response) query; +/// context : blob; +/// }` #[derive(CandidType, Clone, Debug, Deserialize, PartialEq)] pub struct TransformContext { /// Reference function with signature: `func (record {response : http_response; context : blob}) -> (http_response) query;`. diff --git a/src/ic-cdk/src/api/management_canister/main/mod.rs b/src/ic-cdk/src/api/management_canister/main/mod.rs index b3130fb1a..b79afbefe 100644 --- a/src/ic-cdk/src/api/management_canister/main/mod.rs +++ b/src/ic-cdk/src/api/management_canister/main/mod.rs @@ -13,7 +13,7 @@ pub use types::*; /// Cycles cost to create a canister. /// -/// https://internetcomputer.org/docs/current/developer-docs/deploy/computation-and-storage-costs +/// pub const CREATE_CANISTER_CYCLES: u128 = 100_000_000_000u128; /// Register a new canister and get its canister id. From 68fb05b28cbaa9e21cc32d56b9f7f3f175bc1d4d Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Mon, 27 Feb 2023 10:52:48 -0800 Subject: [PATCH 134/234] fix: Refactor executor (#357) * Overhaul executor * Update changelog * Remove all the implementation details from the documentation * Update the docs for the new lints * Update the Rust version elsewhere * Add PR number to changelog * lint * Fix a comment * Additions * that doesn't work --- e2e-tests/Cargo.toml | 1 + e2e-tests/canisters/async.rs | 17 ++ e2e-tests/tests/e2e.rs | 10 ++ library/ic-certified-map/src/hashtree.rs | 3 +- library/ic-certified-map/src/rbtree.rs | 2 +- library/ic-ledger-types/Cargo.toml | 2 +- library/ic-ledger-types/src/lib.rs | 2 +- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 1 + src/ic-cdk/Cargo.toml | 4 +- src/ic-cdk/src/api/call.rs | 169 +++--------------- .../api/management_canister/http_request.rs | 6 +- .../src/api/management_canister/main/mod.rs | 2 +- src/ic-cdk/src/futures.rs | 159 ++++++++-------- 14 files changed, 151 insertions(+), 229 deletions(-) diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 3edb91efe..e927942dc 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -15,6 +15,7 @@ ic-cdk-macros = { path = "../src/ic-cdk-macros" } ic-cdk-timers = { path = "../src/ic-cdk-timers" } lazy_static = "1.4.0" serde_bytes = "0.11" +futures = "0.3" [[bin]] name = "simple-kv-store" diff --git a/e2e-tests/canisters/async.rs b/e2e-tests/canisters/async.rs index 0871433f3..d1562dbc9 100644 --- a/e2e-tests/canisters/async.rs +++ b/e2e-tests/canisters/async.rs @@ -21,6 +21,7 @@ fn invocation_count() -> u64 { } #[update] +#[allow(clippy::await_holding_lock)] async fn panic_after_async() { let value = { let mut lock = RESOURCE @@ -36,6 +37,22 @@ async fn panic_after_async() { ic_cdk::api::trap("Goodbye, cruel world.") } +#[update] +#[allow(clippy::await_holding_lock)] +async fn panic_twice() { + let _lock = RESOURCE.write().unwrap(); + let fut1 = async_then_panic(); + let fut2 = async_then_panic(); + futures::future::join_all([fut1, fut2]).await; +} + +async fn async_then_panic() { + let _: (u64,) = ic_cdk::call(ic_cdk::api::id(), "on_notify", ()) + .await + .expect("Failed to call self"); + panic!(); +} + #[query] fn notifications_received() -> u64 { *NOTIFICATIONS_RECEIVED.read().unwrap() diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 4d17d97eb..6e68a9796 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -126,6 +126,16 @@ fn test_panic_after_async_frees_resources() { call_candid(&env, canister_id, "invalid_reply_payload_does_not_trap", ()) .expect("call failed"); assert_eq!(&message, "handled decoding error gracefully with code 5"); + + let err = + call_candid::<_, ()>(&env, canister_id, "panic_twice", ()).expect_err("failed to panic"); + assert!( + matches!(err, CallError::UserError(u) if u.description().contains("Call already trapped")) + ); + let _: (u64,) = call_candid(&env, canister_id, "notifications_received", ()) + .expect("failed to call unrelated function afterwards"); + let _: (u64,) = + call_candid(&env, canister_id, "invocation_count", ()).expect("failed to recover lock"); } #[test] diff --git a/library/ic-certified-map/src/hashtree.rs b/library/ic-certified-map/src/hashtree.rs index 1363a2c18..68cbc1db2 100644 --- a/library/ic-certified-map/src/hashtree.rs +++ b/library/ic-certified-map/src/hashtree.rs @@ -9,8 +9,7 @@ use std::borrow::Cow; /// SHA-256 hash bytes. pub type Hash = [u8; 32]; -/// HashTree as defined in the interfaces spec. -/// +/// HashTree as defined in the [interfaces spec](https://internetcomputer.org/docs/current/references/ic-interface-spec#certificate). #[derive(Debug)] pub enum HashTree<'a> { Empty, diff --git a/library/ic-certified-map/src/rbtree.rs b/library/ic-certified-map/src/rbtree.rs index 92e1fccfe..26a08fabb 100644 --- a/library/ic-certified-map/src/rbtree.rs +++ b/library/ic-certified-map/src/rbtree.rs @@ -509,7 +509,7 @@ impl, V: AsHashTree + 'static> RbTree { ) -> HashTree<'a> { match n { None => Empty, - Some(n) => match (n).key.as_ref().cmp(lo.as_ref()) { + Some(n) => match n.key.as_ref().cmp(lo.as_ref()) { Equal => three_way_fork( n.left_hash_tree(), match lo { diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index a44c5e494..ae841a5c8 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -12,7 +12,7 @@ keywords = ["internet-computer", "ledger"] categories = ["cryptography::cryptocurrencies", "data-structures"] include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.60.0" +rust-version = "1.65.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/library/ic-ledger-types/src/lib.rs b/library/ic-ledger-types/src/lib.rs index e948667fe..dc491d931 100644 --- a/library/ic-ledger-types/src/lib.rs +++ b/library/ic-ledger-types/src/lib.rs @@ -317,7 +317,7 @@ pub struct GetBlocksArgs { #[derive(CandidType, Deserialize, Clone, Debug)] pub struct QueryBlocksResponse { pub chain_length: u64, - /// The replica certificate for the last block hash (see ). + /// The replica certificate for the last block hash (see [Encoding of Certificates](https://internetcomputer.org/docs/current/references/ic-interface-spec#certification-encoding)). /// Not available when querying blocks from a canister. pub certificate: Option, pub blocks: Vec, diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 05a4d51a4..c544ead22 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -12,7 +12,7 @@ categories = ["api-bindings", "data-structures", "no-std", "development-tools::f keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.60.0" +rust-version = "1.65.0" [lib] proc-macro = true diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index f842d1b72..a5e792cda 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Refactored - Change from pleco to tanton for the chess library in the chess example. (#345) +- Refactor the executor to prevent a double-free on `join_all`. (#357) ## [0.6.8] - 2022-11-28 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index cb9760e63..5dead825b 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -12,7 +12,7 @@ categories = ["api-bindings", "data-structures", "no-std", "development-tools::f keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.60.0" +rust-version = "1.65.0" [dependencies] candid = "0.8" @@ -26,4 +26,4 @@ rstest = "0.12.0" [package.metadata.docs.rs] default-target = "wasm32-unknown-unknown" -rustc-args = ["--cfg=docsrs"] +rustdoc-args = ["--cfg=docsrs"] diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 3dc23c142..fcaee66d5 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -3,134 +3,14 @@ use crate::api::trap; use candid::utils::{ArgumentDecoder, ArgumentEncoder}; use candid::{decode_args, encode_args, write_args, CandidType, Deserialize, Principal}; use serde::ser::Error; +use std::cell::RefCell; use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; +use std::rc::Rc; use std::sync::atomic::Ordering; use std::task::{Context, Poll, Waker}; -#[cfg(all( - target_arch = "wasm32-unknown-unknown", - not(target_feature = "atomics") -))] -#[allow(dead_code)] -mod rc { - use std::cell::{RefCell, RefMut}; - use std::future::Future; - use std::pin::Pin; - use std::rc::Rc; - use std::task::{Context, Poll}; - - pub(crate) type InnerCell = RefCell; - - /// A reference counted cell. This is a specific implementation that is - /// both Send and Sync, but does not rely on Mutex and Arc in WASM as - /// the actual implementation of Mutex can break in async flows. - pub(crate) struct WasmCell(Rc>); - - /// In order to be able to have an async method that returns the - /// result of a call to another canister, we need that result to - /// be Send + Sync, but Rc and RefCell are not. - /// - /// Since inside a canister there isn't actual concurrent access to - /// the referenced cell or the reference counted container, it is - /// safe to force these to be Send/Sync. - unsafe impl Send for WasmCell {} - unsafe impl Sync for WasmCell {} - - impl WasmCell { - pub fn new(val: T) -> Self { - WasmCell(Rc::new(InnerCell::new(val))) - } - pub fn into_raw(self) -> *const InnerCell { - Rc::into_raw(self.0) - } - /// # Safety - /// The pointer must have been created with [`into_raw`]. - pub unsafe fn from_raw(ptr: *const InnerCell) -> Self { - Self(Rc::from_raw(ptr)) - } - pub fn borrow_mut(&self) -> RefMut<'_, T> { - self.0.borrow_mut() - } - pub fn as_ptr(&self) -> *const InnerCell { - self.0.as_ptr() as *const _ - } - } - - impl> Future for WasmCell { - type Output = O; - - #[allow(unused_mut)] - fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { - unsafe { Pin::new_unchecked(&mut *self.0.borrow_mut()) }.poll(ctx) - } - } - - impl Clone for WasmCell { - fn clone(&self) -> Self { - WasmCell(Rc::clone(&self.0)) - } - } -} - -#[cfg(not(target_arch = "wasm32-unknown-unknown"))] -#[allow(dead_code)] -mod rc { - use std::future::Future; - use std::pin::Pin; - use std::sync::{Arc, Mutex, MutexGuard}; - use std::task::{Context, Poll}; - - pub(crate) type InnerCell = Mutex; - - /// A reference counted cell. This is a specific implementation that is - /// both Send and Sync, but does not rely on Mutex and Arc in WASM as - /// the actual implementation of Mutex can break in async flows. - /// - /// The RefCell is for - pub(crate) struct WasmCell(Arc>); - - impl WasmCell { - pub fn new(val: T) -> Self { - WasmCell(Arc::new(InnerCell::new(val))) - } - pub fn into_raw(self) -> *const InnerCell { - Arc::into_raw(self.0) - } - /// # Safety - /// The pointer must have been created with [`into_raw`]. - pub unsafe fn from_raw(ptr: *const InnerCell) -> Self { - // SAFETY: If the pointer was created from into_raw, it internally was created from Arc::into_raw. - Self(unsafe { Arc::from_raw(ptr) }) - } - pub fn borrow_mut(&self) -> MutexGuard<'_, T> { - self.0.lock().unwrap() - } - pub fn as_ptr(&self) -> *const InnerCell { - Arc::<_>::as_ptr(&self.0) - } - } - - impl> Future for WasmCell { - type Output = O; - - #[allow(unused_mut)] - fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { - // SAFETY: this is a projection of self, which is pinned - unsafe { Pin::new_unchecked(&mut *self.0.lock().unwrap()) }.poll(ctx) - } - } - - impl Clone for WasmCell { - fn clone(&self) -> Self { - WasmCell(Arc::clone(&self.0)) - } - } -} - -use rc::{InnerCell, WasmCell}; - /// Rejection code from calling another canister. /// /// These can be obtained either using `reject_code()` or `reject_result()`. @@ -175,23 +55,20 @@ impl From for RejectionCode { pub type CallResult = Result; // Internal state for the Future when sending a call. -struct CallFutureState { - result: Option>, +struct CallFutureState { + result: Option>>, waker: Option, } -struct CallFuture { - // We basically use Rc instead of Arc (since we're single threaded), and use - // RefCell instead of Mutex (because we cannot lock in WASM). - state: rc::WasmCell>, +struct CallFuture { + state: Rc>, } -impl Future for CallFuture { - type Output = Result; +impl Future for CallFuture { + type Output = CallResult>; fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll { - let self_ref = Pin::into_ref(self); - + let self_ref = Pin::into_inner(self); let mut state = self_ref.state.borrow_mut(); if let Some(result) = state.result.take() { @@ -209,10 +86,10 @@ impl Future for CallFuture { /// /// # Safety /// -/// This function must only be passed to the IC with a pointer from WasmCell::into_raw as userdata. -unsafe fn callback(state_ptr: *const InnerCell>>) { - // SAFETY: This function is only ever called by the IC, and we only ever pass a WasmCell as userdata. - let state = unsafe { WasmCell::from_raw(state_ptr) }; +/// This function must only be passed to the IC with a pointer from Rc::into_raw as userdata. +unsafe fn callback(state_ptr: *const RefCell) { + // SAFETY: This function is only ever called by the IC, and we only ever pass a Rc as userdata. + let state = unsafe { Rc::from_raw(state_ptr) }; // Make sure to un-borrow_mut the state. { state.borrow_mut().result = Some(match reject_code() { @@ -234,10 +111,10 @@ unsafe fn callback(state_ptr: *const InnerCell>>) { /// /// # Safety /// -/// This function must only be passed to the IC with a pointer from WasmCell::into_raw as userdata. -unsafe fn cleanup(state_ptr: *const InnerCell>>) { - // SAFETY: This function is only ever called by the IC, and we only ever pass a WasmCell as userdata. - let state = unsafe { WasmCell::from_raw(state_ptr) }; +/// This function must only be passed to the IC with a pointer from Rc::into_raw as userdata. +unsafe fn cleanup(state_ptr: *const RefCell) { + // SAFETY: This function is only ever called by the IC, and we only ever pass a Rc as userdata. + let state = unsafe { Rc::from_raw(state_ptr) }; // We set the call result, even though it won't be read on the // default executor, because we can't guarantee it was called on // our executor. However, we are not allowed to inspect @@ -245,7 +122,7 @@ unsafe fn cleanup(state_ptr: *const InnerCell>>) { // result to a reject. // // Borrowing does not trap - the rollback from the - // previous trap ensures that the WasmCell can be borrowed again. + // previous trap ensures that the RefCell can be borrowed again. state.borrow_mut().result = Some(Err((RejectionCode::NoError, "cleanup".to_string()))); let w = state.borrow_mut().waker.take(); if let Some(waker) = w { @@ -387,19 +264,19 @@ fn call_raw_internal( payment_func: impl FnOnce(), ) -> impl Future>> { let callee = id.as_slice(); - let state = WasmCell::new(CallFutureState { + let state = Rc::new(RefCell::new(CallFutureState { result: None, waker: None, - }); - let state_ptr = WasmCell::into_raw(state.clone()); + })); + let state_ptr = Rc::into_raw(state.clone()); // SAFETY: // `callee`, being &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_new. // `method`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.call_new. // `callback` is a function with signature (env : i32) -> () and therefore can be called as both reply and reject fn for ic0.call_new. - // `state_ptr` is a pointer created via WasmCell::into_raw, and can therefore be passed as the userdata for `callback`. + // `state_ptr` is a pointer created via Rc::into_raw, and can therefore be passed as the userdata for `callback`. // `args`, being a &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_data_append. // `cleanup` is a function with signature (env : i32) -> () and therefore can be called as a cleanup fn for ic0.call_on_cleanup. - // `state_ptr` is a pointer created via WasmCell::into_raw, and can therefore be passed as the userdata for `cleanup`. + // `state_ptr` is a pointer created via Rc::into_raw, and can therefore be passed as the userdata for `cleanup`. // ic0.call_perform is always safe to call. let err_code = unsafe { ic0::call_new( diff --git a/src/ic-cdk/src/api/management_canister/http_request.rs b/src/ic-cdk/src/api/management_canister/http_request.rs index 802aafda2..0bb378f27 100644 --- a/src/ic-cdk/src/api/management_canister/http_request.rs +++ b/src/ic-cdk/src/api/management_canister/http_request.rs @@ -10,7 +10,7 @@ use core::hash::Hash; use serde::{Deserialize, Serialize}; /// "transform" function of type: `func (http_request) -> (http_response) query` -#[derive(Deserialize, Debug, PartialEq, Clone)] +#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] pub struct TransformFunc(pub candid::Func); impl CandidType for TransformFunc { @@ -47,7 +47,7 @@ pub struct TransformArgs { /// function : func (record {response : http_response; context : blob}) -> (http_response) query; /// context : blob; /// }` -#[derive(CandidType, Clone, Debug, Deserialize, PartialEq)] +#[derive(CandidType, Clone, Debug, Deserialize, PartialEq, Eq)] pub struct TransformContext { /// Reference function with signature: `func (record {response : http_response; context : blob}) -> (http_response) query;`. pub function: TransformFunc, @@ -126,7 +126,7 @@ pub enum HttpMethod { } /// Argument type of [http_request]. -#[derive(CandidType, Deserialize, Debug, PartialEq, Clone)] +#[derive(CandidType, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct CanisterHttpRequestArgument { /// The requested URL. pub url: String, diff --git a/src/ic-cdk/src/api/management_canister/main/mod.rs b/src/ic-cdk/src/api/management_canister/main/mod.rs index b79afbefe..759646e56 100644 --- a/src/ic-cdk/src/api/management_canister/main/mod.rs +++ b/src/ic-cdk/src/api/management_canister/main/mod.rs @@ -13,7 +13,7 @@ pub use types::*; /// Cycles cost to create a canister. /// -/// +/// See [Computation and Storage Costs](https://internetcomputer.org/docs/current/developer-docs/deploy/computation-and-storage-costs) pub const CREATE_CANISTER_CYCLES: u128 = 100_000_000_000u128; /// Register a new canister and get its canister id. diff --git a/src/ic-cdk/src/futures.rs b/src/ic-cdk/src/futures.rs index a07eb5c8c..35a70504a 100644 --- a/src/ic-cdk/src/futures.rs +++ b/src/ic-cdk/src/futures.rs @@ -1,121 +1,138 @@ +use std::cell::{Cell, RefCell}; use std::future::Future; use std::pin::Pin; +use std::rc::Rc; use std::sync::atomic::AtomicBool; use std::task::Context; +use self::waker::WakerState; + /// Must be called on every top-level future corresponding to a method call of a -/// canister by the IC. -/// -/// Saves the pointer to the future on the heap and kickstarts the future by -/// polling it once. During the polling we also need to provide the waker -/// callback which is triggered after the future made progress. -/// The waker would then poll the future one last time to advance it to -/// the final state. For that, we pass the future pointer to the waker, so that -/// it can be restored into a box from a raw pointer and then dropped if not -/// needed anymore. -/// -/// Technically, we store 2 pointers on the heap: the pointer to the future -/// itself, and a pointer to that pointer. The reason for this is that the waker -/// API requires us to pass one thin pointer, while a a pointer to a `dyn Trait` -/// can only be fat. So we create one additional thin pointer, pointing to the -/// fat pointer and pass it instead. +/// canister by the IC, other than async functions marked `#[update]` or similar. +#[cfg_attr(not(target_arch = "wasm32"), allow(unused_variables, unreachable_code))] pub fn spawn>(future: F) { - let future_ptr = Box::into_raw(Box::new(future)); - let future_ptr_ptr: *mut *mut dyn Future = Box::into_raw(Box::new(future_ptr)); - // SAFETY: The pointer is to a Box, which satisfies the pinning requirement. - let mut pinned_future = unsafe { Pin::new_unchecked(&mut *future_ptr) }; - if pinned_future + #[cfg(not(target_arch = "wasm32"))] + panic!("Cannot be run outside of wasm!"); // really, just cannot be run in a multi-threaded environment + let pinned_future = Box::pin(future); + let waker_state = Rc::new(WakerState { + future: RefCell::new(pinned_future), + previous_trap: Cell::new(false), + }); + let waker = waker::waker(Rc::clone(&waker_state)); + let _ = waker_state + .future + .borrow_mut() .as_mut() - // SAFETY: future_ptr_ptr was constructed from a boxed box. - // future_ptr_ptr is NOT unique (shared by pinned_future). This call is UNSOUND. - // FIXME - .poll(&mut Context::from_waker(&unsafe { - waker::waker(future_ptr_ptr as *const ()) - })) - .is_ready() - { - // SAFETY: These were created from boxes earlier in the function - unsafe { - let _ = Box::from_raw(future_ptr); - let _ = Box::from_raw(future_ptr_ptr); - } - } + .poll(&mut Context::from_waker(&waker)); } pub(crate) static CLEANUP: AtomicBool = AtomicBool::new(false); // This module contains the implementation of a waker we're using for waking -// top-level futures (the ones returned by canister methods). The waker polls -// the future once and re-pins it on the heap, if it's pending. If the future is -// done, we do nothing. Hence, it will be unallocated once we exit the scope and +// top-level futures (the ones returned by canister methods). Rc handles the +// heap management for us. Hence, it will be deallocated once we exit the scope and // we're not interested in the result, as it can only be a unit `()` if the // waker was used as intended. +// Sizable unsafe code is mandatory here; Future::poll cannot be executed without implementing +// RawWaker in terms of raw pointers. mod waker { use super::*; use std::{ + rc::Rc, sync::atomic::Ordering, task::{RawWaker, RawWakerVTable, Waker}, }; - type FuturePtr = *mut dyn Future; + + // The fields have separate RefCells in order to be modified separately. + pub(crate) struct WakerState { + pub future: RefCell>>>, + pub previous_trap: Cell, + } static MY_VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); /// # Safety /// - /// The pointer must be a unique Box-allocated pointer to a Box-allocated pointer to a `dyn Future`. + /// The pointer must be an owning (i.e. represented in the refcount), Rc-allocated pointer to a `WakerState`. unsafe fn raw_waker(ptr: *const ()) -> RawWaker { // SAFETY: All the function pointers in MY_VTABLE correctly operate on the pointer in question. RawWaker::new(ptr, &MY_VTABLE) } /// # Safety + /// /// This function should only be called by a [Waker] created by [`waker`]. unsafe fn clone(ptr: *const ()) -> RawWaker { - // SAFETY: The pointer attached via `waker` satisfies its own contract. - unsafe { raw_waker(ptr) } + // SAFETY: The function's contract guarantees that this pointer is an Rc to a WakerState, and borrows the data from ptr. + unsafe { + Rc::increment_strong_count(ptr); + raw_waker(ptr) + } } - // Our waker will be called only if one of the response callbacks is triggered. + // Our waker will be called if one of the response callbacks is triggered. // Then, the waker will restore the future from the pointer we passed into the - // waker inside the `kickstart` method and poll the future again. If the future - // is pending, we leave it on the heap. If it's ready, we deallocate the - // pointer. If CLEANUP is set, then we're recovering from a callback trap, and - // want to drop the future without executing any more of it. + // waker inside the `spawn` function and poll the future again. Rc takes care of + // the heap management for us. If CLEANUP is set, then we're recovering from + // a callback trap, and want to drop the future without executing any more of it; + // if previous_trap is set, then we already recovered from a callback trap in a + // different callback, and should immediately trap again in this one. + // /// # Safety + /// /// This function should only be called by a [Waker] created by [`waker`]. unsafe fn wake(ptr: *const ()) { - // SAFETY: The function contract guarantees that the outer pointer is a Box of the FuturePtr. - let boxed_future_ptr_ptr = unsafe { Box::from_raw(ptr as *mut FuturePtr) }; - let future_ptr: FuturePtr = *boxed_future_ptr_ptr; - // SAFETY: The function contract guarantees that the inner pointer is a FuturePtr, and unique. - let mut boxed_future = unsafe { Box::from_raw(future_ptr) }; - // SAFETY: Boxes satisfy the pinning contract and are sound to use in new_unchecked. - // The box is never moved out of, but dropped in place. - let mut pinned_future = unsafe { Pin::new_unchecked(&mut *boxed_future) }; - if !super::CLEANUP.load(Ordering::Relaxed) - && pinned_future - .as_mut() - // SAFETY: The pointer attached via `waker` satisfies its own contract. - .poll(&mut Context::from_waker(&unsafe { waker::waker(ptr) })) - .is_pending() - { - Box::into_raw(boxed_future_ptr_ptr); - Box::into_raw(boxed_future); + // SAFETY: The function's contract guarantees that the pointer is an Rc to a WakerState, and that this call takes ownership of the data. + let state = unsafe { Rc::from_raw(ptr as *const WakerState) }; + // Must check CLEANUP *before* previous_trap, as we may be recovering from the following immediate trap. + if super::CLEANUP.load(Ordering::Relaxed) { + state.previous_trap.set(true); + } else if state.previous_trap.get() { + crate::trap("Call already trapped"); + } else { + let waker = waker(Rc::clone(&state)); + let Ok(mut borrow) = state.future.try_borrow_mut() else { + // If this is already borrowed, then wake was called from inside poll. There's not a lot we can do about this - we are not + // a true scheduler and so cannot immediately schedule another poll, nor can we reentrantly lock the future. So we ignore it. + // This will be disappointing to types like FuturesUnordered that expected this to work, but since the only source of asynchrony + // and thus a guaranteed source of wakeup notifications is the ic0.call_new callback, this shouldn't cause any actual problems. + return; + }; + let pinned_future = borrow.as_mut(); + let _ = pinned_future.poll(&mut Context::from_waker(&waker)); } } - fn wake_by_ref(_: *const ()) {} - - fn drop(_: *const ()) {} + /// # Safety + /// + /// This function should only be called by a [Waker] created by [waker]. + unsafe fn wake_by_ref(ptr: *const ()) { + // SAFETY: + // The function's contract guarantees that the pointer is an Rc to a WakerState, and that this call borrows the data. + // wake has the same contract, except it takes ownership instead of borrowing. Which just requires incrementing the refcount. + unsafe { + Rc::increment_strong_count(ptr as *const WakerState); + wake(ptr); + } + } /// # Safety /// - /// The pointer must be a unique Box-allocated pointer to a Box-allocated pointer to a `dyn Future`. - pub unsafe fn waker(ptr: *const ()) -> Waker { + /// This function should only be called by a [Waker] created by [waker]. + unsafe fn drop(ptr: *const ()) { + // SAFETY: The function contract guarantees that the pointer is an Rc to a WakerState, and that this call takes ownership of the data. + unsafe { + Rc::from_raw(ptr as *const WakerState); + } + } + + /// Creates a new Waker. + pub(crate) fn waker(state: Rc) -> Waker { + let ptr = Rc::into_raw(state); // SAFETY: - // raw_waker has the same safety requirement on ptr as this function - // The functions in the vtable are passed the ptr that was passed to this function + // The pointer is an owning, Rc-allocated pointer to a WakerState, and therefore can be passed to raw_waker + // The functions in the vtable are passed said ptr // The functions in the vtable uphold RawWaker's contract - unsafe { Waker::from_raw(raw_waker(ptr)) } + unsafe { Waker::from_raw(raw_waker(ptr as *const ())) } } } From 65efdbcf343f64b6b8eb3c80b6109dc24ea2b0cf Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 27 Feb 2023 14:06:45 -0500 Subject: [PATCH 135/234] chore: use state machine client in e2e tests (#375) * script to download state machine binary * use state machine client * Instruct how to run e2e tests * ci * fix clippy * fix e2e --- .github/workflows/ci.yml | 3 + .gitignore | 2 + e2e-tests/Cargo.toml | 2 +- e2e-tests/tests/e2e.rs | 183 ++++++++++------------- scripts/download_state_machine_binary.sh | 16 ++ 5 files changed, 97 insertions(+), 109 deletions(-) create mode 100755 scripts/download_state_machine_binary.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 21db968da..039f905f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,6 +70,9 @@ jobs: - name: Install protoc run: | sudo apt-get install -y protobuf-compiler + - name: Download ic-test-state-machine + run: | + bash scripts/download_state_machine_binary.sh - name: Run tests run: | cargo test --all-targets diff --git a/.gitignore b/.gitignore index f8a4c171e..bc533ffc9 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk .DS_Store + +ic-test-state-machine diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index e927942dc..38efa1530 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -38,5 +38,5 @@ name = "timers" path = "canisters/timers.rs" [dev-dependencies] -ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "1612a202d030faa496e1694eed98be4179fca856" } candid = "0.8" +ic-test-state-machine-client = "1" diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 6e68a9796..8600b8967 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -1,71 +1,24 @@ -use std::time::{Duration, SystemTime}; +use std::time::Duration; -// use ic_cdk::export::candid::utils::{decode_args, encode_args, ArgumentDecoder, ArgumentEncoder}; -// use ic_cdk::export::candid::Encode; -use candid::utils::{decode_args, encode_args, ArgumentDecoder, ArgumentEncoder}; -use candid::Encode; +use candid::{Encode, Principal}; use ic_cdk_e2e_tests::cargo_build_canister; -use ic_state_machine_tests::{CanisterId, ErrorCode, StateMachine, UserError, WasmResult}; +use ic_test_state_machine_client::{ + call_candid, query_candid, CallError, ErrorCode, StateMachine, WasmResult, +}; use serde_bytes::ByteBuf; -#[derive(Debug)] -enum CallError { - Reject(String), - UserError(UserError), -} +pub static STATE_MACHINE_BINARY: &str = "../ic-test-state-machine"; -/// A helper function that we use to implement both [`call_candid`] and -/// [`query_candid`]. -fn with_candid( - input: Input, - f: impl FnOnce(Vec) -> Result, -) -> Result -where - Input: ArgumentEncoder, - Output: for<'a> ArgumentDecoder<'a>, -{ - let in_bytes = encode_args(input).expect("failed to encode args"); - match f(in_bytes) { - Ok(WasmResult::Reply(out_bytes)) => Ok(decode_args(&out_bytes).unwrap_or_else(|e| { - panic!( - "Failed to decode bytes {:?} as candid type: {}", - std::any::type_name::(), - e - ) - })), - Ok(WasmResult::Reject(message)) => Err(CallError::Reject(message)), - Err(user_error) => Err(CallError::UserError(user_error)), +pub fn env() -> StateMachine { + if !std::path::Path::new(STATE_MACHINE_BINARY).exists() { + eprintln!( + " +ERROR: Could not find state machine binary to run e2e tests. + Please run `bash scripts/download_state_machine_binary.sh`." + ); } -} - -/// Call a canister candid method. -fn call_candid( - env: &StateMachine, - canister_id: CanisterId, - method: &str, - input: Input, -) -> Result -where - Input: ArgumentEncoder, - Output: for<'a> ArgumentDecoder<'a>, -{ - with_candid(input, |bytes| { - env.execute_ingress(canister_id, method, bytes) - }) -} -/// Query a canister candid method. -fn query_candid( - env: &StateMachine, - canister_id: CanisterId, - method: &str, - input: Input, -) -> Result -where - Input: ArgumentEncoder, - Output: for<'a> ArgumentDecoder<'a>, -{ - with_candid(input, |bytes| env.query(canister_id, method, bytes)) + StateMachine::new(STATE_MACHINE_BINARY, false) } /// Checks that a canister that uses [`ic_cdk::storage::stable_store`] @@ -73,16 +26,15 @@ where /// across upgrades. #[test] fn test_storage_roundtrip() { - let env = StateMachine::new(); - let kv_store_wasm = cargo_build_canister("simple-kv-store"); - let canister_id = env - .install_canister(kv_store_wasm.clone(), vec![], None) - .unwrap(); + let env = env(); + let wasm = cargo_build_canister("simple-kv-store"); + let canister_id = env.create_canister(); + env.install_canister(canister_id, wasm.clone(), vec![]); let () = call_candid(&env, canister_id, "insert", (&"candid", &b"did")) .expect("failed to insert 'candid'"); - env.upgrade_canister(canister_id, kv_store_wasm, vec![]) + env.upgrade_canister(canister_id, wasm, vec![]) .expect("failed to upgrade the simple-kv-store canister"); let (result,): (Option,) = @@ -92,11 +44,10 @@ fn test_storage_roundtrip() { #[test] fn test_panic_after_async_frees_resources() { - let env = StateMachine::new(); + let env = env(); let wasm = cargo_build_canister("async"); - let canister_id = env - .install_canister(wasm, vec![], None) - .expect("failed to install a canister"); + let canister_id = env.create_canister(); + env.install_canister(canister_id, wasm, vec![]); for i in 1..3 { match call_candid(&env, canister_id, "panic_after_async", ()) { @@ -105,13 +56,13 @@ fn test_panic_after_async_frees_resources() { Err(CallError::UserError(e)) => { println!("Got a user error as expected: {}", e); - assert_eq!(e.code(), ErrorCode::CanisterCalledTrap); + assert_eq!(e.code, ErrorCode::CanisterCalledTrap); let expected_message = "Goodbye, cruel world."; assert!( - e.description().contains(expected_message), + e.description.contains(expected_message), "Expected the user error to contain '{}', got: {}", expected_message, - e.description() + e.description ); } } @@ -130,7 +81,7 @@ fn test_panic_after_async_frees_resources() { let err = call_candid::<_, ()>(&env, canister_id, "panic_twice", ()).expect_err("failed to panic"); assert!( - matches!(err, CallError::UserError(u) if u.description().contains("Call already trapped")) + matches!(err, CallError::UserError(u) if u.description.contains("Call already trapped")) ); let _: (u64,) = call_candid(&env, canister_id, "notifications_received", ()) .expect("failed to call unrelated function afterwards"); @@ -140,30 +91,40 @@ fn test_panic_after_async_frees_resources() { #[test] fn test_raw_api() { - let env = StateMachine::new(); - let rev = cargo_build_canister("reverse"); - let canister_id = env.install_canister(rev, vec![], None).unwrap(); + let env = env(); + let wasm = cargo_build_canister("reverse"); + let canister_id = env.create_canister(); + env.install_canister(canister_id, wasm, vec![]); - let result = env.query(canister_id, "reverse", vec![1, 2, 3, 4]).unwrap(); + let result = env + .query_call( + canister_id, + Principal::anonymous(), + "reverse", + vec![1, 2, 3, 4], + ) + .unwrap(); assert_eq!(result, WasmResult::Reply(vec![4, 3, 2, 1])); let result = env - .execute_ingress(canister_id, "empty_call", Default::default()) + .update_call( + canister_id, + Principal::anonymous(), + "empty_call", + Default::default(), + ) .unwrap(); assert_eq!(result, WasmResult::Reply(Default::default())); } #[test] fn test_notify_calls() { - let env = StateMachine::new(); + let env = env(); let wasm = cargo_build_canister("async"); - let sender_id = env - .install_canister(wasm.clone(), vec![], None) - .expect("failed to install a canister"); - - let receiver_id = env - .install_canister(wasm, vec![], None) - .expect("failed to install a canister"); + let sender_id = env.create_canister(); + env.install_canister(sender_id, wasm.clone(), vec![]); + let receiver_id = env.create_canister(); + env.install_canister(receiver_id, wasm, vec![]); let (n,): (u64,) = query_candid(&env, receiver_id, "notifications_received", ()) .expect("failed to query 'notifications_received'"); @@ -181,14 +142,13 @@ fn test_notify_calls() { #[test] #[ignore] fn test_composite_query() { - let env = StateMachine::new(); + let env = env(); let wasm = cargo_build_canister("async"); - let sender_id = env - .install_canister(wasm.clone(), vec![], None) - .expect("failed to install sender"); - let receiver_id = env - .install_canister(wasm, vec![], None) - .expect("failed to install sender"); + let sender_id = env.create_canister(); + env.install_canister(sender_id, wasm.clone(), vec![]); + let receiver_id = env.create_canister(); + env.install_canister(receiver_id, wasm, vec![]); + let (greeting,): (String,) = query_candid(&env, sender_id, "greet_self", (receiver_id,)) .expect("failed to query 'greet_self'"); assert_eq!(greeting, "Hello, myself"); @@ -196,27 +156,32 @@ fn test_composite_query() { #[test] fn test_api_call() { - let env = StateMachine::new(); - let rev = cargo_build_canister("api-call"); - let canister_id = env.install_canister(rev, vec![], None).unwrap(); - + let env = env(); + let wasm = cargo_build_canister("api-call"); + let canister_id = env.create_canister(); + env.install_canister(canister_id, wasm, vec![]); let (result,): (u64,) = query_candid(&env, canister_id, "instruction_counter", ()) .expect("failed to query instruction_counter"); assert!(result > 0); let result = env - .query(canister_id, "manual_reject", Encode!().unwrap()) + .query_call( + canister_id, + Principal::anonymous(), + "manual_reject", + Encode!().unwrap(), + ) .unwrap(); assert_eq!(result, WasmResult::Reject("manual reject".to_string())); } #[test] fn test_timers() { - let env = StateMachine::new(); - let time = SystemTime::now(); - env.set_time(time); + let env = env(); let wasm = cargo_build_canister("timers"); - let canister_id = env.install_canister(wasm, vec![], None).unwrap(); + let canister_id = env.create_canister(); + env.install_canister(canister_id, wasm, vec![]); + call_candid::<(), ()>(&env, canister_id, "schedule", ()).expect("Failed to call schedule"); advance_seconds(&env, 5); @@ -243,9 +208,10 @@ fn test_timers() { #[test] fn test_timers_can_cancel_themselves() { - let env = StateMachine::new(); + let env = env(); let wasm = cargo_build_canister("timers"); - let canister_id = env.install_canister(wasm, vec![], None).unwrap(); + let canister_id = env.create_canister(); + env.install_canister(canister_id, wasm, vec![]); call_candid::<_, ()>(&env, canister_id, "set_self_cancelling_timer", ()) .expect("Failed to call set_self_cancelling_timer"); @@ -266,9 +232,10 @@ fn test_timers_can_cancel_themselves() { fn test_scheduling_many_timers() { // Must be more than the queue limit (500) let timers_to_schedule = 1_000; - let env = StateMachine::new(); + let env = env(); let wasm = cargo_build_canister("timers"); - let canister_id = env.install_canister(wasm, vec![], None).unwrap(); + let canister_id = env.create_canister(); + env.install_canister(canister_id, wasm, vec![]); let () = call_candid( &env, diff --git a/scripts/download_state_machine_binary.sh b/scripts/download_state_machine_binary.sh new file mode 100755 index 000000000..670e6844c --- /dev/null +++ b/scripts/download_state_machine_binary.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Make sure we always run from the root +SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "$SCRIPTS_DIR/.." + +uname_sys=$(uname -s | tr '[:upper:]' '[:lower:]') +echo "uname_sys: $uname_sys" +commit_sha="d0ea9d15cc51bd5bba16c8f1be3a6dfc8ec7dc24" + +curl -sLO "https://download.dfinity.systems/ic/$commit_sha/binaries/x86_64-$uname_sys/ic-test-state-machine.gz" +gzip -d ic-test-state-machine.gz +chmod a+x ic-test-state-machine +./ic-test-state-machine --version From 893f9ea1fc0a80321ec9b29b9e076f7841a58f60 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Mon, 27 Feb 2023 12:13:02 -0800 Subject: [PATCH 136/234] fix: Only call `ic0.global_timer_set` if there isn't a more recent timer (#373) * Only call `ic0.global_timer_set` if there isn't a more recent timer * fix CI * revert, fixed upstream * different strategy --- src/ic-cdk-timers/src/lib.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/ic-cdk-timers/src/lib.rs b/src/ic-cdk-timers/src/lib.rs index 28041d6e4..5ad62b6ee 100644 --- a/src/ic-cdk-timers/src/lib.rs +++ b/src/ic-cdk-timers/src/lib.rs @@ -9,7 +9,13 @@ //! # } //! ``` -use std::{cell::RefCell, cmp::Ordering, collections::BinaryHeap, mem, time::Duration}; +use std::{ + cell::{Cell, RefCell}, + cmp::Ordering, + collections::BinaryHeap, + mem, + time::Duration, +}; use futures::{stream::FuturesUnordered, StreamExt}; use slotmap::{new_key_type, KeyData, SlotMap}; @@ -23,6 +29,7 @@ use ic_cdk::api::call::RejectionCode; thread_local! { static TASKS: RefCell> = RefCell::default(); static TIMERS: RefCell> = RefCell::default(); + static MOST_RECENT: Cell> = Cell::new(None); } enum Task { @@ -165,6 +172,7 @@ extern "C" fn global_timer() { } }); } + MOST_RECENT.with(|recent| recent.set(None)); update_ic0_timer(); }); } @@ -229,9 +237,17 @@ pub fn clear_timer(id: TimerId) { fn update_ic0_timer() { TIMERS.with(|timers| { let timers = timers.borrow(); - let soonest_timer = timers.peek().map_or(0, |timer| timer.time); - // SAFETY: ic0::global_timer_set is always a safe call - unsafe { ic0::global_timer_set(soonest_timer as i64) }; + let soonest_timer = timers.peek().map(|timer| timer.time); + let should_change = match (soonest_timer, MOST_RECENT.with(|recent| recent.get())) { + (Some(timer), Some(recent)) => timer < recent, + (Some(_), None) => true, + _ => false, + }; + if should_change { + // SAFETY: ic0::global_timer_set is always a safe call + unsafe { ic0::global_timer_set(soonest_timer.unwrap() as i64) }; + MOST_RECENT.with(|recent| recent.set(soonest_timer)); + } }); } From bfd976addbcc26ad6a615cdcdd1daef814bcbb4a Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Tue, 28 Feb 2023 15:26:44 -0800 Subject: [PATCH 137/234] chore: Update lint settings and add missing documentation (#376) * Add lints and docs * Update library/ic-ledger-types/src/lib.rs Co-authored-by: Eric Swanson <64809312+ericswanson-dfinity@users.noreply.github.com> * Copy-paste docs from ledger.did * the * the --------- Co-authored-by: Eric Swanson <64809312+ericswanson-dfinity@users.noreply.github.com> --- library/ic-certified-map/Cargo.toml | 3 + library/ic-certified-map/src/hashtree.rs | 14 +- library/ic-certified-map/src/lib.rs | 80 +++++++++++ library/ic-certified-map/src/rbtree.rs | 10 +- library/ic-ledger-types/src/lib.rs | 172 ++++++++++++++++++++++- src/ic-cdk-macros/src/lib.rs | 9 ++ src/ic-cdk-timers/src/lib.rs | 9 ++ src/ic-cdk/src/api/call.rs | 1 + src/ic-cdk/src/api/stable/canister.rs | 2 +- src/ic-cdk/src/api/stable/mod.rs | 8 +- src/ic-cdk/src/lib.rs | 2 + src/ic0/src/ic0.rs | 2 +- src/ic0/src/lib.rs | 11 ++ 13 files changed, 309 insertions(+), 14 deletions(-) diff --git a/library/ic-certified-map/Cargo.toml b/library/ic-certified-map/Cargo.toml index 65639b386..e5d7c2c7d 100644 --- a/library/ic-certified-map/Cargo.toml +++ b/library/ic-certified-map/Cargo.toml @@ -22,3 +22,6 @@ sha2 = "0.10" [dev-dependencies] hex = "0.4" serde_cbor = "0.11" +ic-cdk = { path = "../../src/ic-cdk" } +candid = "0.8" +serde = "1" diff --git a/library/ic-certified-map/src/hashtree.rs b/library/ic-certified-map/src/hashtree.rs index 68cbc1db2..dbb5ea6c0 100644 --- a/library/ic-certified-map/src/hashtree.rs +++ b/library/ic-certified-map/src/hashtree.rs @@ -10,23 +10,32 @@ use std::borrow::Cow; pub type Hash = [u8; 32]; /// HashTree as defined in the [interfaces spec](https://internetcomputer.org/docs/current/references/ic-interface-spec#certificate). -#[derive(Debug)] +#[derive(Debug, Clone, Default)] pub enum HashTree<'a> { + /// No child nodes; a proof of absence. + #[default] Empty, + /// Left and right child branches. Fork(Box<(HashTree<'a>, HashTree<'a>)>), + /// A labeled child node. Labeled(&'a [u8], Box>), + /// A leaf node containing a value or hash. Leaf(Cow<'a, [u8]>), + /// A branch that has been removed from this view of the tree, but is not necessarily absent. Pruned(Hash), } +/// Shorthand for [`HashTree::Fork`]. pub fn fork<'a>(l: HashTree<'a>, r: HashTree<'a>) -> HashTree<'a> { HashTree::Fork(Box::new((l, r))) } +/// Shorthand for [`HashTree::Labeled`]. pub fn labeled<'a>(l: &'a [u8], t: HashTree<'a>) -> HashTree<'a> { HashTree::Labeled(l, Box::new(t)) } +/// Identifiably hashes a fork in the branch. Used for hashing [`HashTree::Fork`]. pub fn fork_hash(l: &Hash, r: &Hash) -> Hash { let mut h = domain_sep("ic-hashtree-fork"); h.update(&l[..]); @@ -34,12 +43,14 @@ pub fn fork_hash(l: &Hash, r: &Hash) -> Hash { h.finalize().into() } +/// Identifiably hashes a leaf node's data. Used for hashing [`HashTree::Leaf`]. pub fn leaf_hash(data: &[u8]) -> Hash { let mut h = domain_sep("ic-hashtree-leaf"); h.update(data); h.finalize().into() } +/// Identifiably hashes a label for this branch. Used for hashing [`HashTree::Labeled`]. pub fn labeled_hash(label: &[u8], content_hash: &Hash) -> Hash { let mut h = domain_sep("ic-hashtree-labeled"); h.update(label); @@ -48,6 +59,7 @@ pub fn labeled_hash(label: &[u8], content_hash: &Hash) -> Hash { } impl HashTree<'_> { + /// Produces the root hash of the tree. pub fn reconstruct(&self) -> Hash { match self { Self::Empty => domain_sep("ic-hashtree-empty").finalize().into(), diff --git a/library/ic-certified-map/src/lib.rs b/library/ic-certified-map/src/lib.rs index c141588d0..c84f8254c 100644 --- a/library/ic-certified-map/src/lib.rs +++ b/library/ic-certified-map/src/lib.rs @@ -1,3 +1,83 @@ +//! This package provides a map backed by a Merkle tree that can be used +//! by Internet Computer canisters to implement certified queries. +//! +//! You can certify your data by using the [`RbTree`] type as a map of +//! known names to the values you want certified. After you record its +//! [`root_hash`](RbTree::root_hash) into your canister's [certified data], +//! query calls can access a [data certificate] proving that the IC certified +//! the hash, under the [path] `/canister//certified_data`. +//! By providing this certificate, as well as a [`witness`](RbTree::witness) +//! that the value exists in the hash, you can then prove to the caller that +//! the IC certified the data. +//! +//! [certified data]: https://docs.rs/ic-cdk/latest/ic_cdk/api/fn.set_certified_data.html +//! [data certificate]: https://docs.rs/ic-cdk/latest/ic_cdk/api/fn.data_certificate.html +//! [path]: https://internetcomputer.org/docs/current/references/ic-interface-spec#state-tree +//! +//! # Example +//! +//! ``` +//! # use std::cell::*; +//! # use ic_cdk::*; +//! # use ic_certified_map::*; +//! # use ic_cdk::export::candid::CandidType; +//! # use serde::Serialize; +//! +//! thread_local! { +//! static COUNTER: Cell = Cell::new(0); +//! static TREE: RefCell> = RefCell::new(RbTree::new()); +//! } +//! +//! #[update] +//! fn inc() { +//! let count = COUNTER.with(|counter| { +//! let count = counter.get() + 1; +//! counter.set(count); +//! count +//! }); +//! TREE.with(|tree| { +//! let mut tree = tree.borrow_mut(); +//! tree.insert("counter", leaf_hash(&count.to_be_bytes())); +//! ic_cdk::api::set_certified_data(&tree.root_hash()); +//! }) +//! } +//! +//! #[derive(CandidType)] +//! struct CertifiedCounter { +//! count: i32, +//! certificate: Vec, +//! witness: Vec, +//! } +//! +//! #[query] +//! fn get() -> CertifiedCounter { +//! let certificate = ic_cdk::api::data_certificate().expect("No data certificate available"); +//! let witness = TREE.with(|tree| { +//! let tree = tree.borrow(); +//! let mut witness = vec![]; +//! let mut witness_serializer = serde_cbor::Serializer::new(&mut witness); +//! witness_serializer.self_describe(); +//! tree.witness(b"counter").serialize(&mut witness_serializer).unwrap(); +//! witness +//! }); +//! let count = COUNTER.with(|counter| counter.get()); +//! CertifiedCounter { +//! count, +//! certificate, +//! witness, +//! } +//! } +//! ``` + +#![warn( + elided_lifetimes_in_paths, + missing_debug_implementations, + missing_docs, + unsafe_op_in_unsafe_fn, + clippy::undocumented_unsafe_blocks, + clippy::missing_safety_doc +)] + mod hashtree; mod rbtree; diff --git a/library/ic-certified-map/src/rbtree.rs b/library/ic-certified-map/src/rbtree.rs index 26a08fabb..6878c6efb 100644 --- a/library/ic-certified-map/src/rbtree.rs +++ b/library/ic-certified-map/src/rbtree.rs @@ -6,7 +6,7 @@ use std::borrow::Cow; use std::cmp::Ordering::{self, Equal, Greater, Less}; use std::fmt; -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Color { Red, Black, @@ -25,6 +25,7 @@ impl Color { } } +/// Types that can be converted into a [`HashTree`]. pub trait AsHashTree { /// Returns the root hash of the tree without constructing it. /// Must be equivalent to `as_hash_tree().reconstruct()`. @@ -88,7 +89,7 @@ type NodeRef = Option>>; // 2. Children of a red node are black. // 3. Every path from a node goes through the same number of black // nodes. -#[derive(Clone)] +#[derive(Clone, Debug)] struct Node { key: K, value: V, @@ -186,7 +187,7 @@ impl, V: AsHashTree + 'static> Node { } } -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] enum Visit { Pre, In, @@ -194,6 +195,7 @@ enum Visit { } /// Iterator over a RbTree. +#[derive(Debug)] pub struct Iter<'a, K, V> { /// Invariants: /// 1. visit == Pre: none of the nodes in parents were visited yet. @@ -358,6 +360,7 @@ impl RbTree { } impl, V: AsHashTree + 'static> RbTree { + /// Looks up the key in the map and returns the associated value, if there is one. pub fn get(&self, key: &[u8]) -> Option<&V> { let mut root = self.root.as_ref(); while let Some(n) = root { @@ -476,6 +479,7 @@ impl, V: AsHashTree + 'static> RbTree { ) } + /// Creates an iterator over the map's keys and values. pub fn iter(&self) -> Iter<'_, K, V> { match &self.root { None => Iter { diff --git a/library/ic-ledger-types/src/lib.rs b/library/ic-ledger-types/src/lib.rs index dc491d931..dda19ef0d 100644 --- a/library/ic-ledger-types/src/lib.rs +++ b/library/ic-ledger-types/src/lib.rs @@ -1,3 +1,14 @@ +//! A library of types to communicate with the ICP ledger canister. + +#![warn( + elided_lifetimes_in_paths, + missing_debug_implementations, + missing_docs, + unsafe_op_in_unsafe_fn, + clippy::undocumented_unsafe_blocks, + clippy::missing_safety_doc +)] + use candid::{types::reference::Func, CandidType, Principal}; use ic_cdk::api::call::CallResult; use serde::{Deserialize, Serialize}; @@ -30,6 +41,7 @@ pub const MAINNET_CYCLES_MINTING_CANISTER_ID: Principal = CandidType, Serialize, Deserialize, Clone, Copy, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, )] pub struct Timestamp { + /// Number of nanoseconds from the UNIX epoch in UTC timezone. pub timestamp_nanos: u64, } @@ -134,13 +146,14 @@ impl From for Subaccount { } /// AccountIdentifier is a 32-byte array. -/// The first 4 bytes is big-endian encoding of a CRC32 checksum of the last 28 bytes. +/// The first 4 bytes is a big-endian encoding of a CRC32 checksum of the last 28 bytes. #[derive( CandidType, Serialize, Deserialize, Clone, Copy, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, )] pub struct AccountIdentifier([u8; 32]); impl AccountIdentifier { + /// Creates a new account identifier from a principal and subaccount. pub fn new(owner: &Principal, subaccount: &Subaccount) -> Self { let mut hasher = sha2::Sha224::new(); hasher.update(b"\x0Aaccount-id"); @@ -190,6 +203,7 @@ impl fmt::Display for AccountIdentifier { /// Arguments for the `account_balance` call. #[derive(CandidType, Serialize, Deserialize, Clone, Debug)] pub struct AccountBalanceArgs { + /// The account identifier to query the balance of. pub account: AccountIdentifier, } @@ -203,11 +217,24 @@ pub struct Memo(pub u64); /// Arguments for the `transfer` call. #[derive(CandidType, Serialize, Deserialize, Clone, Debug)] pub struct TransferArgs { + /// Transaction memo. + /// See docs for the [`Memo`] type. pub memo: Memo, + /// The amount that the caller wants to transfer to the destination address. pub amount: Tokens, + /// The amount that the caller pays for the transaction. + /// Must be 10000 e8s. pub fee: Tokens, + /// The subaccount from which the caller wants to transfer funds. + /// If `None`, the ledger uses the default (all zeros) subaccount to compute the source address. + /// See docs for the [`Subaccount`] type. pub from_subaccount: Option, + /// The destination account. + /// If the transfer is successful, the balance of this address increases by `amount`. pub to: AccountIdentifier, + /// The point in time when the caller created this request. + /// If `None`, the ledger uses the current IC time as the timestamp. + /// Transactions more than one day old will be rejected. pub created_at_time: Option, } @@ -220,11 +247,33 @@ pub type TransferResult = Result; /// Error of the `transfer` call. #[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub enum TransferError { - BadFee { expected_fee: Tokens }, - InsufficientFunds { balance: Tokens }, - TxTooOld { allowed_window_nanos: u64 }, + /// The fee that the caller specified in the transfer request was not the one that the ledger expects. + /// The caller can change the transfer fee to the `expected_fee` and retry the request. + BadFee { + /// The account specified by the caller doesn't have enough funds. + expected_fee: Tokens, + }, + /// The caller did not have enough ICP in the specified subaccount. + InsufficientFunds { + /// The caller's balance. + balance: Tokens, + }, + /// The request is too old. + /// The ledger only accepts requests created within a 24-hour window. + /// This is a non-recoverable error. + TxTooOld { + /// The permitted duration between `created_at_time` and now. + allowed_window_nanos: u64, + }, + /// The caller specified a `created_at_time` that is too far in the future. + /// The caller can retry the request later. + /// This may also be caused by clock desynchronization. TxCreatedInFuture, - TxDuplicate { duplicate_of: BlockIndex }, + /// The ledger has already executed the request. + TxDuplicate { + /// The index of the block containing the original transaction. + duplicate_of: BlockIndex, + }, } impl fmt::Display for TransferError { @@ -257,55 +306,84 @@ impl fmt::Display for TransferError { } } +/// The content of a ledger transaction. #[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub enum Operation { + /// Tokens were minted, usually via spawning/disbursing neuron maturity or as node operator rewards. Mint { + /// The account that the tokens were transferred to. to: AccountIdentifier, + /// The amount that was transferred. amount: Tokens, }, + /// Tokens were burned, usually to create cycles for a canister. Burn { + /// The account that sent the tokens to be burned. from: AccountIdentifier, + /// The amount that was burned. amount: Tokens, }, + /// Tokens were transferred from one account to another. Transfer { + /// The account the tokens were transferred from. from: AccountIdentifier, + /// The account the tokens were transferred to. to: AccountIdentifier, + /// The amount of tokens that were transferred. amount: Tokens, + /// The fee that was charged for the transfer. fee: Tokens, }, + /// An account approved another account to transfer tokens on its behalf. Approve { + /// The account that owns the tokens. from: AccountIdentifier, + /// The account that was enabled to spend them. spender: AccountIdentifier, // TODO: add the allowance_e8s field after the official ICRC-2 release. + /// The expiration date for this approval. expires_at: Option, + /// The fee that was charged for the approval. fee: Tokens, }, + /// An account transferred tokens from another account on its behalf, following an approval. TransferFrom { + /// The account that the tokens were transferred from. from: AccountIdentifier, + /// The account that the tokens were transferred to. to: AccountIdentifier, + /// The account that performed the transfer. spender: AccountIdentifier, + /// The amount that was transferred. amount: Tokens, + /// The fee that was charged for the transfer. fee: Tokens, }, } +/// A recorded ledger transaction. #[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub struct Transaction { + /// The memo that was provided for the transaction. pub memo: Memo, + /// The content of the transaction. pub operation: Option, /// The time at which the client of the ledger constructed the transaction. pub created_at_time: Timestamp, } +/// A single record in the ledger. #[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub struct Block { /// The hash of the parent block. pub parent_hash: Option<[u8; 32]>, + /// The transaction that occurred in this block. pub transaction: Transaction, /// The time at which the ledger constructed the block. pub timestamp: Timestamp, } +/// Arguments for the `get_blocks` function. #[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub struct GetBlocksArgs { /// The index of the first block to fetch. @@ -314,40 +392,88 @@ pub struct GetBlocksArgs { pub length: u64, } +/// Return type for the `query_blocks` function. #[derive(CandidType, Deserialize, Clone, Debug)] pub struct QueryBlocksResponse { + /// The total number of blocks in the chain. + /// If the chain length is positive, the index of the last block is `chain_length - 1`. pub chain_length: u64, /// The replica certificate for the last block hash (see [Encoding of Certificates](https://internetcomputer.org/docs/current/references/ic-interface-spec#certification-encoding)). - /// Not available when querying blocks from a canister. + /// Only available when *querying* blocks from a canister. pub certificate: Option, + /// List of blocks that were available in the ledger when it processed the call. + /// + /// The blocks form a contiguous range, with the first block having index + /// `first_block_index` (see below), and the last block having index + /// `first_block_index + blocks.len() - 1`. + /// + /// The block range can be an arbitrary sub-range of the originally requested range. pub blocks: Vec, /// The index of the first block in [QueryBlocksResponse::blocks]. + /// If the `blocks` vector is empty, the exact value of this field is not specified. pub first_block_index: BlockIndex, + /// Encoded functions for fetching archived blocks whose indices fall into the + /// requested range. + /// + /// For each entry `e` in `archived_blocks`, `e.start..e.start + e.length` is a sub-range + /// of the originally requested block range. pub archived_blocks: Vec, } +/// A function that can be called to retrieve a range of archived blocks. #[derive(CandidType, Deserialize, Clone, Debug)] pub struct ArchivedBlockRange { + /// The index of the first archived block that can be fetched using `callback`. pub start: BlockIndex, + /// The number of blocks that can be fetched using `callback`. pub length: u64, + /// The function that should be called to fetch the archived blocks. + /// The range of the blocks accessible using this function is given by the `start` + /// and `length` fields above. pub callback: QueryArchiveFn, } +/// A prefix of the block range specified in the `get_blocks` and [`query_archived_blocks`] function. #[derive(CandidType, Deserialize, Clone, Debug, PartialEq, Eq)] pub struct BlockRange { + /// A prefix of the requested block range. + /// The index of the first block is equal to [`GetBlocksArgs.start`](GetBlocksArgs). + /// + /// ## Note + /// + /// The number of blocks might be less than the requested + /// [`GetBlocksArgs.length`](GetBlocksArgs) for various reasons, for example: + /// + /// 1. The query might have hit the replica with an outdated state + /// that doesn't have the full block range yet. + /// 2. The requested range is too large to fit into a single reply. + /// + /// The list of blocks can be empty if: + /// + /// 1. [`GetBlocksArgs.length`](GetBlocksArgs) was zero. + /// 2. [`GetBlocksArgs.start`](GetBlocksArgs) was larger than the last block known to the canister. pub blocks: Vec, } +/// The return type of `get_blocks`. pub type GetBlocksResult = Result; +/// An error indicating that the arguments passed to `get_blocks` or [`query_archived_blocks`] were invalid. #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, CandidType)] pub enum GetBlocksError { + /// The [`GetBlocksArgs.start`](GetBlocksArgs) argument was smaller than the first block + /// served by the canister that received the request. BadFirstBlockIndex { + /// The index that was requested. requested_index: BlockIndex, + /// The minimum index that can be requested, for this particular call. first_valid_index: BlockIndex, }, + /// Reserved for future use. Other { + /// A machine-readable error code. error_code: u64, + /// A human-readable error message. error_message: String, }, } @@ -375,6 +501,8 @@ impl fmt::Display for GetBlocksError { } } +/// Function type used by `query_blocks` for fetching blocks from the archive. +/// Has the signature `(`[`GetBlocksArgs`]`) -> (`[`GetBlocksResult`]`)`. #[derive(Debug, Clone, Deserialize)] #[serde(transparent)] pub struct QueryArchiveFn(Func); @@ -460,8 +588,10 @@ pub async fn transfer( Ok(result) } +/// Return type of the `token_symbol` function. #[derive(Serialize, Deserialize, CandidType, Clone, Hash, Debug, PartialEq, Eq)] pub struct Symbol { + /// A token's trade symbol, e.g. 'ICP'. pub symbol: String, } @@ -517,6 +647,36 @@ pub async fn query_blocks( Ok(result) } +/// Continues a query started in [`query_blocks`] by calling its returned archive function. +/// +/// # Example +/// +/// ```no_run +/// use candid::Principal; +/// use ic_cdk::api::call::CallResult; +/// use ic_ledger_types::{BlockIndex, Block, GetBlocksArgs, query_blocks, query_archived_blocks}; +/// +/// async fn query_one_block(ledger: Principal, block_index: BlockIndex) -> CallResult> { +/// let args = GetBlocksArgs { start: block_index, length: 1 }; +/// +/// let blocks_result = query_blocks(ledger, args.clone()).await?; +/// +/// if blocks_result.blocks.len() >= 1 { +/// debug_assert_eq!(blocks_result.first_block_index, block_index); +/// return Ok(blocks_result.blocks.into_iter().next()); +/// } +/// +/// if let Some(func) = blocks_result +/// .archived_blocks +/// .into_iter() +/// .find_map(|b| (b.start <= block_index && (block_index - b.start) < b.length).then(|| b.callback)) { +/// match query_archived_blocks(&func, args).await? { +/// Ok(range) => return Ok(range.blocks.into_iter().next()), +/// _ => (), +/// } +/// } +/// Ok(None) +/// } pub async fn query_archived_blocks( func: &QueryArchiveFn, args: GetBlocksArgs, diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index 00410db42..fe598404d 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -20,6 +20,15 @@ //! //! * [`import`](attr.import.html) +#![warn( + elided_lifetimes_in_paths, + missing_debug_implementations, + missing_docs, + unsafe_op_in_unsafe_fn, + clippy::undocumented_unsafe_blocks, + clippy::missing_safety_doc +)] + use proc_macro::TokenStream; use std::sync::atomic::{AtomicU32, Ordering}; use syn::Error; diff --git a/src/ic-cdk-timers/src/lib.rs b/src/ic-cdk-timers/src/lib.rs index 5ad62b6ee..49684ecf5 100644 --- a/src/ic-cdk-timers/src/lib.rs +++ b/src/ic-cdk-timers/src/lib.rs @@ -9,6 +9,15 @@ //! # } //! ``` +#![warn( + elided_lifetimes_in_paths, + missing_debug_implementations, + missing_docs, + unsafe_op_in_unsafe_fn, + clippy::undocumented_unsafe_blocks, + clippy::missing_safety_doc +)] + use std::{ cell::{Cell, RefCell}, cmp::Ordering, diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index fcaee66d5..b2cbda8b4 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -407,6 +407,7 @@ pub fn reject(message: &str) { } /// An io::Write for message replies. +#[derive(Debug, Copy, Clone)] pub struct CallReplyWriter; impl std::io::Write for CallReplyWriter { diff --git a/src/ic-cdk/src/api/stable/canister.rs b/src/ic-cdk/src/api/stable/canister.rs index 020047eb9..12186bf4c 100644 --- a/src/ic-cdk/src/api/stable/canister.rs +++ b/src/ic-cdk/src/api/stable/canister.rs @@ -3,7 +3,7 @@ use super::*; /// A standard implementation of [`StableMemory`]. /// /// Useful for creating [`StableWriter`] and [`StableReader`]. -#[derive(Default)] +#[derive(Default, Debug, Copy, Clone)] pub struct CanisterStableMemory {} impl StableMemory for CanisterStableMemory { diff --git a/src/ic-cdk/src/api/stable/mod.rs b/src/ic-cdk/src/api/stable/mod.rs index b544256ff..9ef7e7c11 100644 --- a/src/ic-cdk/src/api/stable/mod.rs +++ b/src/ic-cdk/src/api/stable/mod.rs @@ -69,7 +69,7 @@ pub enum StableMemoryError { } impl fmt::Display for StableMemoryError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::OutOfMemory => f.write_str("Out of memory"), Self::OutOfBounds => f.write_str("Read exceeds allocated memory"), @@ -141,7 +141,7 @@ pub fn stable_bytes() -> Vec { /// /// Will attempt to grow the memory as it writes, /// and keep offsets and total capacity. - +#[derive(Debug)] pub struct StableIO { /// The offset of the next write. offset: A, @@ -292,6 +292,7 @@ impl_stable_io!(u64); /// /// Will attempt to grow the memory as it writes, /// and keep offsets and total capacity. +#[derive(Debug)] pub struct StableWriter(StableIO); #[allow(clippy::derivable_impls)] @@ -364,6 +365,7 @@ impl From> for StableWriter { /// /// Note: Each call to grow or write to stable memory is a relatively expensive operation, so pick a /// buffer size large enough to avoid excessive calls to stable memory. +#[derive(Debug)] pub struct BufferedStableWriter { inner: io::BufWriter>, } @@ -409,6 +411,7 @@ impl io::Seek for BufferedStableWriter { // A reader to the stable memory. /// /// Keeps an offset and reads off stable memory consecutively. +#[derive(Debug)] pub struct StableReader(StableIO); #[allow(clippy::derivable_impls)] @@ -466,6 +469,7 @@ impl From> for StableReader { } /// A reader to the stable memory which reads bytes a chunk at a time as each chunk is required. +#[derive(Debug)] pub struct BufferedStableReader { inner: io::BufReader>, } diff --git a/src/ic-cdk/src/lib.rs b/src/ic-cdk/src/lib.rs index f57bf0417..0b4d38717 100644 --- a/src/ic-cdk/src/lib.rs +++ b/src/ic-cdk/src/lib.rs @@ -1,4 +1,6 @@ #![warn( + elided_lifetimes_in_paths, + missing_debug_implementations, missing_docs, unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks, diff --git a/src/ic0/src/ic0.rs b/src/ic0/src/ic0.rs index bac978350..0ac10cd38 100644 --- a/src/ic0/src/ic0.rs +++ b/src/ic0/src/ic0.rs @@ -64,7 +64,7 @@ extern "C" { #[cfg(not(target_arch = "wasm32"))] #[allow(unused_variables)] -#[allow(clippy::missing_safety_doc)] +#[allow(clippy::missing_safety_doc, missing_docs)] #[allow(clippy::too_many_arguments)] mod non_wasm { pub unsafe fn msg_arg_data_size() -> i32 { diff --git a/src/ic0/src/lib.rs b/src/ic0/src/lib.rs index fc803c53a..935c110cd 100644 --- a/src/ic0/src/lib.rs +++ b/src/ic0/src/lib.rs @@ -1,2 +1,13 @@ +//! Raw bindings to the [Internet Computer system API](https://internetcomputer.org/docs/current/references/ic-interface-spec#system-api-imports). + +#![warn( + elided_lifetimes_in_paths, + missing_debug_implementations, + missing_docs, + unsafe_op_in_unsafe_fn, + clippy::undocumented_unsafe_blocks, + clippy::missing_safety_doc +)] + mod ic0; pub use crate::ic0::*; From 01d987af56d1923c4da5fdc1a80c1f0ed224b758 Mon Sep 17 00:00:00 2001 From: Andriy Berestovskyy <91958447+dfinity-berestovskyy@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:08:19 +0100 Subject: [PATCH 138/234] chore: update timers readme and links (#377) --- README.md | 2 ++ docs/modules/rust-guide/pages/rust-intro.adoc | 2 ++ src/ic-cdk-macros/README.md | 2 +- src/ic-cdk-timers/README.md | 29 +++++++++++++++++-- src/ic-cdk-timers/src/lib.rs | 2 +- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c5134335c..c576179ac 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ This repo provides libraries and tools to facilitate developing canisters in Rus Bindings of the System API. - [`ic-cdk-macros`](src/ic-cdk-macros): Annotate functions with attribute macros to make them exposed public interfaces. +- [`ic-cdk-timers`](src/ic-cdk-timers): +The library implements multiple and periodic timers. - [`ic-certified-map`](library/ic-certified-map): An implementation of map which support *certified queries*. - [`ic-ledger-types`](library/ic-ledger-types): diff --git a/docs/modules/rust-guide/pages/rust-intro.adoc b/docs/modules/rust-guide/pages/rust-intro.adoc index 8cdfa225c..dad04b8e8 100644 --- a/docs/modules/rust-guide/pages/rust-intro.adoc +++ b/docs/modules/rust-guide/pages/rust-intro.adoc @@ -25,6 +25,8 @@ Collectively, these tools are referred to as the {cdk-long-name} and consist of |`+ic-cdk-macros+` |The `+ic-cdk-macros+` library defines the procedural macros that facilitate building operation endpoints and APIs. This library includes macros for `+update+`, `+query+`, `+import+` and other important operations. +|`+ic-cdk-timers+` |The `+ic-cdk-timers+` library implements multiple and periodic timers. + |`+ic-cdk-optimizer+` |The `+ic-cdk-optimizer+` is a helper library used to reduce the size of WebAssembly modules. |=== diff --git a/src/ic-cdk-macros/README.md b/src/ic-cdk-macros/README.md index 03ec86ee3..95c912264 100644 --- a/src/ic-cdk-macros/README.md +++ b/src/ic-cdk-macros/README.md @@ -8,4 +8,4 @@ [![Downloads](https://img.shields.io/crates/d/ic-cdk-macros.svg)](https://crates.io/crates/ic-cdk-macros) [![CI](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml) -This crate provide attribute macros, with which you can annotate regular rust functions to be public interfaces of a canister. +This crate provides attribute macros, with which you can annotate regular rust functions to be public interfaces of a canister. diff --git a/src/ic-cdk-timers/README.md b/src/ic-cdk-timers/README.md index 4539f98f7..eaa5766ba 100644 --- a/src/ic-cdk-timers/README.md +++ b/src/ic-cdk-timers/README.md @@ -1,9 +1,32 @@ -# ic-cdk-timers +Rust CDK Timers Library +======================= -A library for Internet Computer canisters to schedule one-shot or repeating timers, to execute a function at some point in the future. +[![Documentation](https://docs.rs/ic-cdk-timers/badge.svg)](https://docs.rs/ic-cdk-timers/) +[![Crates.io](https://img.shields.io/crates/v/ic-cdk-timers.svg)](https://crates.io/crates/ic-cdk-timers) +[![License](https://img.shields.io/crates/l/ic-cdk-timers.svg)](https://github.com/dfinity/cdk-rs/blob/main/src/ic-cdk-timers/LICENSE) +[![Downloads](https://img.shields.io/crates/d/ic-cdk-timers.svg)](https://crates.io/crates/ic-cdk-timers) +[![CI](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml) -## Example +This crate provides a library to schedule multiple and periodic tasks on the Internet Computer. + +Example +------- + +In `Cargo.toml`: + +```toml +[dependencies] +ic-cdk-timers = "0.1.1" +``` + +To schedule a one-shot task to be executed 1s later: ```rust ic_cdk_timers::set_timer(Duration::from_secs(1), || ic_cdk::println!("Hello from the future!")); ``` + +References +---------- + +1. Internet Computer Developer Guide: [Periodic Tasks and Timers](https://internetcomputer.org/docs/current/developer-docs/backend/periodic-tasks) +2. Example: [Periodic Tasks and Timers](https://github.com/dfinity/examples/tree/master/rust/periodic_tasks) (compares timers and heartbeats). diff --git a/src/ic-cdk-timers/src/lib.rs b/src/ic-cdk-timers/src/lib.rs index 49684ecf5..a25ec0336 100644 --- a/src/ic-cdk-timers/src/lib.rs +++ b/src/ic-cdk-timers/src/lib.rs @@ -1,4 +1,4 @@ -//! A library for Internet Computer canisters to schedule one-shot or repeating timers, to execute a function at some point in the future. +//! The library implements multiple and periodic timers on the Internet Computer. //! //! # Example //! From 9856ff616bd156941ab6ca0b557a674e057bef62 Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Wed, 1 Mar 2023 17:15:51 +0000 Subject: [PATCH 139/234] fix: incorrect types in error messages (#355) * fix: incorrect types in error messages * Update changelog * Add PR number to changelog message Co-authored-by: Linwei Shang --- src/ic-cdk/CHANGELOG.md | 2 ++ src/ic-cdk/src/api/call.rs | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index a5e792cda..85a7f599a 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +- Fix type name in error message when a deserialization error occurs after making a canister-to-canister call. (#355) + ## [0.7.1] - 2023-02-22 ### Fixed diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index b2cbda8b4..0eef7c085 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -331,7 +331,7 @@ pub fn call ArgumentDecoder<'a>>( let fut = call_raw(id, method, &args_raw, 0); async { let bytes = fut.await?; - decode_args(&bytes).map_err(decoder_error_to_reject::) + decode_args(&bytes).map_err(decoder_error_to_reject::) } } @@ -346,7 +346,7 @@ pub fn call_with_payment ArgumentDecoder<'a>>( let fut = call_raw(id, method, &args_raw, cycles); async { let bytes = fut.await?; - decode_args(&bytes).map_err(decoder_error_to_reject::) + decode_args(&bytes).map_err(decoder_error_to_reject::) } } @@ -361,7 +361,7 @@ pub fn call_with_payment128 ArgumentDecoder<'a>>( let fut = call_raw128(id, method, &args_raw, cycles); async { let bytes = fut.await?; - decode_args(&bytes).map_err(decoder_error_to_reject::) + decode_args(&bytes).map_err(decoder_error_to_reject::) } } From 6a15aa1616bcfdfdc4c120d17d37a089f5700c36 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 1 Mar 2023 13:51:45 -0500 Subject: [PATCH 140/234] bump version and changelog (#378) --- library/ic-certified-map/CHANGELOG.md | 4 ++++ library/ic-certified-map/Cargo.toml | 2 +- library/ic-ledger-types/CHANGELOG.md | 4 ++++ library/ic-ledger-types/Cargo.toml | 2 +- src/ic-cdk-macros/CHANGELOG.md | 13 +++++++++++++ src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-timers/CHANGELOG.md | 2 ++ src/ic-cdk-timers/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 4 ++++ src/ic-cdk/Cargo.toml | 2 +- 10 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 src/ic-cdk-macros/CHANGELOG.md diff --git a/library/ic-certified-map/CHANGELOG.md b/library/ic-certified-map/CHANGELOG.md index da7b6dfde..20e8b933f 100644 --- a/library/ic-certified-map/CHANGELOG.md +++ b/library/ic-certified-map/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [0.3.4] - 2023-03-01 +### Added +- Derive common traits for structs. + ## [0.3.3] - 2023-02-22 ### Fixed - Update links in doc. diff --git a/library/ic-certified-map/Cargo.toml b/library/ic-certified-map/Cargo.toml index e5d7c2c7d..1832e3eba 100644 --- a/library/ic-certified-map/Cargo.toml +++ b/library/ic-certified-map/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-certified-map" -version = "0.3.3" +version = "0.3.4" edition = "2021" authors = ["DFINITY Stiftung "] description = "Merkleized map data structure." diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index f41af406a..d24fa15bf 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.4.2] - 2023-03-01 +### Fixed +- Fill missing docs. + ## [0.4.1] - 2023-02-22 ### Fixed - Use automatic link in document. diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index ae841a5c8..6af0ee907 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.4.1" +version = "0.4.2" edition = "2021" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md new file mode 100644 index 000000000..2e09893ed --- /dev/null +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [unreleased] + +## [0.6.10] - 2023-03-01 + +### Changed + +- Update lint settings. diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index c544ead22..5c707f0fc 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.6.9" # no need to sync with ic-cdk +version = "0.6.10" # no need to sync with ic-cdk authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index a9c09a3d9..7d831a982 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.1.2] - 2023-03-01 + ## [0.1.1] - 2023-02-22 ### Fixed diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index 942f027f0..1b1305365 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.1.1" +version = "0.1.2" authors = ["DFINITY Stiftung "] edition = "2021" description = "Timers library for the Rust CDK." diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 85a7f599a..ce0358f69 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.7.2] - 2023-03-01 + +### Fixed + - Fix type name in error message when a deserialization error occurs after making a canister-to-canister call. (#355) ## [0.7.1] - 2023-02-22 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 5dead825b..5e58938fa 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.7.1" +version = "0.7.2" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." From 2e877f5be3dd40a945c99a72aca1e6b08e9785b9 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Wed, 1 Mar 2023 14:52:37 -0800 Subject: [PATCH 141/234] fix: call futures implement Send + Sync (#379) --- src/ic-cdk/CHANGELOG.md | 6 ++++- src/ic-cdk/Cargo.toml | 2 +- src/ic-cdk/src/api/call.rs | 55 +++++++++++++++++++------------------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index ce0358f69..6a21c5b57 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -4,7 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [unreleased] +## [0.7.3] = 2023-03-01 + +### Fixed + +- Addressed a compatibility error in the signature of the `call` family of functions. (#379) ## [0.7.2] - 2023-03-01 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 5e58938fa..156790991 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.7.2" +version = "0.7.3" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 0eef7c085..4f5914d1d 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -3,12 +3,11 @@ use crate::api::trap; use candid::utils::{ArgumentDecoder, ArgumentEncoder}; use candid::{decode_args, encode_args, write_args, CandidType, Deserialize, Principal}; use serde::ser::Error; -use std::cell::RefCell; use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; -use std::rc::Rc; use std::sync::atomic::Ordering; +use std::sync::{Arc, RwLock}; use std::task::{Context, Poll, Waker}; /// Rejection code from calling another canister. @@ -61,7 +60,7 @@ struct CallFutureState { } struct CallFuture { - state: Rc>, + state: Arc>, } impl Future for CallFuture { @@ -69,7 +68,7 @@ impl Future for CallFuture { fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll { let self_ref = Pin::into_inner(self); - let mut state = self_ref.state.borrow_mut(); + let mut state = self_ref.state.write().unwrap(); if let Some(result) = state.result.take() { Poll::Ready(result) @@ -86,18 +85,18 @@ impl Future for CallFuture { /// /// # Safety /// -/// This function must only be passed to the IC with a pointer from Rc::into_raw as userdata. -unsafe fn callback(state_ptr: *const RefCell) { - // SAFETY: This function is only ever called by the IC, and we only ever pass a Rc as userdata. - let state = unsafe { Rc::from_raw(state_ptr) }; +/// This function must only be passed to the IC with a pointer from Arc::into_raw as userdata. +unsafe fn callback(state_ptr: *const RwLock) { + // SAFETY: This function is only ever called by the IC, and we only ever pass a Arc as userdata. + let state = unsafe { Arc::from_raw(state_ptr) }; // Make sure to un-borrow_mut the state. { - state.borrow_mut().result = Some(match reject_code() { + state.write().unwrap().result = Some(match reject_code() { RejectionCode::NoError => Ok(arg_data_raw()), n => Err((n, reject_message())), }); } - let w = state.borrow_mut().waker.take(); + let w = state.write().unwrap().waker.take(); if let Some(waker) = w { // This is all to protect this little guy here which will call the poll() which // borrow_mut() the state as well. So we need to be careful to not double-borrow_mut. @@ -111,10 +110,10 @@ unsafe fn callback(state_ptr: *const RefCell) { /// /// # Safety /// -/// This function must only be passed to the IC with a pointer from Rc::into_raw as userdata. -unsafe fn cleanup(state_ptr: *const RefCell) { - // SAFETY: This function is only ever called by the IC, and we only ever pass a Rc as userdata. - let state = unsafe { Rc::from_raw(state_ptr) }; +/// This function must only be passed to the IC with a pointer from Arc::into_raw as userdata. +unsafe fn cleanup(state_ptr: *const RwLock) { + // SAFETY: This function is only ever called by the IC, and we only ever pass a Arc as userdata. + let state = unsafe { Arc::from_raw(state_ptr) }; // We set the call result, even though it won't be read on the // default executor, because we can't guarantee it was called on // our executor. However, we are not allowed to inspect @@ -122,9 +121,9 @@ unsafe fn cleanup(state_ptr: *const RefCell) { // result to a reject. // // Borrowing does not trap - the rollback from the - // previous trap ensures that the RefCell can be borrowed again. - state.borrow_mut().result = Some(Err((RejectionCode::NoError, "cleanup".to_string()))); - let w = state.borrow_mut().waker.take(); + // previous trap ensures that the RwLock can be borrowed again. + state.write().unwrap().result = Some(Err((RejectionCode::NoError, "cleanup".to_string()))); + let w = state.write().unwrap().waker.take(); if let Some(waker) = w { // Flag that we do not want to actually wake the task - we // want to drop it *without* executing it. @@ -233,7 +232,7 @@ pub fn call_raw( method: &str, args_raw: &[u8], payment: u64, -) -> impl Future>> { +) -> impl Future>> + Send + Sync { call_raw_internal(id, method, args_raw, move || { if payment > 0 { // SAFETY: ic0.call_cycles_add is always safe to call. @@ -251,7 +250,7 @@ pub fn call_raw128( method: &str, args_raw: &[u8], payment: u128, -) -> impl Future>> { +) -> impl Future>> + Send + Sync { call_raw_internal(id, method, args_raw, move || { add_payment(payment); }) @@ -262,21 +261,21 @@ fn call_raw_internal( method: &str, args_raw: &[u8], payment_func: impl FnOnce(), -) -> impl Future>> { +) -> impl Future>> + Send + Sync { let callee = id.as_slice(); - let state = Rc::new(RefCell::new(CallFutureState { + let state = Arc::new(RwLock::new(CallFutureState { result: None, waker: None, })); - let state_ptr = Rc::into_raw(state.clone()); + let state_ptr = Arc::into_raw(state.clone()); // SAFETY: // `callee`, being &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_new. // `method`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.call_new. // `callback` is a function with signature (env : i32) -> () and therefore can be called as both reply and reject fn for ic0.call_new. - // `state_ptr` is a pointer created via Rc::into_raw, and can therefore be passed as the userdata for `callback`. + // `state_ptr` is a pointer created via Arc::into_raw, and can therefore be passed as the userdata for `callback`. // `args`, being a &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_data_append. // `cleanup` is a function with signature (env : i32) -> () and therefore can be called as a cleanup fn for ic0.call_on_cleanup. - // `state_ptr` is a pointer created via Rc::into_raw, and can therefore be passed as the userdata for `cleanup`. + // `state_ptr` is a pointer created via Arc::into_raw, and can therefore be passed as the userdata for `cleanup`. // ic0.call_perform is always safe to call. let err_code = unsafe { ic0::call_new( @@ -298,7 +297,7 @@ fn call_raw_internal( // 0 is a special error code meaning call_simple call succeeded. if err_code != 0 { - let mut state = state.borrow_mut(); + let mut state = state.write().unwrap(); state.result = Some(Err(( RejectionCode::from(err_code), "Couldn't send message".to_string(), @@ -326,7 +325,7 @@ pub fn call ArgumentDecoder<'a>>( id: Principal, method: &str, args: T, -) -> impl Future> { +) -> impl Future> + Send + Sync { let args_raw = encode_args(args).expect("Failed to encode arguments."); let fut = call_raw(id, method, &args_raw, 0); async { @@ -341,7 +340,7 @@ pub fn call_with_payment ArgumentDecoder<'a>>( method: &str, args: T, cycles: u64, -) -> impl Future> { +) -> impl Future> + Send + Sync { let args_raw = encode_args(args).expect("Failed to encode arguments."); let fut = call_raw(id, method, &args_raw, cycles); async { @@ -356,7 +355,7 @@ pub fn call_with_payment128 ArgumentDecoder<'a>>( method: &str, args: T, cycles: u128, -) -> impl Future> { +) -> impl Future> + Send + Sync { let args_raw = encode_args(args).expect("Failed to encode arguments."); let fut = call_raw128(id, method, &args_raw, cycles); async { From 573d040c28e574fd39a65953c09fb9faad2dd043 Mon Sep 17 00:00:00 2001 From: mathematician Date: Thu, 9 Mar 2023 02:16:42 +0200 Subject: [PATCH 142/234] feat: WASM_PAGE_SIZE_IN_BYTES made pub (#380) * Update mod.rs Add `pub` to `WASM_PAGE_SIZE_IN_BYTES` definition * Update mod.rs Change documented. * Update CHANGELOG.md WASM_PAGE_SIZE_IN_BYTES made pub * bump dfx in ci --------- Co-authored-by: Victor Porton Co-authored-by: Linwei Shang --- .github/workflows/examples.yml | 2 +- src/ic-cdk/CHANGELOG.md | 3 +++ src/ic-cdk/src/api/stable/mod.rs | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 039e68c46..5ded616b4 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -12,7 +12,7 @@ concurrency: env: rust-version: 1.66.1 - dfx-version: 0.12.0-beta.6 + dfx-version: 0.13.1 jobs: test: diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 6a21c5b57..4836b780c 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### Added +- `WASM_PAGE_SIZE_IN_BYTES` made `pub`. + ## [0.7.3] = 2023-03-01 ### Fixed diff --git a/src/ic-cdk/src/api/stable/mod.rs b/src/ic-cdk/src/api/stable/mod.rs index 9ef7e7c11..447313df3 100644 --- a/src/ic-cdk/src/api/stable/mod.rs +++ b/src/ic-cdk/src/api/stable/mod.rs @@ -10,7 +10,8 @@ mod tests; pub use canister::CanisterStableMemory; use std::{error, fmt, io}; -const WASM_PAGE_SIZE_IN_BYTES: usize = 64 * 1024; // 64KB +/// WASM page size in bytes. +pub const WASM_PAGE_SIZE_IN_BYTES: usize = 64 * 1024; // 64KB static CANISTER_STABLE_MEMORY: CanisterStableMemory = CanisterStableMemory {}; From a350e4211ccb2098b9f090ca44b7c310466a4f02 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 21 Mar 2023 16:54:54 -0400 Subject: [PATCH 143/234] feat: http_request_with_cycles (#381) * Add http_request_with_cycles and doc * changelog * clone * remove missing_doc lint for ic0 --- .../management_canister/src/caller/lib.rs | 14 ++++++++- src/ic-cdk/CHANGELOG.md | 6 +++- .../api/management_canister/http_request.rs | 30 +++++++++++++++++-- src/ic0/src/lib.rs | 1 - 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index 8003e4212..13d3b53da 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -97,7 +97,19 @@ mod http_request { body: None, transform: Some(TransformContext::new(transform, vec![])), }; - let response = http_request(arg).await.unwrap().0; + let response = http_request(arg.clone()).await.unwrap().0; + assert_eq!(response.status, 200); + assert_eq!( + response.headers.get(0), + Some(&HttpHeader { + name: "custom-header".to_string(), + value: "test".to_string(), + }) + ); + let response = http_request_with_cycles(arg, 718500000u128) + .await + .unwrap() + .0; assert_eq!(response.status, 200); assert_eq!( response.headers.get(0), diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 4836b780c..32d7bd762 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -4,8 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [unreleased] + ### Added -- `WASM_PAGE_SIZE_IN_BYTES` made `pub`. + +- `WASM_PAGE_SIZE_IN_BYTES` made `pub`. (#380) +- `http_request_with_cycles`. (#381) ## [0.7.3] = 2023-03-01 diff --git a/src/ic-cdk/src/api/management_canister/http_request.rs b/src/ic-cdk/src/api/management_canister/http_request.rs index 0bb378f27..b28fc57a5 100644 --- a/src/ic-cdk/src/api/management_canister/http_request.rs +++ b/src/ic-cdk/src/api/management_canister/http_request.rs @@ -157,10 +157,13 @@ pub struct HttpResponse { /// Make an HTTP request to a given URL and return the HTTP response, possibly after a transformation. /// +/// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). +/// /// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. -/// See source code for the exact function. +/// This method handles the cycles cost calculation under the hood which assuming the canister is on a 13-node Application Subnet. +/// If the canister is on a 34-node Application Subnets, you may have to compute the cost by yourself and call [http_request_with_cycles] instead. /// -/// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). +/// Check [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs) for more details. pub async fn http_request(arg: CanisterHttpRequestArgument) -> CallResult<(HttpResponse,)> { let cycles = http_request_required_cycles(&arg); call_with_payment128( @@ -172,13 +175,34 @@ pub async fn http_request(arg: CanisterHttpRequestArgument) -> CallResult<(HttpR .await } +/// Make an HTTP request to a given URL and return the HTTP response, possibly after a transformation. +/// +/// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). +/// +/// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. +/// Check [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs) for more details. +/// +/// If the canister is on a 13-node Application Subnet, you can call [http_request] instead which handles cycles cost calculation under the hood. +pub async fn http_request_with_cycles( + arg: CanisterHttpRequestArgument, + cycles: u128, +) -> CallResult<(HttpResponse,)> { + call_with_payment128( + Principal::management_canister(), + "http_request", + (arg,), + cycles, + ) + .await +} + fn http_request_required_cycles(arg: &CanisterHttpRequestArgument) -> u128 { let max_response_bytes = match arg.max_response_bytes { Some(ref n) => *n as u128, None => 2 * 1024 * 1024u128, // default 2MiB }; let arg_raw = candid::utils::encode_args((arg,)).expect("Failed to encode arguments."); - // TODO: this formula should be documented somewhere + // The coefficients can be found in [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs). // 12 is "http_request".len(). 400_000_000u128 + 100_000u128 * (arg_raw.len() as u128 + 12 + max_response_bytes) } diff --git a/src/ic0/src/lib.rs b/src/ic0/src/lib.rs index 935c110cd..7609219bc 100644 --- a/src/ic0/src/lib.rs +++ b/src/ic0/src/lib.rs @@ -3,7 +3,6 @@ #![warn( elided_lifetimes_in_paths, missing_debug_implementations, - missing_docs, unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks, clippy::missing_safety_doc From b590d63045d1ba9449b7cd96dbec4af6613b28e3 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 21 Mar 2023 18:22:09 -0400 Subject: [PATCH 144/234] ic-cdk v0.7.4 (#382) --- src/ic-cdk/CHANGELOG.md | 4 +++- src/ic-cdk/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 32d7bd762..e1ac9129b 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,12 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.7.4] - 2023-03-21 + ### Added - `WASM_PAGE_SIZE_IN_BYTES` made `pub`. (#380) - `http_request_with_cycles`. (#381) -## [0.7.3] = 2023-03-01 +## [0.7.3] - 2023-03-01 ### Fixed diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 156790991..dc9b84c0a 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.7.3" +version = "0.7.4" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." From f4d48dc181a23758df64fbee6be27577a52e6604 Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Mon, 3 Apr 2023 14:37:43 +0200 Subject: [PATCH 145/234] docs: fix link to documentation site of the IC (#384) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c576179ac..145f363a1 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ You may be looking for: -- [Documentation Site of the Internet Computer](https://smartcontracts.org/) +- [Documentation Site of the Internet Computer](https://internetcomputer.org/docs) - [Tutorials of Rust CDK](https://internetcomputer.org/docs/current/developer-docs/build/cdks/cdk-rs-dfinity/) - [Examples](https://github.com/dfinity/cdk-rs/tree/main/examples) - [`dfx` for managing IC projects](https://github.com/dfinity/sdk) From 24bdf5ee37399c4e27ad329880c79733f6454f27 Mon Sep 17 00:00:00 2001 From: Severin Siffert Date: Tue, 4 Apr 2023 12:07:15 +0200 Subject: [PATCH 146/234] feat: add ic0.is_controller to ic0 and cdk-rs (#383) --- src/ic-cdk/CHANGELOG.md | 4 ++++ src/ic-cdk/src/api/mod.rs | 7 +++++++ src/ic0/ic0.txt | 1 + src/ic0/src/ic0.rs | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index e1ac9129b..e3e5f8c8a 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Added + +- `ic0.is_controller` as a public function. (#383) + ## [0.7.4] - 2023-03-21 ### Added diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index f758231e2..1ce2f9daa 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -133,3 +133,10 @@ pub fn canister_version() -> u64 { // SAFETY: ic0.canister_version is always safe to call. unsafe { ic0::canister_version() as u64 } } + +/// Determine if a Principal is a controller of the canister. +pub fn is_controller(principal: &Principal) -> bool { + let slice = principal.as_slice(); + // SAFETY: `principal.as_bytes()`, being `&[u8]`, is a readable sequence of bytes and therefore safe to pass to `ic0.is_controller`. + unsafe { ic0::is_controller(slice.as_ptr() as i32, slice.len() as i32) != 0 } +} diff --git a/src/ic0/ic0.txt b/src/ic0/ic0.txt index 0c9cae2ac..1ea8594a0 100644 --- a/src/ic0/ic0.txt +++ b/src/ic0/ic0.txt @@ -62,6 +62,7 @@ ic0.data_certificate_copy : (dst: i32, offset: i32, size: i32) -> (); // * ic0.time : () -> (timestamp : i64); // * ic0.global_timer_set : (timestamp : i64) -> i64; // I U Ry Rt C T ic0.performance_counter : (counter_type : i32) -> (counter : i64); // * s +ic0.is_controller: (src: i32, size: i32) -> (result: i32); // * s ic0.debug_print : (src : i32, size : i32) -> (); // * s ic0.trap : (src : i32, size : i32) -> (); // * s \ No newline at end of file diff --git a/src/ic0/src/ic0.rs b/src/ic0/src/ic0.rs index 0ac10cd38..f68971b45 100644 --- a/src/ic0/src/ic0.rs +++ b/src/ic0/src/ic0.rs @@ -58,6 +58,7 @@ extern "C" { pub fn time() -> i64; pub fn global_timer_set(timestamp: i64) -> i64; pub fn performance_counter(counter_type: i32) -> i64; + pub fn is_controller(src: i32, size: i32) -> i32; pub fn debug_print(src: i32, size: i32); pub fn trap(src: i32, size: i32); } @@ -220,6 +221,9 @@ mod non_wasm { pub unsafe fn trap(src: i32, size: i32) { panic!("trap should only be called inside canisters."); } + pub unsafe fn is_controller(src: i32, size: i32) -> i32 { + panic!("is_controller should only be called inside canisters."); + } } #[cfg(not(target_arch = "wasm32"))] From f69356d75db8699ed162ce7b003a13cdcd9d2398 Mon Sep 17 00:00:00 2001 From: Dimitris Sarlis Date: Mon, 24 Apr 2023 20:31:47 +0200 Subject: [PATCH 147/234] chore: Improve doc comments for max_response_bytes (#387) * chore: Improve doc comments for max_response_bytes * Add link to documentation --------- Co-authored-by: Linwei Shang --- src/ic-cdk/src/api/management_canister/http_request.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ic-cdk/src/api/management_canister/http_request.rs b/src/ic-cdk/src/api/management_canister/http_request.rs index b28fc57a5..9009717fa 100644 --- a/src/ic-cdk/src/api/management_canister/http_request.rs +++ b/src/ic-cdk/src/api/management_canister/http_request.rs @@ -131,6 +131,10 @@ pub struct CanisterHttpRequestArgument { /// The requested URL. pub url: String, /// The maximal size of the response in bytes. If None, 2MiB will be the limit. + /// This value affects the cost of the http request and it is highly recommended + /// to set it as low as possible to avoid unnecessary extra costs. + /// See also the pricing section of HTTP outcalls documentation at + /// https://internetcomputer.org/docs/current/developer-docs/integrations/http_requests/http_requests-how-it-works#pricing. pub max_response_bytes: Option, /// The method of HTTP request. pub method: HttpMethod, From 1b7cf27ec8c3bc373a025d6201aa069f815a2684 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Wed, 3 May 2023 12:00:03 -0700 Subject: [PATCH 148/234] feat: Implement closure-based http transform API (#385) * Implement closure-based HTTP transform API * Update ic0.rs for warnings * Update changelog * Update example * doc lint * Update example to include captured context * Add separate constructor function to TransformContext * Rename crate feature and document `transform` field * Update src/ic-cdk/src/api/management_canister/http_request.rs Co-authored-by: Linwei Shang * Update src/ic-cdk/src/api/management_canister/http_request.rs Co-authored-by: Linwei Shang * Better assertion message --------- Co-authored-by: Linwei Shang --- .../management_canister/src/caller/Cargo.toml | 2 +- .../management_canister/src/caller/lib.rs | 59 +++---- src/ic-cdk/CHANGELOG.md | 4 + src/ic-cdk/Cargo.toml | 11 +- .../api/management_canister/http_request.rs | 167 +++++++++++++----- src/ic0/src/ic0.rs | 8 +- 6 files changed, 170 insertions(+), 81 deletions(-) diff --git a/examples/management_canister/src/caller/Cargo.toml b/examples/management_canister/src/caller/Cargo.toml index 6f5097ef1..ed0d83eb9 100644 --- a/examples/management_canister/src/caller/Cargo.toml +++ b/examples/management_canister/src/caller/Cargo.toml @@ -10,6 +10,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk" } +ic-cdk = { path = "../../../../src/ic-cdk", features = ["transform-closure"] } ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } sha2 = "0.10" diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index 13d3b53da..86d1b1970 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -95,41 +95,36 @@ mod http_request { method: HttpMethod::GET, headers: vec![], body: None, - transform: Some(TransformContext::new(transform, vec![])), + transform: None, }; - let response = http_request(arg.clone()).await.unwrap().0; + let header = HttpHeader { + name: "custom-header".to_string(), + value: "test".to_string(), + }; + let response = http_request_with(arg.clone(), { + let header = header.clone(); + move |mut response| { + response.headers = vec![header]; + response + } + }) + .await + .unwrap() + .0; assert_eq!(response.status, 200); - assert_eq!( - response.headers.get(0), - Some(&HttpHeader { - name: "custom-header".to_string(), - value: "test".to_string(), - }) - ); - let response = http_request_with_cycles(arg, 718500000u128) - .await - .unwrap() - .0; + assert_eq!(response.headers.get(0), Some(&header)); + let response = http_request_with_cycles_with(arg, 718500000u128, { + let header = header.clone(); + move |mut response| { + response.headers = vec![header]; + response + } + }) + .await + .unwrap() + .0; assert_eq!(response.status, 200); - assert_eq!( - response.headers.get(0), - Some(&HttpHeader { - name: "custom-header".to_string(), - value: "test".to_string(), - }) - ); - } - - // transform function must be a *query* method of the canister - #[query] - fn transform(arg: TransformArgs) -> HttpResponse { - HttpResponse { - headers: vec![HttpHeader { - name: "custom-header".to_string(), - value: "test".to_string(), - }], - ..arg.response - } + assert_eq!(response.headers.get(0), Some(&header)); } } diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index e3e5f8c8a..1a44bddd9 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `ic0.is_controller` as a public function. (#383) +### Changed + +- `TransformContext::new` has been replaced with dedicated functions that accept closures. (#385) + ## [0.7.4] - 2023-03-21 ### Added diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index dc9b84c0a..c396eaa5e 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -8,7 +8,12 @@ homepage = "https://docs.rs/ic-cdk" documentation = "https://docs.rs/ic-cdk" license = "Apache-2.0" readme = "README.md" -categories = ["api-bindings", "data-structures", "no-std", "development-tools::ffi"] +categories = [ + "api-bindings", + "data-structures", + "no-std", + "development-tools::ffi", +] keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" @@ -20,10 +25,14 @@ ic0 = { path = "../ic0", version = "0.18.9" } ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.6.7" } serde = "1.0.110" serde_bytes = "0.11.7" +slotmap = { version = "1.0.6", optional = true } [dev-dependencies] rstest = "0.12.0" +[features] +transform-closure = ["dep:slotmap"] + [package.metadata.docs.rs] default-target = "wasm32-unknown-unknown" rustdoc-args = ["--cfg=docsrs"] diff --git a/src/ic-cdk/src/api/management_canister/http_request.rs b/src/ic-cdk/src/api/management_canister/http_request.rs index 9009717fa..c97391014 100644 --- a/src/ic-cdk/src/api/management_canister/http_request.rs +++ b/src/ic-cdk/src/api/management_canister/http_request.rs @@ -1,13 +1,20 @@ //! Canister HTTP request. -use crate::api::call::{call_with_payment128, CallResult}; +use crate::{ + api::call::{call_with_payment128, CallResult}, + id, +}; use candid::{ parser::types::FuncMode, types::{Function, Serializer, Type}, - CandidType, Principal, + CandidType, Func, Principal, }; use core::hash::Hash; use serde::{Deserialize, Serialize}; +#[cfg(feature = "transform-closure")] +use slotmap::{DefaultKey, Key, SlotMap}; +#[cfg(feature = "transform-closure")] +use std::cell::RefCell; /// "transform" function of type: `func (http_request) -> (http_response) query` #[derive(Deserialize, Debug, PartialEq, Eq, Clone)] @@ -58,42 +65,45 @@ pub struct TransformContext { } impl TransformContext { - /// Construct `TransformContext` from a transform function. - /// - /// # example - /// - /// ```no_run - /// # use ic_cdk::api::management_canister::http_request::{TransformContext, TransformArgs, HttpResponse}; - /// #[ic_cdk::query] - /// fn my_transform(arg: TransformArgs) -> HttpResponse { - /// // ... - /// # unimplemented!() - /// } - /// # fn main() { - /// # let context = vec![]; - /// let transform = TransformContext::new(my_transform, context); - /// # } - /// ``` - pub fn new(func: T, context: Vec) -> Self - where - T: Fn(TransformArgs) -> HttpResponse, - { + /// Constructs a TransformContext from a name and context. The principal is assumed to be the [current canister's](id). + pub fn from_name(candid_function_name: String, context: Vec) -> Self { Self { - function: TransformFunc(candid::Func { - principal: crate::id(), - method: get_function_name(func).to_string(), - }), context, + function: TransformFunc(Func { + method: candid_function_name, + principal: id(), + }), } } } -fn get_function_name(_: F) -> &'static str { - let full_name = std::any::type_name::(); - match full_name.rfind(':') { - Some(index) => &full_name[index + 1..], - None => full_name, +#[cfg(feature = "transform-closure")] +thread_local! { + #[allow(clippy::type_complexity)] + static TRANSFORMS: RefCell HttpResponse>>> = RefCell::default(); +} + +#[cfg(feature = "transform-closure")] +#[export_name = "canister_query http_transform"] +extern "C" fn http_transform() { + use crate::api::{ + call::{arg_data, reply}, + caller, + }; + use slotmap::KeyData; + if caller() != Principal::management_canister() { + crate::trap("This function is internal to ic-cdk and should not be called externally."); } + crate::setup(); + let (args,): (TransformArgs,) = arg_data(); + let int = u64::from_be_bytes(args.context[..].try_into().unwrap()); + let key = DefaultKey::from(KeyData::from_ffi(int)); + let func = TRANSFORMS.with(|transforms| transforms.borrow_mut().remove(key)); + let Some(func) = func else { + crate::trap(&format!("Missing transform function for request {int}")); + }; + let transformed = func(args.response); + reply((transformed,)) } /// HTTP header. @@ -111,11 +121,23 @@ pub struct HttpHeader { /// /// Currently support following methods. #[derive( - CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, + CandidType, + Serialize, + Deserialize, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Clone, + Copy, + Default, )] pub enum HttpMethod { /// GET #[serde(rename = "get")] + #[default] GET, /// POST #[serde(rename = "post")] @@ -126,15 +148,14 @@ pub enum HttpMethod { } /// Argument type of [http_request]. -#[derive(CandidType, Deserialize, Debug, PartialEq, Eq, Clone)] +#[derive(CandidType, Deserialize, Debug, PartialEq, Eq, Clone, Default)] pub struct CanisterHttpRequestArgument { /// The requested URL. pub url: String, /// The maximal size of the response in bytes. If None, 2MiB will be the limit. /// This value affects the cost of the http request and it is highly recommended /// to set it as low as possible to avoid unnecessary extra costs. - /// See also the pricing section of HTTP outcalls documentation at - /// https://internetcomputer.org/docs/current/developer-docs/integrations/http_requests/http_requests-how-it-works#pricing. + /// See also the [pricing section of HTTP outcalls documentation](https://internetcomputer.org/docs/current/developer-docs/integrations/http_requests/http_requests-how-it-works#pricing). pub max_response_bytes: Option, /// The method of HTTP request. pub method: HttpMethod, @@ -143,6 +164,7 @@ pub struct CanisterHttpRequestArgument { /// Optionally provide request body. pub body: Option>, /// Name of the transform function which is `func (transform_args) -> (http_response) query`. + /// Set to `None` if you are using `http_request_with` or `http_request_with_cycles_with`. pub transform: Option, } @@ -165,7 +187,7 @@ pub struct HttpResponse { /// /// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. /// This method handles the cycles cost calculation under the hood which assuming the canister is on a 13-node Application Subnet. -/// If the canister is on a 34-node Application Subnets, you may have to compute the cost by yourself and call [http_request_with_cycles] instead. +/// If the canister is on a 34-node Application Subnets, you may have to compute the cost by yourself and call [`http_request_with_cycles`] instead. /// /// Check [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs) for more details. pub async fn http_request(arg: CanisterHttpRequestArgument) -> CallResult<(HttpResponse,)> { @@ -179,6 +201,27 @@ pub async fn http_request(arg: CanisterHttpRequestArgument) -> CallResult<(HttpR .await } +/// Make an HTTP request to a given URL and return the HTTP response, after a transformation. +/// +/// Do not set the `transform` field of `arg`. To use a Candid function, call [`http_request`] instead. +/// +/// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). +/// +/// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. +/// This method handles the cycles cost calculation under the hood which assuming the canister is on a 13-node Application Subnet. +/// If the canister is on a 34-node Application Subnets, you may have to compute the cost by yourself and call [`http_request_with_cycles_with`] instead. +/// +/// Check [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs) for more details. +#[cfg(any(docsrs, feature = "transform-closure"))] +#[cfg_attr(docsrs, doc(cfg(feature = "transform-closure")))] +pub async fn http_request_with( + arg: CanisterHttpRequestArgument, + transform_func: impl FnOnce(HttpResponse) -> HttpResponse + 'static, +) -> CallResult<(HttpResponse,)> { + let cycles = http_request_required_cycles(&arg); + http_request_with_cycles_with(arg, cycles, transform_func).await +} + /// Make an HTTP request to a given URL and return the HTTP response, possibly after a transformation. /// /// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). @@ -186,7 +229,7 @@ pub async fn http_request(arg: CanisterHttpRequestArgument) -> CallResult<(HttpR /// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. /// Check [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs) for more details. /// -/// If the canister is on a 13-node Application Subnet, you can call [http_request] instead which handles cycles cost calculation under the hood. +/// If the canister is on a 13-node Application Subnet, you can call [`http_request`] instead which handles cycles cost calculation under the hood. pub async fn http_request_with_cycles( arg: CanisterHttpRequestArgument, cycles: u128, @@ -200,6 +243,50 @@ pub async fn http_request_with_cycles( .await } +/// Make an HTTP request to a given URL and return the HTTP response, after a transformation. +/// +/// Do not set the `transform` field of `arg`. To use a Candid function, call [`http_request_with_cycles`] instead. +/// +/// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). +/// +/// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. +/// Check [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs) for more details. +/// +/// If the canister is on a 13-node Application Subnet, you can call [`http_request_with`] instead which handles cycles cost calculation under the hood. +#[cfg(any(docsrs, feature = "transform-closure"))] +#[cfg_attr(docsrs, doc(cfg(feature = "transform-closure")))] +pub async fn http_request_with_cycles_with( + arg: CanisterHttpRequestArgument, + cycles: u128, + transform_func: impl FnOnce(HttpResponse) -> HttpResponse + 'static, +) -> CallResult<(HttpResponse,)> { + assert!( + arg.transform.is_none(), + "`CanisterHttpRequestArgument`'s `transform` field must be `None` when using a closure" + ); + let transform_func = Box::new(transform_func) as _; + let key = TRANSFORMS.with(|transforms| transforms.borrow_mut().insert(transform_func)); + struct DropGuard(DefaultKey); + impl Drop for DropGuard { + fn drop(&mut self) { + TRANSFORMS.with(|transforms| transforms.borrow_mut().remove(self.0)); + } + } + let key = DropGuard(key); + let context = key.0.data().as_ffi().to_be_bytes().to_vec(); + let arg = CanisterHttpRequestArgument { + transform: Some(TransformContext { + function: TransformFunc(candid::Func { + method: " http_transform".into(), + principal: crate::id(), + }), + context, + }), + ..arg + }; + http_request_with_cycles(arg, cycles).await +} + fn http_request_required_cycles(arg: &CanisterHttpRequestArgument) -> u128 { let max_response_bytes = match arg.max_response_bytes { Some(ref n) => *n as u128, @@ -242,10 +329,4 @@ mod tests { }; assert_eq!(http_request_required_cycles(&arg), 210132900000u128); } - - #[test] - fn get_function_name_work() { - fn func() {} - assert_eq!(get_function_name(func), "func"); - } } diff --git a/src/ic0/src/ic0.rs b/src/ic0/src/ic0.rs index f68971b45..f5c2ba03c 100644 --- a/src/ic0/src/ic0.rs +++ b/src/ic0/src/ic0.rs @@ -65,7 +65,7 @@ extern "C" { #[cfg(not(target_arch = "wasm32"))] #[allow(unused_variables)] -#[allow(clippy::missing_safety_doc, missing_docs)] +#[allow(clippy::missing_safety_doc)] #[allow(clippy::too_many_arguments)] mod non_wasm { pub unsafe fn msg_arg_data_size() -> i32 { @@ -215,15 +215,15 @@ mod non_wasm { pub unsafe fn performance_counter(counter_type: i32) -> i64 { panic!("performance_counter should only be called inside canisters."); } + pub unsafe fn is_controller(src: i32, size: i32) -> i32 { + panic!("is_controller should only be called inside canisters."); + } pub unsafe fn debug_print(src: i32, size: i32) { panic!("debug_print should only be called inside canisters."); } pub unsafe fn trap(src: i32, size: i32) { panic!("trap should only be called inside canisters."); } - pub unsafe fn is_controller(src: i32, size: i32) -> i32 { - panic!("is_controller should only be called inside canisters."); - } } #[cfg(not(target_arch = "wasm32"))] From 307a83bb11863ba2dea15ef76d302faccd6ca996 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Mon, 8 May 2023 10:29:13 -0700 Subject: [PATCH 149/234] Fail CI for explicitly enabled warnings (#395) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 039f905f3..80b641ab6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,7 +134,7 @@ jobs: sudo apt-get install -y protobuf-compiler - name: Run clippy run: | - cargo clippy --tests --benches -- -D clippy::all + cargo clippy --tests --benches -- -D warnings aggregate: name: ci:required From 259ece44c3ba24d0df473084cb5c30ded682ccad Mon Sep 17 00:00:00 2001 From: mraszyk <31483726+mraszyk@users.noreply.github.com> Date: Fri, 12 May 2023 16:28:48 +0200 Subject: [PATCH 150/234] fix: lazy CallFuture (#391) * lazy calls * fix * add condition on waker * address Adam's feedback * do not clone args_raw * cargo clippy * added to CHANGELOG.md * update docs * do not overwrite state.waker * Add borrowed arg data to lazy calls (#396) * Allow argument data to be borrowed * have these been non-extern fns the entire time? --------- Co-authored-by: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> --- src/ic-cdk/CHANGELOG.md | 1 + src/ic-cdk/src/api/call.rs | 232 ++++++++++++++++++++----------------- 2 files changed, 129 insertions(+), 104 deletions(-) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 1a44bddd9..8cb0c6fbb 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `ic0.is_controller` as a public function. (#383) +- `CallFuture` only makes an inter-canister call if it is awaited. (#391) ### Changed diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 4f5914d1d..6c01ecc94 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -7,7 +7,7 @@ use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; use std::sync::atomic::Ordering; -use std::sync::{Arc, RwLock}; +use std::sync::{Arc, RwLock, Weak}; use std::task::{Context, Poll, Waker}; /// Rejection code from calling another canister. @@ -54,26 +54,77 @@ impl From for RejectionCode { pub type CallResult = Result; // Internal state for the Future when sending a call. -struct CallFutureState { +struct CallFutureState> { result: Option>>, waker: Option, + id: Principal, + method: String, + arg: T, + payment: u128, } -struct CallFuture { - state: Arc>, +struct CallFuture> { + state: Arc>>, } -impl Future for CallFuture { +impl> Future for CallFuture { type Output = CallResult>; fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll { let self_ref = Pin::into_inner(self); + let state_ptr = Weak::into_raw(Arc::downgrade(&self_ref.state)); let mut state = self_ref.state.write().unwrap(); if let Some(result) = state.result.take() { Poll::Ready(result) } else { - state.waker = Some(context.waker().clone()); + if state.waker.is_none() { + let callee = state.id.as_slice(); + let method = &state.method; + let args = state.arg.as_ref(); + let payment = state.payment; + // SAFETY: + // `callee`, being &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_new. + // `method`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.call_new. + // `callback` is a function with signature (env : i32) -> () and therefore can be called as both reply and reject fn for ic0.call_new. + // `state_ptr` is a pointer created via Weak::into_raw, and can therefore be passed as the userdata for `callback`. + // `args`, being a &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_data_append. + // `cleanup` is a function with signature (env : i32) -> () and therefore can be called as a cleanup fn for ic0.call_on_cleanup. + // `state_ptr` is a pointer created via Weak::into_raw, and can therefore be passed as the userdata for `cleanup`. + // ic0.call_perform is always safe to call. + // callback and cleanup are safe to parameterize with T because: + // - if the future is dropped before the callback is called, there will be no more strong references and the weak reference will fail to upgrade + // - if the future is *not* dropped before the callback is called, the compiler will mandate that any data borrowed by T is still alive + let err_code = unsafe { + ic0::call_new( + callee.as_ptr() as i32, + callee.len() as i32, + method.as_ptr() as i32, + method.len() as i32, + callback:: as usize as i32, + state_ptr as i32, + callback:: as usize as i32, + state_ptr as i32, + ); + + ic0::call_data_append(args.as_ptr() as i32, args.len() as i32); + add_payment(payment); + ic0::call_on_cleanup(cleanup:: as usize as i32, state_ptr as i32); + ic0::call_perform() + }; + + // 0 is a special error code meaning call succeeded. + if err_code != 0 { + let result = Err(( + RejectionCode::from(err_code), + "Couldn't send message".to_string(), + )); + state.result = Some(result.clone()); + return Poll::Ready(result); + } + + state.waker = Some(context.waker().clone()); + } Poll::Pending } } @@ -85,22 +136,24 @@ impl Future for CallFuture { /// /// # Safety /// -/// This function must only be passed to the IC with a pointer from Arc::into_raw as userdata. -unsafe fn callback(state_ptr: *const RwLock) { - // SAFETY: This function is only ever called by the IC, and we only ever pass a Arc as userdata. - let state = unsafe { Arc::from_raw(state_ptr) }; - // Make sure to un-borrow_mut the state. - { - state.write().unwrap().result = Some(match reject_code() { - RejectionCode::NoError => Ok(arg_data_raw()), - n => Err((n, reject_message())), - }); - } - let w = state.write().unwrap().waker.take(); - if let Some(waker) = w { - // This is all to protect this little guy here which will call the poll() which - // borrow_mut() the state as well. So we need to be careful to not double-borrow_mut. - waker.wake() +/// This function must only be passed to the IC with a pointer from Weak::into_raw as userdata. +unsafe extern "C" fn callback>(state_ptr: *const RwLock>) { + // SAFETY: This function is only ever called by the IC, and we only ever pass a Weak as userdata. + let state = unsafe { Weak::from_raw(state_ptr) }; + if let Some(state) = state.upgrade() { + // Make sure to un-borrow_mut the state. + { + state.write().unwrap().result = Some(match reject_code() { + RejectionCode::NoError => Ok(arg_data_raw()), + n => Err((n, reject_message())), + }); + } + let w = state.write().unwrap().waker.take(); + if let Some(waker) = w { + // This is all to protect this little guy here which will call the poll() which + // borrow_mut() the state as well. So we need to be careful to not double-borrow_mut. + waker.wake() + } } } @@ -110,26 +163,28 @@ unsafe fn callback(state_ptr: *const RwLock) { /// /// # Safety /// -/// This function must only be passed to the IC with a pointer from Arc::into_raw as userdata. -unsafe fn cleanup(state_ptr: *const RwLock) { - // SAFETY: This function is only ever called by the IC, and we only ever pass a Arc as userdata. - let state = unsafe { Arc::from_raw(state_ptr) }; - // We set the call result, even though it won't be read on the - // default executor, because we can't guarantee it was called on - // our executor. However, we are not allowed to inspect - // reject_code() inside of a cleanup callback, so always set the - // result to a reject. - // - // Borrowing does not trap - the rollback from the - // previous trap ensures that the RwLock can be borrowed again. - state.write().unwrap().result = Some(Err((RejectionCode::NoError, "cleanup".to_string()))); - let w = state.write().unwrap().waker.take(); - if let Some(waker) = w { - // Flag that we do not want to actually wake the task - we - // want to drop it *without* executing it. - crate::futures::CLEANUP.store(true, Ordering::Relaxed); - waker.wake(); - crate::futures::CLEANUP.store(false, Ordering::Relaxed); +/// This function must only be passed to the IC with a pointer from Weak::into_raw as userdata. +unsafe extern "C" fn cleanup>(state_ptr: *const RwLock>) { + // SAFETY: This function is only ever called by the IC, and we only ever pass a Weak as userdata. + let state = unsafe { Weak::from_raw(state_ptr) }; + if let Some(state) = state.upgrade() { + // We set the call result, even though it won't be read on the + // default executor, because we can't guarantee it was called on + // our executor. However, we are not allowed to inspect + // reject_code() inside of a cleanup callback, so always set the + // result to a reject. + // + // Borrowing does not trap - the rollback from the + // previous trap ensures that the RwLock can be borrowed again. + state.write().unwrap().result = Some(Err((RejectionCode::NoError, "cleanup".to_string()))); + let w = state.write().unwrap().waker.take(); + if let Some(waker) = w { + // Flag that we do not want to actually wake the task - we + // want to drop it *without* executing it. + crate::futures::CLEANUP.store(true, Ordering::Relaxed); + waker.wake(); + crate::futures::CLEANUP.store(false, Ordering::Relaxed); + } } } @@ -227,82 +282,39 @@ pub fn notify_raw( } /// Similar to `call`, but without serialization. -pub fn call_raw( +pub fn call_raw<'a, T: AsRef<[u8]> + Send + Sync + 'a>( id: Principal, method: &str, - args_raw: &[u8], + args_raw: T, payment: u64, -) -> impl Future>> + Send + Sync { - call_raw_internal(id, method, args_raw, move || { - if payment > 0 { - // SAFETY: ic0.call_cycles_add is always safe to call. - unsafe { - // This is called as part of the call_new lifecycle, and so will not trap. - ic0::call_cycles_add(payment as i64); - } - } - }) +) -> impl Future>> + Send + Sync + 'a { + call_raw_internal(id, method, args_raw, payment.into()) } /// Similar to `call128`, but without serialization. -pub fn call_raw128( +pub fn call_raw128<'a, T: AsRef<[u8]> + Send + Sync + 'a>( id: Principal, method: &str, - args_raw: &[u8], + args_raw: T, payment: u128, -) -> impl Future>> + Send + Sync { - call_raw_internal(id, method, args_raw, move || { - add_payment(payment); - }) +) -> impl Future>> + Send + Sync + 'a { + call_raw_internal(id, method, args_raw, payment) } -fn call_raw_internal( +fn call_raw_internal<'a, T: AsRef<[u8]> + Send + Sync + 'a>( id: Principal, method: &str, - args_raw: &[u8], - payment_func: impl FnOnce(), -) -> impl Future>> + Send + Sync { - let callee = id.as_slice(); + args_raw: T, + payment: u128, +) -> impl Future>> + Send + Sync + 'a { let state = Arc::new(RwLock::new(CallFutureState { result: None, waker: None, + id, + method: method.to_string(), + arg: args_raw, + payment, })); - let state_ptr = Arc::into_raw(state.clone()); - // SAFETY: - // `callee`, being &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_new. - // `method`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.call_new. - // `callback` is a function with signature (env : i32) -> () and therefore can be called as both reply and reject fn for ic0.call_new. - // `state_ptr` is a pointer created via Arc::into_raw, and can therefore be passed as the userdata for `callback`. - // `args`, being a &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_data_append. - // `cleanup` is a function with signature (env : i32) -> () and therefore can be called as a cleanup fn for ic0.call_on_cleanup. - // `state_ptr` is a pointer created via Arc::into_raw, and can therefore be passed as the userdata for `cleanup`. - // ic0.call_perform is always safe to call. - let err_code = unsafe { - ic0::call_new( - callee.as_ptr() as i32, - callee.len() as i32, - method.as_ptr() as i32, - method.len() as i32, - callback as usize as i32, - state_ptr as i32, - callback as usize as i32, - state_ptr as i32, - ); - - ic0::call_data_append(args_raw.as_ptr() as i32, args_raw.len() as i32); - payment_func(); - ic0::call_on_cleanup(cleanup as usize as i32, state_ptr as i32); - ic0::call_perform() - }; - - // 0 is a special error code meaning call_simple call succeeded. - if err_code != 0 { - let mut state = state.write().unwrap(); - state.result = Some(Err(( - RejectionCode::from(err_code), - "Couldn't send message".to_string(), - ))); - } CallFuture { state } } @@ -321,13 +333,17 @@ fn decoder_error_to_reject(err: candid::error::Error) -> (RejectionCode, Stri /// /// If the reply payload is not a valid encoding of the expected type `T`, /// the call results in [RejectionCode::CanisterError] error. +/// +/// Note that the asynchronous call must be awaited +/// in order for the inter-canister call to be made +/// using the [System API](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-call). pub fn call ArgumentDecoder<'a>>( id: Principal, method: &str, args: T, ) -> impl Future> + Send + Sync { let args_raw = encode_args(args).expect("Failed to encode arguments."); - let fut = call_raw(id, method, &args_raw, 0); + let fut = call_raw(id, method, args_raw, 0); async { let bytes = fut.await?; decode_args(&bytes).map_err(decoder_error_to_reject::) @@ -335,6 +351,10 @@ pub fn call ArgumentDecoder<'a>>( } /// Performs an asynchronous call to another canister and pay cycles at the same time. +/// +/// Note that the asynchronous call must be awaited +/// in order for the inter-canister call to be made +/// using the [System API](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-call). pub fn call_with_payment ArgumentDecoder<'a>>( id: Principal, method: &str, @@ -342,7 +362,7 @@ pub fn call_with_payment ArgumentDecoder<'a>>( cycles: u64, ) -> impl Future> + Send + Sync { let args_raw = encode_args(args).expect("Failed to encode arguments."); - let fut = call_raw(id, method, &args_raw, cycles); + let fut = call_raw(id, method, args_raw, cycles); async { let bytes = fut.await?; decode_args(&bytes).map_err(decoder_error_to_reject::) @@ -350,6 +370,10 @@ pub fn call_with_payment ArgumentDecoder<'a>>( } /// Performs an asynchronous call to another canister and pay cycles at the same time. +/// +/// Note that the asynchronous call must be awaited +/// in order for the inter-canister call to be made +/// using the [System API](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-call). pub fn call_with_payment128 ArgumentDecoder<'a>>( id: Principal, method: &str, @@ -357,7 +381,7 @@ pub fn call_with_payment128 ArgumentDecoder<'a>>( cycles: u128, ) -> impl Future> + Send + Sync { let args_raw = encode_args(args).expect("Failed to encode arguments."); - let fut = call_raw128(id, method, &args_raw, cycles); + let fut = call_raw128(id, method, args_raw, cycles); async { let bytes = fut.await?; decode_args(&bytes).map_err(decoder_error_to_reject::) From d6eec23b534571bfabbdcabaa067f0102eb186e1 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Fri, 12 May 2023 12:12:52 -0700 Subject: [PATCH 151/234] Revert 286faae (#397) --- src/ic-cdk/src/api/call.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 6c01ecc94..f95aa0231 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -122,9 +122,8 @@ impl> Future for CallFuture { state.result = Some(result.clone()); return Poll::Ready(result); } - - state.waker = Some(context.waker().clone()); } + state.waker = Some(context.waker().clone()); Poll::Pending } } From cefe7a11ed6b2cf720dd8e072d682dea1575bce2 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 26 May 2023 12:14:38 -0400 Subject: [PATCH 152/234] chore: release ic-cdk v0.8.0 (#398) * bump version * bump minor --- library/ic-ledger-types/CHANGELOG.md | 4 ++++ library/ic-ledger-types/Cargo.toml | 4 ++-- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-timers/CHANGELOG.md | 6 ++++++ src/ic-cdk-timers/Cargo.toml | 4 ++-- src/ic-cdk/CHANGELOG.md | 4 +++- src/ic-cdk/Cargo.toml | 4 ++-- src/ic0/Cargo.toml | 2 +- src/ic0/ic0.txt | 20 ++++++++++---------- 9 files changed, 31 insertions(+), 19 deletions(-) diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index d24fa15bf..d4b76d06b 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.5.0] - 2023-05-26 +### Changed +- Upgrade `ic-cdk` to v0.8. + ## [0.4.2] - 2023-03-01 ### Fixed - Fill missing docs. diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 6af0ee907..4108b802c 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.4.2" +version = "0.5.0" edition = "2021" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." @@ -17,7 +17,7 @@ rust-version = "1.65.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ic-cdk = { path = "../../src/ic-cdk", version = "0.7" } +ic-cdk = { path = "../../src/ic-cdk", version = "0.8" } candid = "0.8.0" crc32fast = "1.2.0" hex = "0.4" diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 5c707f0fc..af4c5f61a 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -27,4 +27,4 @@ serde = "1.0.111" [dev-dependencies] trybuild = "1.0" -ic-cdk = { path = "../ic-cdk", version = "0.7" } +ic-cdk = { path = "../ic-cdk", version = "0.8" } diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index 7d831a982..481ace290 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.2.0] - 2023-05-26 + +### Changed + +- Upgrade `ic-cdk` to v0.8. + ## [0.1.2] - 2023-03-01 ## [0.1.1] - 2023-02-22 diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index 1b1305365..72f9fe9d4 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.1.2" +version = "0.2.0" authors = ["DFINITY Stiftung "] edition = "2021" description = "Timers library for the Rust CDK." @@ -15,7 +15,7 @@ repository = "https://github.com/dfinity/cdk-rs" rust-version = "1.60.0" [dependencies] -ic-cdk = { path = "../../src/ic-cdk", version = "0.7" } +ic-cdk = { path = "../../src/ic-cdk", version = "0.8" } serde = "1.0.110" serde_bytes = "0.11.7" ic0 = { path = "../ic0", version = "0.18.9" } diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 8cb0c6fbb..6b0e078de 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,14 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.8.0] - 2023-05-26 + ### Added - `ic0.is_controller` as a public function. (#383) -- `CallFuture` only makes an inter-canister call if it is awaited. (#391) ### Changed - `TransformContext::new` has been replaced with dedicated functions that accept closures. (#385) +- `CallFuture` only makes an inter-canister call if it is awaited. (#391) ## [0.7.4] - 2023-03-21 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index c396eaa5e..2cbd4934c 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.7.4" +version = "0.8.0" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." @@ -21,7 +21,7 @@ rust-version = "1.65.0" [dependencies] candid = "0.8" -ic0 = { path = "../ic0", version = "0.18.9" } +ic0 = { path = "../ic0", version = "0.18.10" } ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.6.7" } serde = "1.0.110" serde_bytes = "0.11.7" diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml index c5b97979c..01836584a 100644 --- a/src/ic0/Cargo.toml +++ b/src/ic0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic0" -version = "0.18.9" +version = "0.18.10" authors = ["DFINITY Stiftung "] edition = "2021" description = "Internet Computer System API Binding." diff --git a/src/ic0/ic0.txt b/src/ic0/ic0.txt index 1ea8594a0..9c4a5c3a4 100644 --- a/src/ic0/ic0.txt +++ b/src/ic0/ic0.txt @@ -45,14 +45,14 @@ ic0.call_cycles_add : (amount : i64) -> (); // U ic0.call_cycles_add128 : (amount_high : i64, amount_low: i64) -> (); // U Ry Rt T ic0.call_perform : () -> ( err_code : i32 ); // U Ry Rt T -ic0.stable_size : () -> (page_count : i32); // * -ic0.stable_grow : (new_pages : i32) -> (old_page_count : i32); // * -ic0.stable_write : (offset : i32, src : i32, size : i32) -> (); // * -ic0.stable_read : (dst : i32, offset : i32, size : i32) -> (); // * -ic0.stable64_size : () -> (page_count : i64); // * -ic0.stable64_grow : (new_pages : i64) -> (old_page_count : i64); // * -ic0.stable64_write : (offset : i64, src : i64, size : i64) -> (); // * -ic0.stable64_read : (dst : i64, offset : i64, size : i64) -> (); // * +ic0.stable_size : () -> (page_count : i32); // * s +ic0.stable_grow : (new_pages : i32) -> (old_page_count : i32); // * s +ic0.stable_write : (offset : i32, src : i32, size : i32) -> (); // * s +ic0.stable_read : (dst : i32, offset : i32, size : i32) -> (); // * s +ic0.stable64_size : () -> (page_count : i64); // * s +ic0.stable64_grow : (new_pages : i64) -> (old_page_count : i64); // * s +ic0.stable64_write : (offset : i64, src : i64, size : i64) -> (); // * s +ic0.stable64_read : (dst : i64, offset : i64, size : i64) -> (); // * s ic0.certified_data_set : (src: i32, size: i32) -> (); // I G U Ry Rt T ic0.data_certificate_present : () -> i32; // * @@ -60,9 +60,9 @@ ic0.data_certificate_size : () -> i32; // * ic0.data_certificate_copy : (dst: i32, offset: i32, size: i32) -> (); // * ic0.time : () -> (timestamp : i64); // * -ic0.global_timer_set : (timestamp : i64) -> i64; // I U Ry Rt C T +ic0.global_timer_set : (timestamp : i64) -> i64; // I G U Ry Rt C T ic0.performance_counter : (counter_type : i32) -> (counter : i64); // * s -ic0.is_controller: (src: i32, size: i32) -> (result: i32); // * s +ic0.is_controller: (src: i32, size: i32) -> ( result: i32); // * s ic0.debug_print : (src : i32, size : i32) -> (); // * s ic0.trap : (src : i32, size : i32) -> (); // * s \ No newline at end of file From a8454cb37420c200c7b224befd6f68326a01442e Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Tue, 30 May 2023 09:02:46 -0700 Subject: [PATCH 153/234] fix: Fix docs.rs build (#400) * Fix doc build * Bump version --- src/ic-cdk/Cargo.toml | 3 ++- src/ic-cdk/src/api/management_canister/http_request.rs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 2cbd4934c..df681fff9 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.8.0" +version = "0.8.1" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." @@ -34,5 +34,6 @@ rstest = "0.12.0" transform-closure = ["dep:slotmap"] [package.metadata.docs.rs] +all-features = true default-target = "wasm32-unknown-unknown" rustdoc-args = ["--cfg=docsrs"] diff --git a/src/ic-cdk/src/api/management_canister/http_request.rs b/src/ic-cdk/src/api/management_canister/http_request.rs index c97391014..af7b674bd 100644 --- a/src/ic-cdk/src/api/management_canister/http_request.rs +++ b/src/ic-cdk/src/api/management_canister/http_request.rs @@ -212,7 +212,7 @@ pub async fn http_request(arg: CanisterHttpRequestArgument) -> CallResult<(HttpR /// If the canister is on a 34-node Application Subnets, you may have to compute the cost by yourself and call [`http_request_with_cycles_with`] instead. /// /// Check [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs) for more details. -#[cfg(any(docsrs, feature = "transform-closure"))] +#[cfg(feature = "transform-closure")] #[cfg_attr(docsrs, doc(cfg(feature = "transform-closure")))] pub async fn http_request_with( arg: CanisterHttpRequestArgument, @@ -253,7 +253,7 @@ pub async fn http_request_with_cycles( /// Check [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs) for more details. /// /// If the canister is on a 13-node Application Subnet, you can call [`http_request_with`] instead which handles cycles cost calculation under the hood. -#[cfg(any(docsrs, feature = "transform-closure"))] +#[cfg(feature = "transform-closure")] #[cfg_attr(docsrs, doc(cfg(feature = "transform-closure")))] pub async fn http_request_with_cycles_with( arg: CanisterHttpRequestArgument, From 0478ba2c5eea6be7ee88f2025d6c3e36bc85a64c Mon Sep 17 00:00:00 2001 From: mraszyk <31483726+mraszyk@users.noreply.github.com> Date: Fri, 9 Jun 2023 09:57:51 +0200 Subject: [PATCH 154/234] feat: set sender_canister_version and support canister_info (#401) * set sender_canister_version and support canister_info * use canister_info in test canister * remove Canister from CanisterChangeOrigin and CanisterChangeDetails variant types --- e2e-tests/Cargo.toml | 5 + e2e-tests/canisters/canister_info.rs | 79 ++++++++ e2e-tests/tests/e2e.rs | 181 +++++++++++++++++- scripts/download_state_machine_binary.sh | 2 +- src/ic-cdk/CHANGELOG.md | 3 + .../src/api/management_canister/main/mod.rs | 57 +++++- .../src/api/management_canister/main/types.rs | 176 +++++++++++++++++ 7 files changed, 496 insertions(+), 7 deletions(-) create mode 100644 e2e-tests/canisters/canister_info.rs diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 38efa1530..79f8f3587 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -37,6 +37,11 @@ path = "canisters/api_call.rs" name = "timers" path = "canisters/timers.rs" +[[bin]] +name = "canister_info" +path = "canisters/canister_info.rs" + [dev-dependencies] candid = "0.8" +hex = "0.4.3" ic-test-state-machine-client = "1" diff --git a/e2e-tests/canisters/canister_info.rs b/e2e-tests/canisters/canister_info.rs new file mode 100644 index 000000000..19d048040 --- /dev/null +++ b/e2e-tests/canisters/canister_info.rs @@ -0,0 +1,79 @@ +use ic_cdk::api::management_canister::main::{ + canister_info, create_canister, install_code, uninstall_code, update_settings, + CanisterIdRecord, CanisterInfoRequest, CanisterInfoResponse, + CanisterInstallMode::{Install, Reinstall, Upgrade}, + CanisterSettings, CreateCanisterArgument, InstallCodeArgument, UpdateSettingsArgument, +}; +use ic_cdk::export::Principal; + +#[ic_cdk::update] +async fn info(canister_id: Principal) -> CanisterInfoResponse { + let request = CanisterInfoRequest { + canister_id, + num_requested_changes: Some(20), + }; + canister_info(request).await.unwrap().0 +} + +#[ic_cdk_macros::update] +async fn canister_lifecycle() -> Principal { + let canister_id = create_canister(CreateCanisterArgument { settings: None }) + .await + .unwrap() + .0; + install_code(InstallCodeArgument { + mode: Install, + arg: vec![], + wasm_module: vec![0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00], + canister_id: canister_id.canister_id, + }) + .await + .unwrap(); + uninstall_code(CanisterIdRecord { + canister_id: canister_id.canister_id, + }) + .await + .unwrap(); + install_code(InstallCodeArgument { + mode: Install, + arg: vec![], + wasm_module: vec![0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00], + canister_id: canister_id.canister_id, + }) + .await + .unwrap(); + install_code(InstallCodeArgument { + mode: Reinstall, + arg: vec![], + wasm_module: vec![0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00], + canister_id: canister_id.canister_id, + }) + .await + .unwrap(); + install_code(InstallCodeArgument { + mode: Upgrade, + arg: vec![], + wasm_module: vec![0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00], + canister_id: canister_id.canister_id, + }) + .await + .unwrap(); + update_settings(UpdateSettingsArgument { + settings: CanisterSettings { + controllers: Some(vec![ + ic_cdk::id(), + canister_id.canister_id, + Principal::anonymous(), + ]), + compute_allocation: None, + memory_allocation: None, + freezing_threshold: None, + }, + canister_id: canister_id.canister_id, + }) + .await + .unwrap(); + canister_id.canister_id +} + +fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 8600b8967..241637070 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -1,11 +1,19 @@ use std::time::Duration; use candid::{Encode, Principal}; +use ic_cdk::api::management_canister::main::{ + CanisterChange, CanisterChangeDetails, CanisterChangeOrigin, CanisterIdRecord, + CanisterInfoResponse, + CanisterInstallMode::{Install, Reinstall, Upgrade}, + CodeDeploymentRecord, ControllersChangeRecord, CreationRecord, FromCanisterRecord, + FromUserRecord, InstallCodeArgument, +}; use ic_cdk_e2e_tests::cargo_build_canister; use ic_test_state_machine_client::{ - call_candid, query_candid, CallError, ErrorCode, StateMachine, WasmResult, + call_candid, call_candid_as, query_candid, CallError, ErrorCode, StateMachine, WasmResult, }; use serde_bytes::ByteBuf; +use std::time::SystemTime; pub static STATE_MACHINE_BINARY: &str = "../ic-test-state-machine"; @@ -260,3 +268,174 @@ fn advance_seconds(env: &StateMachine, seconds: u32) { env.tick(); } } + +#[test] +fn test_canister_info() { + let env = env(); + let wasm = cargo_build_canister("canister_info"); + let canister_id = env.create_canister(); + env.add_cycles(canister_id, 1_000_000_000_000); + env.install_canister(canister_id, wasm, vec![]); + + let new_canister: (Principal,) = call_candid(&env, canister_id, "canister_lifecycle", ()) + .expect("Error calling canister_lifecycle"); + + let () = call_candid_as( + &env, + Principal::management_canister(), + Principal::anonymous(), + "uninstall_code", + (CanisterIdRecord { + canister_id: new_canister.0, + },), + ) + .expect("Error calling uninstall_code"); + let () = call_candid_as( + &env, + Principal::management_canister(), + Principal::anonymous(), + "install_code", + (InstallCodeArgument { + mode: Install, + arg: vec![], + wasm_module: vec![0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00], + canister_id: new_canister.0, + },), + ) + .expect("Error calling install_code"); + + let info: (CanisterInfoResponse,) = call_candid(&env, canister_id, "info", (new_canister.0,)) + .expect("Error calling canister_info"); + + let timestamp_nanos = env + .time() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_nanos() as u64; + assert_eq!( + info.0, + CanisterInfoResponse { + total_num_changes: 9, + recent_changes: vec![ + CanisterChange { + timestamp_nanos, + canister_version: 0, + origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { + canister_id, + canister_version: Some(1) + }), + details: CanisterChangeDetails::Creation(CreationRecord { + controllers: vec![canister_id] + }), + }, + CanisterChange { + timestamp_nanos, + canister_version: 1, + origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { + canister_id, + canister_version: Some(2) + }), + details: CanisterChangeDetails::CodeDeployment(CodeDeploymentRecord { + mode: Install, + module_hash: hex::decode( + "93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476" + ) + .unwrap(), + }), + }, + CanisterChange { + timestamp_nanos, + canister_version: 2, + origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { + canister_id, + canister_version: Some(3) + }), + details: CanisterChangeDetails::CodeUninstall, + }, + CanisterChange { + timestamp_nanos, + canister_version: 3, + origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { + canister_id, + canister_version: Some(4) + }), + details: CanisterChangeDetails::CodeDeployment(CodeDeploymentRecord { + mode: Install, + module_hash: hex::decode( + "93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476" + ) + .unwrap(), + }), + }, + CanisterChange { + timestamp_nanos, + canister_version: 4, + origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { + canister_id, + canister_version: Some(5) + }), + details: CanisterChangeDetails::CodeDeployment(CodeDeploymentRecord { + mode: Reinstall, + module_hash: hex::decode( + "93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476" + ) + .unwrap(), + }), + }, + CanisterChange { + timestamp_nanos, + canister_version: 5, + origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { + canister_id, + canister_version: Some(6) + }), + details: CanisterChangeDetails::CodeDeployment(CodeDeploymentRecord { + mode: Upgrade, + module_hash: hex::decode( + "93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476" + ) + .unwrap(), + }), + }, + CanisterChange { + timestamp_nanos, + canister_version: 6, + origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { + canister_id, + canister_version: Some(7) + }), + details: CanisterChangeDetails::ControllersChange(ControllersChangeRecord { + controllers: vec![Principal::anonymous(), canister_id, new_canister.0] + }), + }, + CanisterChange { + timestamp_nanos, + canister_version: 7, + origin: CanisterChangeOrigin::FromUser(FromUserRecord { + user_id: Principal::anonymous(), + }), + details: CanisterChangeDetails::CodeUninstall, + }, + CanisterChange { + timestamp_nanos, + canister_version: 8, + origin: CanisterChangeOrigin::FromUser(FromUserRecord { + user_id: Principal::anonymous(), + }), + details: CanisterChangeDetails::CodeDeployment(CodeDeploymentRecord { + mode: Install, + module_hash: hex::decode( + "93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476" + ) + .unwrap(), + }), + }, + ], + module_hash: Some( + hex::decode("93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476") + .unwrap() + ), + controllers: vec![Principal::anonymous(), canister_id, new_canister.0], + } + ); +} diff --git a/scripts/download_state_machine_binary.sh b/scripts/download_state_machine_binary.sh index 670e6844c..a9098adfb 100755 --- a/scripts/download_state_machine_binary.sh +++ b/scripts/download_state_machine_binary.sh @@ -8,7 +8,7 @@ cd "$SCRIPTS_DIR/.." uname_sys=$(uname -s | tr '[:upper:]' '[:lower:]') echo "uname_sys: $uname_sys" -commit_sha="d0ea9d15cc51bd5bba16c8f1be3a6dfc8ec7dc24" +commit_sha="4bffd861d15a28682761c97bd0e6608bf324c5c2" curl -sLO "https://download.dfinity.systems/ic/$commit_sha/binaries/x86_64-$uname_sys/ic-test-state-machine.gz" gzip -d ic-test-state-machine.gz diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 6b0e078de..d9dbb01e3 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +- Set caller's canister version in the field `sender_canister_version` of management canister call payloads. +- Add management canister types for `canister_info` management canister call (`CanisterInfoRequest` and `CanisterInfoResponse`). + ## [0.8.0] - 2023-05-26 ### Added diff --git a/src/ic-cdk/src/api/management_canister/main/mod.rs b/src/ic-cdk/src/api/management_canister/main/mod.rs index 759646e56..786026ce3 100644 --- a/src/ic-cdk/src/api/management_canister/main/mod.rs +++ b/src/ic-cdk/src/api/management_canister/main/mod.rs @@ -6,6 +6,7 @@ //! [1]: https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-management-canister use crate::api::call::{call, call_with_payment128, CallResult}; +use crate::api::canister_version; use candid::Principal; mod types; @@ -22,10 +23,14 @@ pub const CREATE_CANISTER_CYCLES: u128 = 100_000_000_000u128; /// /// See [IC method `create_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-create_canister). pub async fn create_canister(arg: CreateCanisterArgument) -> CallResult<(CanisterIdRecord,)> { + let extended_arg = CreateCanisterArgumentExtended { + settings: arg.settings, + sender_canister_version: Some(canister_version()), + }; call_with_payment128( Principal::management_canister(), "create_canister", - (arg,), + (extended_arg,), CREATE_CANISTER_CYCLES, ) .await @@ -40,10 +45,14 @@ pub async fn create_canister_with_extra_cycles( arg: CreateCanisterArgument, cycles: u128, ) -> CallResult<(CanisterIdRecord,)> { + let extended_arg = CreateCanisterArgumentExtended { + settings: arg.settings, + sender_canister_version: Some(canister_version()), + }; call_with_payment128( Principal::management_canister(), "create_canister", - (arg,), + (extended_arg,), CREATE_CANISTER_CYCLES + cycles, ) .await @@ -53,21 +62,52 @@ pub async fn create_canister_with_extra_cycles( /// /// See [IC method `update_settings`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-update_settings). pub async fn update_settings(arg: UpdateSettingsArgument) -> CallResult<()> { - call(Principal::management_canister(), "update_settings", (arg,)).await + let extended_arg = UpdateSettingsArgumentExtended { + canister_id: arg.canister_id, + settings: arg.settings, + sender_canister_version: Some(canister_version()), + }; + call( + Principal::management_canister(), + "update_settings", + (extended_arg,), + ) + .await } /// Install code into a canister. /// /// See [IC method `install_code`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-install_code). pub async fn install_code(arg: InstallCodeArgument) -> CallResult<()> { - call(Principal::management_canister(), "install_code", (arg,)).await + let extended_arg = InstallCodeArgumentExtended { + mode: arg.mode, + canister_id: arg.canister_id, + wasm_module: arg.wasm_module, + arg: arg.arg, + sender_canister_version: Some(canister_version()), + }; + call( + Principal::management_canister(), + "install_code", + (extended_arg,), + ) + .await } /// Remove a canister's code and state, making the canister empty again. /// /// See [IC method `uninstall_code`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-uninstall_code) pub async fn uninstall_code(arg: CanisterIdRecord) -> CallResult<()> { - call(Principal::management_canister(), "uninstall_code", (arg,)).await + let extended_arg = CanisterIdRecordExtended { + canister_id: arg.canister_id, + sender_canister_version: Some(canister_version()), + }; + call( + Principal::management_canister(), + "uninstall_code", + (extended_arg,), + ) + .await } /// Start a canister if the canister status was `stopped` or `stopping`. @@ -120,3 +160,10 @@ pub async fn deposit_cycles(arg: CanisterIdRecord, cycles: u128) -> CallResult<( pub async fn raw_rand() -> CallResult<(Vec,)> { call(Principal::management_canister(), "raw_rand", ()).await } + +/// Get public information about the canister. +/// +/// See [IC method `canister_info`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-canister_info) +pub async fn canister_info(arg: CanisterInfoRequest) -> CallResult<(CanisterInfoResponse,)> { + call(Principal::management_canister(), "canister_info", (arg,)).await +} diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index 478024a1f..05d79c33d 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -30,6 +30,16 @@ pub struct CreateCanisterArgument { pub settings: Option, } +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub(crate) struct CreateCanisterArgumentExtended { + /// See [CanisterSettings]. + pub settings: Option, + /// sender_canister_version must be set to ic_cdk::api::canister_version() + pub sender_canister_version: Option, +} + /// Argument type of [update_settings](super::update_settings). #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, @@ -41,6 +51,18 @@ pub struct UpdateSettingsArgument { pub settings: CanisterSettings, } +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub(crate) struct UpdateSettingsArgumentExtended { + /// Principle of the canister. + pub canister_id: CanisterId, + /// See [CanisterSettings]. + pub settings: CanisterSettings, + /// sender_canister_version must be set to ic_cdk::api::canister_version() + pub sender_canister_version: Option, +} + /// The mode with which a canister is installed. #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, @@ -76,6 +98,22 @@ pub struct InstallCodeArgument { pub arg: Vec, } +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub(crate) struct InstallCodeArgumentExtended { + /// See [CanisterInstallMode]. + pub mode: CanisterInstallMode, + /// Principle of the canister. + pub canister_id: CanisterId, + /// Code to be installed. + pub wasm_module: WasmModule, + /// The argument to be passed to `canister_init` or `canister_post_upgrade`. + pub arg: Vec, + /// sender_canister_version must be set to ic_cdk::api::canister_version() + pub sender_canister_version: Option, +} + /// A wrapper of canister id. #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, @@ -85,6 +123,16 @@ pub struct CanisterIdRecord { pub canister_id: CanisterId, } +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, +)] +pub(crate) struct CanisterIdRecordExtended { + /// Principle of the canister. + pub canister_id: CanisterId, + /// sender_canister_version must be set to ic_cdk::api::canister_version() + pub sender_canister_version: Option, +} + /// Status of a canister. #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, @@ -135,3 +183,131 @@ pub struct CanisterStatusResponse { /// Amount of cycles burned per day. pub idle_cycles_burned_per_day: Nat, } + +/// Details about a canister change initiated by a user. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct FromUserRecord { + /// Principle of the user. + pub user_id: Principal, +} + +/// Details about a canister change initiated by a canister (called _originator_). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct FromCanisterRecord { + /// Principle of the originator. + pub canister_id: Principal, + /// Canister version of the originator when the originator initiated the change. + /// This is null if the original does not include its canister version + /// in the field `sender_canister_version` of the management canister payload. + pub canister_version: Option, +} + +/// Provides details on who initiated a canister change. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub enum CanisterChangeOrigin { + /// See [FromUserRecord]. + #[serde(rename = "from_user")] + FromUser(FromUserRecord), + /// See [FromCanisterRecord]. + #[serde(rename = "from_canister")] + FromCanister(FromCanisterRecord), +} + +/// Details about a canister creation. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct CreationRecord { + /// Initial set of canister controllers. + pub controllers: Vec, +} + +/// Details about a canister code deployment. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct CodeDeploymentRecord { + /// See [CanisterInstallMode]. + pub mode: CanisterInstallMode, + /// A SHA256 hash of the new module installed on the canister. + pub module_hash: Vec, +} + +/// Details about updating canister controllers. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct ControllersChangeRecord { + /// The full new set of canister controllers. + pub controllers: Vec, +} + +/// Provides details on the respective canister change. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub enum CanisterChangeDetails { + /// See [CreationRecord]. + #[serde(rename = "creation")] + Creation(CreationRecord), + /// Uninstalling canister's module. + #[serde(rename = "code_uninstall")] + CodeUninstall, + /// See [CodeDeploymentRecord]. + #[serde(rename = "code_deployment")] + CodeDeployment(CodeDeploymentRecord), + /// See [ControllersChangeRecord]. + #[serde(rename = "controllers_change")] + ControllersChange(ControllersChangeRecord), +} + +/// Represents a canister change as stored in the canister history. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct CanisterChange { + /// The system timestamp (in nanoseconds since Unix Epoch) at which the change was performed + pub timestamp_nanos: u64, + /// The canister version after performing the change. + pub canister_version: u64, + /// The change's origin (a user or a canister). + pub origin: CanisterChangeOrigin, + /// The change's details. + pub details: CanisterChangeDetails, +} + +/// Argument type of [canister_info](super::canister_info). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct CanisterInfoRequest { + /// Principle of the canister. + pub canister_id: Principal, + /// Number of most recent changes requested to be retrieved from canister history. + /// No changes are retrieved if this field is null. + pub num_requested_changes: Option, +} + +/// Return type of [canister_info](super::canister_info). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct CanisterInfoResponse { + /// Total number of changes ever recorded in canister history. + /// This might be higher than the number of canister changes in `recent_changes` + /// because the IC might drop old canister changes from its history + /// (with `20` most recent canister changes to always remain in the list). + pub total_num_changes: u64, + /// The canister changes stored in the order from the oldest to the most recent. + pub recent_changes: Vec, + /// A SHA256 hash of the module installed on the canister. This is null if the canister is empty. + pub module_hash: Option>, + /// Controllers of the canister. + pub controllers: Vec, +} From bfa2b386d16f6596f7a75349314932058da3c17c Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 20 Jun 2023 19:29:29 -0400 Subject: [PATCH 155/234] fix: no hard-coded fees for management canister calls (#404) * btc API fees * ecdsa fees * create canister fee * mv * split http_request * http_request fee * tests * doc * bump ver & changelog --- .github/workflows/examples.yml | 2 +- e2e-tests/canisters/canister_info.rs | 11 +- .../management_canister/src/caller/Cargo.toml | 1 - .../management_canister/src/caller/lib.rs | 60 ++-- examples/management_canister/src/main.rs | 3 - library/ic-certified-map/Cargo.toml | 2 +- library/ic-ledger-types/CHANGELOG.md | 4 + library/ic-ledger-types/Cargo.toml | 2 +- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-timers/CHANGELOG.md | 6 + src/ic-cdk-timers/Cargo.toml | 4 +- src/ic-cdk/CHANGELOG.md | 12 +- src/ic-cdk/Cargo.toml | 2 +- .../api/management_canister/bitcoin/mod.rs | 46 +-- .../src/api/management_canister/ecdsa/mod.rs | 18 +- .../api/management_canister/http_request.rs | 332 ------------------ .../management_canister/http_request/mod.rs | 100 ++++++ .../management_canister/http_request/types.rs | 143 ++++++++ .../src/api/management_canister/main/mod.rs | 47 +-- .../src/api/management_canister/main/types.rs | 1 - src/ic-cdk/src/api/management_canister/mod.rs | 4 +- .../api/management_canister/provisional.rs | 2 +- 22 files changed, 364 insertions(+), 440 deletions(-) delete mode 100644 examples/management_canister/src/main.rs delete mode 100644 src/ic-cdk/src/api/management_canister/http_request.rs create mode 100644 src/ic-cdk/src/api/management_canister/http_request/mod.rs create mode 100644 src/ic-cdk/src/api/management_canister/http_request/types.rs diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 5ded616b4..af6108f4d 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -12,7 +12,7 @@ concurrency: env: rust-version: 1.66.1 - dfx-version: 0.13.1 + dfx-version: 0.14.1 jobs: test: diff --git a/e2e-tests/canisters/canister_info.rs b/e2e-tests/canisters/canister_info.rs index 19d048040..d7208a206 100644 --- a/e2e-tests/canisters/canister_info.rs +++ b/e2e-tests/canisters/canister_info.rs @@ -17,10 +17,13 @@ async fn info(canister_id: Principal) -> CanisterInfoResponse { #[ic_cdk_macros::update] async fn canister_lifecycle() -> Principal { - let canister_id = create_canister(CreateCanisterArgument { settings: None }) - .await - .unwrap() - .0; + let canister_id = create_canister( + CreateCanisterArgument { settings: None }, + 100_000_000_000 / 13, + ) + .await + .unwrap() + .0; install_code(InstallCodeArgument { mode: Install, arg: vec![], diff --git a/examples/management_canister/src/caller/Cargo.toml b/examples/management_canister/src/caller/Cargo.toml index ed0d83eb9..56fc03b6c 100644 --- a/examples/management_canister/src/caller/Cargo.toml +++ b/examples/management_canister/src/caller/Cargo.toml @@ -11,5 +11,4 @@ crate-type = ["cdylib"] [dependencies] ic-cdk = { path = "../../../../src/ic-cdk", features = ["transform-closure"] } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } sha2 = "0.10" diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index 86d1b1970..5fd864dc7 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -13,16 +13,11 @@ mod main { freezing_threshold: Some(10000.into()), }), }; - create_canister(arg).await.unwrap(); - - let canister_id = create_canister_with_extra_cycles( - CreateCanisterArgument::default(), - 1_000_000_000_000u128, - ) - .await - .unwrap() - .0 - .canister_id; + let canister_id = create_canister(arg, 100_000_000_000u128 / 13) + .await + .unwrap() + .0 + .canister_id; let arg = UpdateSettingsArgument { canister_id, @@ -86,6 +81,18 @@ mod http_request { use super::*; use ic_cdk::api::management_canister::http_request::*; + fn http_request_required_cycles(arg: &CanisterHttpRequestArgument) -> u128 { + let max_response_bytes = match arg.max_response_bytes { + Some(ref n) => *n as u128, + None => 2 * 1024 * 1024u128, // default 2MiB + }; + let arg_raw = ic_cdk::export::candid::utils::encode_args((arg,)) + .expect("Failed to encode arguments."); + 400_000_000u128 / 13 + + 100_000u128 / 13 + * (arg_raw.len() as u128 + "http_request".len() as u128 + max_response_bytes) + } + #[update] async fn http_request_example() { let url = "https://example.com".to_string(); @@ -101,19 +108,8 @@ mod http_request { name: "custom-header".to_string(), value: "test".to_string(), }; - let response = http_request_with(arg.clone(), { - let header = header.clone(); - move |mut response| { - response.headers = vec![header]; - response - } - }) - .await - .unwrap() - .0; - assert_eq!(response.status, 200); - assert_eq!(response.headers.get(0), Some(&header)); - let response = http_request_with_cycles_with(arg, 718500000u128, { + let cycles = http_request_required_cycles(&arg); + let response = http_request_with_closure(arg.clone(), cycles, { let header = header.clone(); move |mut response| { response.headers = vec![header]; @@ -159,7 +155,10 @@ mod ecdsa { derivation_path, key_id, }; - let SignWithEcdsaResponse { signature } = sign_with_ecdsa(arg).await.unwrap().0; + let SignWithEcdsaResponse { signature } = sign_with_ecdsa(arg, 10_000_000_000u128 / 13) + .await + .unwrap() + .0; assert_eq!(signature.len(), 64); } } @@ -178,14 +177,14 @@ mod bitcoin { network, min_confirmations: Some(1), }; - let _balance = bitcoin_get_balance(arg).await.unwrap().0; + let _balance = bitcoin_get_balance(arg, 40_000_000u128).await.unwrap().0; let arg = GetUtxosRequest { address: address.clone(), network, filter: Some(UtxoFilter::MinConfirmations(1)), }; - let mut response = bitcoin_get_utxos(arg).await.unwrap().0; + let mut response = bitcoin_get_utxos(arg, 4_000_000_000u128).await.unwrap().0; while let Some(page) = response.next_page { ic_cdk::println!("bitcoin_get_utxos next page"); @@ -194,17 +193,20 @@ mod bitcoin { network, filter: Some(UtxoFilter::Page(page)), }; - response = bitcoin_get_utxos(arg).await.unwrap().0; + response = bitcoin_get_utxos(arg, 4_000_000_000u128).await.unwrap().0; } let arg = GetCurrentFeePercentilesRequest { network }; - let _percentiles = bitcoin_get_current_fee_percentiles(arg).await.unwrap().0; + let _percentiles = bitcoin_get_current_fee_percentiles(arg, 4_000_000u128) + .await + .unwrap() + .0; let arg = SendTransactionRequest { transaction: vec![], network, }; - let response = bitcoin_send_transaction(arg).await; + let response = bitcoin_send_transaction(arg, 2_000_000_000u128).await; assert!(response.is_err()); if let Err((rejection_code, rejection_reason)) = response { assert_eq!(rejection_code, RejectionCode::CanisterReject); diff --git a/examples/management_canister/src/main.rs b/examples/management_canister/src/main.rs deleted file mode 100644 index e7a11a969..000000000 --- a/examples/management_canister/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/library/ic-certified-map/Cargo.toml b/library/ic-certified-map/Cargo.toml index 1832e3eba..a4fec4f18 100644 --- a/library/ic-certified-map/Cargo.toml +++ b/library/ic-certified-map/Cargo.toml @@ -22,6 +22,6 @@ sha2 = "0.10" [dev-dependencies] hex = "0.4" serde_cbor = "0.11" -ic-cdk = { path = "../../src/ic-cdk" } +ic-cdk = { path = "../../src/ic-cdk", version = "0.9" } candid = "0.8" serde = "1" diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index d4b76d06b..666a68145 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.5.0] - 2023-06-20 +### Changed +- Upgrade `ic-cdk` to v0.9. + ## [0.5.0] - 2023-05-26 ### Changed - Upgrade `ic-cdk` to v0.8. diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 4108b802c..921ec44f7 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -17,7 +17,7 @@ rust-version = "1.65.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ic-cdk = { path = "../../src/ic-cdk", version = "0.8" } +ic-cdk = { path = "../../src/ic-cdk", version = "0.9" } candid = "0.8.0" crc32fast = "1.2.0" hex = "0.4" diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index af4c5f61a..20476be1a 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -27,4 +27,4 @@ serde = "1.0.111" [dev-dependencies] trybuild = "1.0" -ic-cdk = { path = "../ic-cdk", version = "0.8" } +ic-cdk = { path = "../ic-cdk", version = "0.9" } diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index 481ace290..ec6060990 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.3.0] - 2023-06-20 + +### Changed + +- Upgrade `ic-cdk` to v0.9. + ## [0.2.0] - 2023-05-26 ### Changed diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index 72f9fe9d4..24799ea1f 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.2.0" +version = "0.3.0" authors = ["DFINITY Stiftung "] edition = "2021" description = "Timers library for the Rust CDK." @@ -15,7 +15,7 @@ repository = "https://github.com/dfinity/cdk-rs" rust-version = "1.60.0" [dependencies] -ic-cdk = { path = "../../src/ic-cdk", version = "0.8" } +ic-cdk = { path = "../../src/ic-cdk", version = "0.9" } serde = "1.0.110" serde_bytes = "0.11.7" ic0 = { path = "../ic0", version = "0.18.9" } diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index d9dbb01e3..6fff27360 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,8 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -- Set caller's canister version in the field `sender_canister_version` of management canister call payloads. -- Add management canister types for `canister_info` management canister call (`CanisterInfoRequest` and `CanisterInfoResponse`). +## [0.9.0] - 2023-06-20 + +### Added + +- Set caller's canister version in the field `sender_canister_version` of management canister call payloads. (#401) +- Add management canister types for `canister_info` management canister call (`CanisterInfoRequest` and `CanisterInfoResponse`). (#401) + +### Changed + +- No hard-coded fees for management canister calls. (#404) ## [0.8.0] - 2023-05-26 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index df681fff9..4149197b8 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.8.1" +version = "0.9.0" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs b/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs index 025941220..8f99402cc 100644 --- a/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs +++ b/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs @@ -6,40 +6,42 @@ use candid::Principal; mod types; pub use types::*; -// The fees for the various bitcoin endpoints. -// TODO: where is the public doc of these parameters? -const GET_BALANCE_CYCLES: u128 = 100_000_000; -const GET_UTXOS_CYCLES: u128 = 100_000_000; -const GET_CURRENT_FEE_PERCENTILES_CYCLES: u128 = 100_000_000; -const SEND_TRANSACTION_BASE_CYCLES: u128 = 5_000_000_000; -const SEND_TRANSACTION_PER_BYTE_CYCLES: u128 = 20_000_000; - -/// See [IC method `bitcoin_get_balance`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_balance) -pub async fn bitcoin_get_balance(arg: GetBalanceRequest) -> CallResult<(Satoshi,)> { +/// See [IC method `bitcoin_get_balance`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_balance). +/// +/// This call requires cycles payment. The required cycles varies according to the subnet size (number of nodes). +/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. +pub async fn bitcoin_get_balance(arg: GetBalanceRequest, cycles: u128) -> CallResult<(Satoshi,)> { call_with_payment128( Principal::management_canister(), "bitcoin_get_balance", (arg,), - GET_BALANCE_CYCLES, + cycles, ) .await } -/// See [IC method `bitcoin_get_utxos`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_utxos) -pub async fn bitcoin_get_utxos(arg: GetUtxosRequest) -> CallResult<(GetUtxosResponse,)> { +/// See [IC method `bitcoin_get_utxos`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_utxos). +/// +/// This call requires cycles payment. The required cycles varies according to the subnet size (number of nodes). +/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. +pub async fn bitcoin_get_utxos( + arg: GetUtxosRequest, + cycles: u128, +) -> CallResult<(GetUtxosResponse,)> { call_with_payment128( Principal::management_canister(), "bitcoin_get_utxos", (arg,), - GET_UTXOS_CYCLES, + cycles, ) .await } -/// See [IC method `bitcoin_send_transaction`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_send_transaction) -pub async fn bitcoin_send_transaction(arg: SendTransactionRequest) -> CallResult<()> { - let cycles = SEND_TRANSACTION_BASE_CYCLES - + (arg.transaction.len() as u128) * SEND_TRANSACTION_PER_BYTE_CYCLES; +/// See [IC method `bitcoin_send_transaction`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_send_transaction). +/// +/// This call requires cycles payment. The required cycles varies according to the subnet size (number of nodes). +/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. +pub async fn bitcoin_send_transaction(arg: SendTransactionRequest, cycles: u128) -> CallResult<()> { call_with_payment128( Principal::management_canister(), "bitcoin_send_transaction", @@ -49,15 +51,19 @@ pub async fn bitcoin_send_transaction(arg: SendTransactionRequest) -> CallResult .await } -/// See [IC method `bitcoin_get_current_fee_percentiles`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_current_fee_percentiles) +/// See [IC method `bitcoin_get_current_fee_percentiles`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_current_fee_percentiles). +/// +/// This call requires cycles payment. The required cycles varies according to the subnet size (number of nodes). +/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. pub async fn bitcoin_get_current_fee_percentiles( arg: GetCurrentFeePercentilesRequest, + cycles: u128, ) -> CallResult<(Vec,)> { call_with_payment128( Principal::management_canister(), "bitcoin_get_current_fee_percentiles", (arg,), - GET_CURRENT_FEE_PERCENTILES_CYCLES, + cycles, ) .await } diff --git a/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs b/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs index cb444ba80..a679ed3bf 100644 --- a/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs +++ b/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs @@ -1,6 +1,6 @@ //! The ECDSA API. -use crate::api::call::{call, CallResult}; +use crate::api::call::{call, call_with_payment128, CallResult}; use candid::Principal; mod types; @@ -18,6 +18,18 @@ pub async fn ecdsa_public_key( /// Return a new ECDSA signature of the given message_hash that can be separately verified against a derived ECDSA public key. /// /// See [IC method `sign_with_ecdsa`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-sign_with_ecdsa). -pub async fn sign_with_ecdsa(arg: SignWithEcdsaArgument) -> CallResult<(SignWithEcdsaResponse,)> { - call(Principal::management_canister(), "sign_with_ecdsa", (arg,)).await +/// +/// This call requires cycles payment. The required cycles varies according to the subnet size (number of nodes). +/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. +pub async fn sign_with_ecdsa( + arg: SignWithEcdsaArgument, + cycles: u128, +) -> CallResult<(SignWithEcdsaResponse,)> { + call_with_payment128( + Principal::management_canister(), + "sign_with_ecdsa", + (arg,), + cycles, + ) + .await } diff --git a/src/ic-cdk/src/api/management_canister/http_request.rs b/src/ic-cdk/src/api/management_canister/http_request.rs deleted file mode 100644 index af7b674bd..000000000 --- a/src/ic-cdk/src/api/management_canister/http_request.rs +++ /dev/null @@ -1,332 +0,0 @@ -//! Canister HTTP request. - -use crate::{ - api::call::{call_with_payment128, CallResult}, - id, -}; -use candid::{ - parser::types::FuncMode, - types::{Function, Serializer, Type}, - CandidType, Func, Principal, -}; -use core::hash::Hash; -use serde::{Deserialize, Serialize}; -#[cfg(feature = "transform-closure")] -use slotmap::{DefaultKey, Key, SlotMap}; -#[cfg(feature = "transform-closure")] -use std::cell::RefCell; - -/// "transform" function of type: `func (http_request) -> (http_response) query` -#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct TransformFunc(pub candid::Func); - -impl CandidType for TransformFunc { - fn _ty() -> Type { - Type::Func(Function { - modes: vec![FuncMode::Query], - args: vec![TransformArgs::ty()], - rets: vec![HttpResponse::ty()], - }) - } - - fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> { - serializer.serialize_function(self.0.principal.as_slice(), &self.0.method) - } -} - -/// Type used for encoding/decoding: -/// `record { -/// response : http_response; -/// context : blob; -/// }` -#[derive(CandidType, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct TransformArgs { - /// Raw response from remote service, to be transformed - pub response: HttpResponse, - - /// Context for response transformation - #[serde(with = "serde_bytes")] - pub context: Vec, -} - -/// Type used for encoding/decoding: -/// `record { -/// function : func (record {response : http_response; context : blob}) -> (http_response) query; -/// context : blob; -/// }` -#[derive(CandidType, Clone, Debug, Deserialize, PartialEq, Eq)] -pub struct TransformContext { - /// Reference function with signature: `func (record {response : http_response; context : blob}) -> (http_response) query;`. - pub function: TransformFunc, - - /// Context to be passed to `transform` function to transform HTTP response for consensus - #[serde(with = "serde_bytes")] - pub context: Vec, -} - -impl TransformContext { - /// Constructs a TransformContext from a name and context. The principal is assumed to be the [current canister's](id). - pub fn from_name(candid_function_name: String, context: Vec) -> Self { - Self { - context, - function: TransformFunc(Func { - method: candid_function_name, - principal: id(), - }), - } - } -} - -#[cfg(feature = "transform-closure")] -thread_local! { - #[allow(clippy::type_complexity)] - static TRANSFORMS: RefCell HttpResponse>>> = RefCell::default(); -} - -#[cfg(feature = "transform-closure")] -#[export_name = "canister_query http_transform"] -extern "C" fn http_transform() { - use crate::api::{ - call::{arg_data, reply}, - caller, - }; - use slotmap::KeyData; - if caller() != Principal::management_canister() { - crate::trap("This function is internal to ic-cdk and should not be called externally."); - } - crate::setup(); - let (args,): (TransformArgs,) = arg_data(); - let int = u64::from_be_bytes(args.context[..].try_into().unwrap()); - let key = DefaultKey::from(KeyData::from_ffi(int)); - let func = TRANSFORMS.with(|transforms| transforms.borrow_mut().remove(key)); - let Some(func) = func else { - crate::trap(&format!("Missing transform function for request {int}")); - }; - let transformed = func(args.response); - reply((transformed,)) -} - -/// HTTP header. -#[derive( - CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, -)] -pub struct HttpHeader { - /// Name - pub name: String, - /// Value - pub value: String, -} - -/// HTTP method. -/// -/// Currently support following methods. -#[derive( - CandidType, - Serialize, - Deserialize, - Debug, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Clone, - Copy, - Default, -)] -pub enum HttpMethod { - /// GET - #[serde(rename = "get")] - #[default] - GET, - /// POST - #[serde(rename = "post")] - POST, - /// HEAD - #[serde(rename = "head")] - HEAD, -} - -/// Argument type of [http_request]. -#[derive(CandidType, Deserialize, Debug, PartialEq, Eq, Clone, Default)] -pub struct CanisterHttpRequestArgument { - /// The requested URL. - pub url: String, - /// The maximal size of the response in bytes. If None, 2MiB will be the limit. - /// This value affects the cost of the http request and it is highly recommended - /// to set it as low as possible to avoid unnecessary extra costs. - /// See also the [pricing section of HTTP outcalls documentation](https://internetcomputer.org/docs/current/developer-docs/integrations/http_requests/http_requests-how-it-works#pricing). - pub max_response_bytes: Option, - /// The method of HTTP request. - pub method: HttpMethod, - /// List of HTTP request headers and their corresponding values. - pub headers: Vec, - /// Optionally provide request body. - pub body: Option>, - /// Name of the transform function which is `func (transform_args) -> (http_response) query`. - /// Set to `None` if you are using `http_request_with` or `http_request_with_cycles_with`. - pub transform: Option, -} - -/// The returned HTTP response. -#[derive( - CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, -)] -pub struct HttpResponse { - /// The response status (e.g., 200, 404). - pub status: candid::Nat, - /// List of HTTP response headers and their corresponding values. - pub headers: Vec, - /// The response’s body. - pub body: Vec, -} - -/// Make an HTTP request to a given URL and return the HTTP response, possibly after a transformation. -/// -/// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). -/// -/// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. -/// This method handles the cycles cost calculation under the hood which assuming the canister is on a 13-node Application Subnet. -/// If the canister is on a 34-node Application Subnets, you may have to compute the cost by yourself and call [`http_request_with_cycles`] instead. -/// -/// Check [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs) for more details. -pub async fn http_request(arg: CanisterHttpRequestArgument) -> CallResult<(HttpResponse,)> { - let cycles = http_request_required_cycles(&arg); - call_with_payment128( - Principal::management_canister(), - "http_request", - (arg,), - cycles, - ) - .await -} - -/// Make an HTTP request to a given URL and return the HTTP response, after a transformation. -/// -/// Do not set the `transform` field of `arg`. To use a Candid function, call [`http_request`] instead. -/// -/// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). -/// -/// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. -/// This method handles the cycles cost calculation under the hood which assuming the canister is on a 13-node Application Subnet. -/// If the canister is on a 34-node Application Subnets, you may have to compute the cost by yourself and call [`http_request_with_cycles_with`] instead. -/// -/// Check [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs) for more details. -#[cfg(feature = "transform-closure")] -#[cfg_attr(docsrs, doc(cfg(feature = "transform-closure")))] -pub async fn http_request_with( - arg: CanisterHttpRequestArgument, - transform_func: impl FnOnce(HttpResponse) -> HttpResponse + 'static, -) -> CallResult<(HttpResponse,)> { - let cycles = http_request_required_cycles(&arg); - http_request_with_cycles_with(arg, cycles, transform_func).await -} - -/// Make an HTTP request to a given URL and return the HTTP response, possibly after a transformation. -/// -/// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). -/// -/// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. -/// Check [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs) for more details. -/// -/// If the canister is on a 13-node Application Subnet, you can call [`http_request`] instead which handles cycles cost calculation under the hood. -pub async fn http_request_with_cycles( - arg: CanisterHttpRequestArgument, - cycles: u128, -) -> CallResult<(HttpResponse,)> { - call_with_payment128( - Principal::management_canister(), - "http_request", - (arg,), - cycles, - ) - .await -} - -/// Make an HTTP request to a given URL and return the HTTP response, after a transformation. -/// -/// Do not set the `transform` field of `arg`. To use a Candid function, call [`http_request_with_cycles`] instead. -/// -/// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). -/// -/// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. -/// Check [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs) for more details. -/// -/// If the canister is on a 13-node Application Subnet, you can call [`http_request_with`] instead which handles cycles cost calculation under the hood. -#[cfg(feature = "transform-closure")] -#[cfg_attr(docsrs, doc(cfg(feature = "transform-closure")))] -pub async fn http_request_with_cycles_with( - arg: CanisterHttpRequestArgument, - cycles: u128, - transform_func: impl FnOnce(HttpResponse) -> HttpResponse + 'static, -) -> CallResult<(HttpResponse,)> { - assert!( - arg.transform.is_none(), - "`CanisterHttpRequestArgument`'s `transform` field must be `None` when using a closure" - ); - let transform_func = Box::new(transform_func) as _; - let key = TRANSFORMS.with(|transforms| transforms.borrow_mut().insert(transform_func)); - struct DropGuard(DefaultKey); - impl Drop for DropGuard { - fn drop(&mut self) { - TRANSFORMS.with(|transforms| transforms.borrow_mut().remove(self.0)); - } - } - let key = DropGuard(key); - let context = key.0.data().as_ffi().to_be_bytes().to_vec(); - let arg = CanisterHttpRequestArgument { - transform: Some(TransformContext { - function: TransformFunc(candid::Func { - method: " http_transform".into(), - principal: crate::id(), - }), - context, - }), - ..arg - }; - http_request_with_cycles(arg, cycles).await -} - -fn http_request_required_cycles(arg: &CanisterHttpRequestArgument) -> u128 { - let max_response_bytes = match arg.max_response_bytes { - Some(ref n) => *n as u128, - None => 2 * 1024 * 1024u128, // default 2MiB - }; - let arg_raw = candid::utils::encode_args((arg,)).expect("Failed to encode arguments."); - // The coefficients can be found in [this page](https://internetcomputer.org/docs/current/developer-docs/production/computation-and-storage-costs). - // 12 is "http_request".len(). - 400_000_000u128 + 100_000u128 * (arg_raw.len() as u128 + 12 + max_response_bytes) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn required_cycles_some_max() { - let url = "https://example.com".to_string(); - let arg = CanisterHttpRequestArgument { - url, - max_response_bytes: Some(3000), - method: HttpMethod::GET, - headers: vec![], - body: None, - transform: None, - }; - assert_eq!(http_request_required_cycles(&arg), 718500000u128); - } - - #[test] - fn required_cycles_none_max() { - let url = "https://example.com".to_string(); - let arg = CanisterHttpRequestArgument { - url, - max_response_bytes: None, - method: HttpMethod::GET, - headers: vec![], - body: None, - transform: None, - }; - assert_eq!(http_request_required_cycles(&arg), 210132900000u128); - } -} diff --git a/src/ic-cdk/src/api/management_canister/http_request/mod.rs b/src/ic-cdk/src/api/management_canister/http_request/mod.rs new file mode 100644 index 000000000..aebd4776f --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/http_request/mod.rs @@ -0,0 +1,100 @@ +//! Canister HTTP request. + +use crate::api::call::{call_with_payment128, CallResult}; +use candid::Principal; +#[cfg(feature = "transform-closure")] +use slotmap::{DefaultKey, Key, KeyData, SlotMap}; +#[cfg(feature = "transform-closure")] +use std::cell::RefCell; + +mod types; +pub use types::*; + +/// Make an HTTP request to a given URL and return the HTTP response, possibly after a transformation. +/// +/// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). +/// +/// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. +/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. +pub async fn http_request( + arg: CanisterHttpRequestArgument, + cycles: u128, +) -> CallResult<(HttpResponse,)> { + call_with_payment128( + Principal::management_canister(), + "http_request", + (arg,), + cycles, + ) + .await +} + +#[cfg(feature = "transform-closure")] +thread_local! { + #[allow(clippy::type_complexity)] + static TRANSFORMS: RefCell HttpResponse>>> = RefCell::default(); +} + +#[cfg(feature = "transform-closure")] +#[export_name = "canister_query http_transform"] +extern "C" fn http_transform() { + use crate::api::{ + call::{arg_data, reply}, + caller, + }; + if caller() != Principal::management_canister() { + crate::trap("This function is internal to ic-cdk and should not be called externally."); + } + crate::setup(); + let (args,): (TransformArgs,) = arg_data(); + let int = u64::from_be_bytes(args.context[..].try_into().unwrap()); + let key = DefaultKey::from(KeyData::from_ffi(int)); + let func = TRANSFORMS.with(|transforms| transforms.borrow_mut().remove(key)); + let Some(func) = func else { + crate::trap(&format!("Missing transform function for request {int}")); + }; + let transformed = func(args.response); + reply((transformed,)) +} + +/// Make an HTTP request to a given URL and return the HTTP response, after a transformation. +/// +/// Do not set the `transform` field of `arg`. To use a Candid function, call [`http_request`] instead. +/// +/// See [IC method `http_request`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request). +/// +/// This call requires cycles payment. The required cycles is a function of the request size and max_response_bytes. +/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. +#[cfg(feature = "transform-closure")] +#[cfg_attr(docsrs, doc(cfg(feature = "transform-closure")))] +pub async fn http_request_with_closure( + arg: CanisterHttpRequestArgument, + cycles: u128, + transform_func: impl FnOnce(HttpResponse) -> HttpResponse + 'static, +) -> CallResult<(HttpResponse,)> { + assert!( + arg.transform.is_none(), + "`CanisterHttpRequestArgument`'s `transform` field must be `None` when using a closure" + ); + let transform_func = Box::new(transform_func) as _; + let key = TRANSFORMS.with(|transforms| transforms.borrow_mut().insert(transform_func)); + struct DropGuard(DefaultKey); + impl Drop for DropGuard { + fn drop(&mut self) { + TRANSFORMS.with(|transforms| transforms.borrow_mut().remove(self.0)); + } + } + let key = DropGuard(key); + let context = key.0.data().as_ffi().to_be_bytes().to_vec(); + let arg = CanisterHttpRequestArgument { + transform: Some(TransformContext { + function: TransformFunc(candid::Func { + method: " http_transform".into(), + principal: crate::id(), + }), + context, + }), + ..arg + }; + http_request(arg, cycles).await +} diff --git a/src/ic-cdk/src/api/management_canister/http_request/types.rs b/src/ic-cdk/src/api/management_canister/http_request/types.rs new file mode 100644 index 000000000..e05b1585b --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/http_request/types.rs @@ -0,0 +1,143 @@ +use crate::id; +use candid::{ + parser::types::FuncMode, + types::{Function, Serializer, Type}, + CandidType, Func, +}; +use serde::{Deserialize, Serialize}; + +/// "transform" function of type: `func (http_request) -> (http_response) query` +#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct TransformFunc(pub candid::Func); + +impl CandidType for TransformFunc { + fn _ty() -> Type { + Type::Func(Function { + modes: vec![FuncMode::Query], + args: vec![TransformArgs::ty()], + rets: vec![HttpResponse::ty()], + }) + } + + fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> { + serializer.serialize_function(self.0.principal.as_slice(), &self.0.method) + } +} + +/// Type used for encoding/decoding: +/// `record { +/// response : http_response; +/// context : blob; +/// }` +#[derive(CandidType, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct TransformArgs { + /// Raw response from remote service, to be transformed + pub response: HttpResponse, + + /// Context for response transformation + #[serde(with = "serde_bytes")] + pub context: Vec, +} + +/// Type used for encoding/decoding: +/// `record { +/// function : func (record {response : http_response; context : blob}) -> (http_response) query; +/// context : blob; +/// }` +#[derive(CandidType, Clone, Debug, Deserialize, PartialEq, Eq)] +pub struct TransformContext { + /// Reference function with signature: `func (record {response : http_response; context : blob}) -> (http_response) query;`. + pub function: TransformFunc, + + /// Context to be passed to `transform` function to transform HTTP response for consensus + #[serde(with = "serde_bytes")] + pub context: Vec, +} + +impl TransformContext { + /// Constructs a TransformContext from a name and context. The principal is assumed to be the [current canister's](id). + pub fn from_name(candid_function_name: String, context: Vec) -> Self { + Self { + context, + function: TransformFunc(Func { + method: candid_function_name, + principal: id(), + }), + } + } +} + +/// HTTP header. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct HttpHeader { + /// Name + pub name: String, + /// Value + pub value: String, +} + +/// HTTP method. +/// +/// Currently support following methods. +#[derive( + CandidType, + Serialize, + Deserialize, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Clone, + Copy, + Default, +)] +pub enum HttpMethod { + /// GET + #[serde(rename = "get")] + #[default] + GET, + /// POST + #[serde(rename = "post")] + POST, + /// HEAD + #[serde(rename = "head")] + HEAD, +} + +/// Argument type of [http_request]. +#[derive(CandidType, Deserialize, Debug, PartialEq, Eq, Clone, Default)] +pub struct CanisterHttpRequestArgument { + /// The requested URL. + pub url: String, + /// The maximal size of the response in bytes. If None, 2MiB will be the limit. + /// This value affects the cost of the http request and it is highly recommended + /// to set it as low as possible to avoid unnecessary extra costs. + /// See also the [pricing section of HTTP outcalls documentation](https://internetcomputer.org/docs/current/developer-docs/integrations/http_requests/http_requests-how-it-works#pricing). + pub max_response_bytes: Option, + /// The method of HTTP request. + pub method: HttpMethod, + /// List of HTTP request headers and their corresponding values. + pub headers: Vec, + /// Optionally provide request body. + pub body: Option>, + /// Name of the transform function which is `func (transform_args) -> (http_response) query`. + /// Set to `None` if you are using `http_request_with` or `http_request_with_cycles_with`. + pub transform: Option, +} + +/// The returned HTTP response. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct HttpResponse { + /// The response status (e.g., 200, 404). + pub status: candid::Nat, + /// List of HTTP response headers and their corresponding values. + pub headers: Vec, + /// The response’s body. + pub body: Vec, +} diff --git a/src/ic-cdk/src/api/management_canister/main/mod.rs b/src/ic-cdk/src/api/management_canister/main/mod.rs index 786026ce3..02a83d028 100644 --- a/src/ic-cdk/src/api/management_canister/main/mod.rs +++ b/src/ic-cdk/src/api/management_canister/main/mod.rs @@ -12,36 +12,13 @@ use candid::Principal; mod types; pub use types::*; -/// Cycles cost to create a canister. -/// -/// See [Computation and Storage Costs](https://internetcomputer.org/docs/current/developer-docs/deploy/computation-and-storage-costs) -pub const CREATE_CANISTER_CYCLES: u128 = 100_000_000_000u128; - /// Register a new canister and get its canister id. /// -/// Note: This call charges [CREATE_CANISTER_CYCLES] from the caller canister. -/// /// See [IC method `create_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-create_canister). -pub async fn create_canister(arg: CreateCanisterArgument) -> CallResult<(CanisterIdRecord,)> { - let extended_arg = CreateCanisterArgumentExtended { - settings: arg.settings, - sender_canister_version: Some(canister_version()), - }; - call_with_payment128( - Principal::management_canister(), - "create_canister", - (extended_arg,), - CREATE_CANISTER_CYCLES, - ) - .await -} - -/// [create_canister] and specify extra cycles to the new canister. -/// -/// Note: This call charges [CREATE_CANISTER_CYCLES] and the specified extra cycles from the caller canister. /// -/// See [IC method `create_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-create_canister). -pub async fn create_canister_with_extra_cycles( +/// This call requires cycles payment. The required cycles varies according to the subnet size (number of nodes). +/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. +pub async fn create_canister( arg: CreateCanisterArgument, cycles: u128, ) -> CallResult<(CanisterIdRecord,)> { @@ -53,7 +30,7 @@ pub async fn create_canister_with_extra_cycles( Principal::management_canister(), "create_canister", (extended_arg,), - CREATE_CANISTER_CYCLES + cycles, + cycles, ) .await } @@ -96,7 +73,7 @@ pub async fn install_code(arg: InstallCodeArgument) -> CallResult<()> { /// Remove a canister's code and state, making the canister empty again. /// -/// See [IC method `uninstall_code`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-uninstall_code) +/// See [IC method `uninstall_code`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-uninstall_code). pub async fn uninstall_code(arg: CanisterIdRecord) -> CallResult<()> { let extended_arg = CanisterIdRecordExtended { canister_id: arg.canister_id, @@ -112,28 +89,28 @@ pub async fn uninstall_code(arg: CanisterIdRecord) -> CallResult<()> { /// Start a canister if the canister status was `stopped` or `stopping`. /// -/// See [IC method `start_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-start_canister) +/// See [IC method `start_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-start_canister). pub async fn start_canister(arg: CanisterIdRecord) -> CallResult<()> { call(Principal::management_canister(), "start_canister", (arg,)).await } /// Stop a canister. /// -/// See [IC method `stop_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-stop_canister) +/// See [IC method `stop_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-stop_canister). pub async fn stop_canister(arg: CanisterIdRecord) -> CallResult<()> { call(Principal::management_canister(), "stop_canister", (arg,)).await } /// Get status information about the canister. /// -/// See [IC method `canister_status`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-canister_status) +/// See [IC method `canister_status`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-canister_status). pub async fn canister_status(arg: CanisterIdRecord) -> CallResult<(CanisterStatusResponse,)> { call(Principal::management_canister(), "canister_status", (arg,)).await } /// Delete a canister from the IC. /// -/// See [IC method `delete_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-delete_canister) +/// See [IC method `delete_canister`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-delete_canister). pub async fn delete_canister(arg: CanisterIdRecord) -> CallResult<()> { call(Principal::management_canister(), "delete_canister", (arg,)).await } @@ -143,7 +120,7 @@ pub async fn delete_canister(arg: CanisterIdRecord) -> CallResult<()> { /// Note that, beyond the argument as specified in the interface description, /// there is a second parameter `cycles` which is the amount of cycles to be deposited. /// -/// See [IC method `deposit_cycles`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-deposit_cycles) +/// See [IC method `deposit_cycles`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-deposit_cycles). pub async fn deposit_cycles(arg: CanisterIdRecord, cycles: u128) -> CallResult<()> { call_with_payment128( Principal::management_canister(), @@ -156,14 +133,14 @@ pub async fn deposit_cycles(arg: CanisterIdRecord, cycles: u128) -> CallResult<( /// Get 32 pseudo-random bytes. /// -/// See [IC method `raw_rand`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-raw_rand) +/// See [IC method `raw_rand`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-raw_rand). pub async fn raw_rand() -> CallResult<(Vec,)> { call(Principal::management_canister(), "raw_rand", ()).await } /// Get public information about the canister. /// -/// See [IC method `canister_info`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-canister_info) +/// See [IC method `canister_info`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-canister_info). pub async fn canister_info(arg: CanisterInfoRequest) -> CallResult<(CanisterInfoResponse,)> { call(Principal::management_canister(), "canister_info", (arg,)).await } diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index 05d79c33d..685b1439f 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -137,7 +137,6 @@ pub(crate) struct CanisterIdRecordExtended { #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, )] -// #[serde(rename_all = "lowercase")] pub enum CanisterStatusType { /// The canister is running. #[serde(rename = "running")] diff --git a/src/ic-cdk/src/api/management_canister/mod.rs b/src/ic-cdk/src/api/management_canister/mod.rs index 77217cf2f..85481ce5b 100644 --- a/src/ic-cdk/src/api/management_canister/mod.rs +++ b/src/ic-cdk/src/api/management_canister/mod.rs @@ -1,11 +1,11 @@ //! Functions and types for calling [the IC management canister][1]. //! -//! This module is a direct translation from the [interface decription][2]. +//! This module is a direct translation from the [interface description][2]. //! //! The functions and types defined in this module serves these purposes: //! * Make it easy to construct correct request data. -//! * For those calls require cycles payments, they are handled behind-the-scenes. //! * Handle the response ergonomically. +//! * For those calls require cycles payments, the cycles amount is an explicit argument. //! //! [1]: https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-management-canister //! [2]: https://internetcomputer.org/assets/files/ic-a45d11feb0ba0494055083f9d2d21ddf.did diff --git a/src/ic-cdk/src/api/management_canister/provisional.rs b/src/ic-cdk/src/api/management_canister/provisional.rs index ce449d77f..504648fb1 100644 --- a/src/ic-cdk/src/api/management_canister/provisional.rs +++ b/src/ic-cdk/src/api/management_canister/provisional.rs @@ -28,7 +28,7 @@ pub struct ProvisionalTopUpCanisterArgument { pub amount: Nat, } -/// Create a new canister with specified amout of cycles balance. +/// Create a new canister with specified amount of cycles balance. /// /// This method is only available in local development instances. /// From 7140125f42e23a14c1cfbd8d1b2bf9fe8426e96d Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 20 Jun 2023 20:01:03 -0400 Subject: [PATCH 156/234] bump ver (#405) --- library/ic-ledger-types/CHANGELOG.md | 2 +- library/ic-ledger-types/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index 666a68145..1d4727a58 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,7 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -## [0.5.0] - 2023-06-20 +## [0.6.0] - 2023-06-20 ### Changed - Upgrade `ic-cdk` to v0.9. diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 921ec44f7..df047e143 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.5.0" +version = "0.6.0" edition = "2021" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." From 46cc4ea1a92bdbbadebf5a90bddc862ebd95eb41 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 21 Jun 2023 15:10:59 -0400 Subject: [PATCH 157/234] feat: Bitcoin API handles cycles cost under the hood. (#406) * bitcoin fee * bump ver & changelog --- .../management_canister/src/caller/lib.rs | 13 ++-- src/ic-cdk/CHANGELOG.md | 8 +- src/ic-cdk/Cargo.toml | 2 +- .../api/management_canister/bitcoin/mod.rs | 78 +++++++++++++++---- 4 files changed, 76 insertions(+), 25 deletions(-) diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index 5fd864dc7..dbf72e119 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -177,14 +177,14 @@ mod bitcoin { network, min_confirmations: Some(1), }; - let _balance = bitcoin_get_balance(arg, 40_000_000u128).await.unwrap().0; + let _balance = bitcoin_get_balance(arg).await.unwrap().0; let arg = GetUtxosRequest { address: address.clone(), network, filter: Some(UtxoFilter::MinConfirmations(1)), }; - let mut response = bitcoin_get_utxos(arg, 4_000_000_000u128).await.unwrap().0; + let mut response = bitcoin_get_utxos(arg).await.unwrap().0; while let Some(page) = response.next_page { ic_cdk::println!("bitcoin_get_utxos next page"); @@ -193,20 +193,17 @@ mod bitcoin { network, filter: Some(UtxoFilter::Page(page)), }; - response = bitcoin_get_utxos(arg, 4_000_000_000u128).await.unwrap().0; + response = bitcoin_get_utxos(arg).await.unwrap().0; } let arg = GetCurrentFeePercentilesRequest { network }; - let _percentiles = bitcoin_get_current_fee_percentiles(arg, 4_000_000u128) - .await - .unwrap() - .0; + let _percentiles = bitcoin_get_current_fee_percentiles(arg).await.unwrap().0; let arg = SendTransactionRequest { transaction: vec![], network, }; - let response = bitcoin_send_transaction(arg, 2_000_000_000u128).await; + let response = bitcoin_send_transaction(arg).await; assert!(response.is_err()); if let Err((rejection_code, rejection_reason)) = response { assert_eq!(rejection_code, RejectionCode::CanisterReject); diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 6fff27360..d0439a938 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,7 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -## [0.9.0] - 2023-06-20 +## [0.9.1] - 2023-06-21 + +### Changed + +- Bitcoin API handles cycles cost under the hood. (#406) + +## [0.9.0] - 2023-06-20 (yanked) ### Added diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 4149197b8..ec86fc863 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.9.0" +version = "0.9.1" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs b/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs index 8f99402cc..4769f17ee 100644 --- a/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs +++ b/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs @@ -1,4 +1,6 @@ //! The IC Bitcoin API. +//! +//! Check [Bitcoin integration](https://internetcomputer.org/docs/current/developer-docs/integrations/bitcoin/bitcoin-how-it-works/#api) for more details. use crate::api::call::{call_with_payment128, CallResult}; use candid::Principal; @@ -6,11 +8,32 @@ use candid::Principal; mod types; pub use types::*; +const GET_UTXO_MAINNET: u128 = 10_000_000_000; +const GET_UTXO_TESTNET: u128 = 4_000_000_000; + +const GET_CURRENT_FEE_PERCENTILES_MAINNET: u128 = 100_000_000; +const GET_CURRENT_FEE_PERCENTILES_TESTNET: u128 = 40_000_000; + +const GET_BALANCE_MAINNET: u128 = 100_000_000; +const GET_BALANCE_TESTNET: u128 = 40_000_000; + +const SEND_TRANSACTION_SUBMISSION_MAINNET: u128 = 5_000_000_000; +const SEND_TRANSACTION_SUBMISSION_TESTNET: u128 = 2_000_000_000; + +const SEND_TRANSACTION_PAYLOAD_MAINNET: u128 = 20_000_000; +const SEND_TRANSACTION_PAYLOAD_TESTNET: u128 = 8_000_000; + /// See [IC method `bitcoin_get_balance`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_balance). /// -/// This call requires cycles payment. The required cycles varies according to the subnet size (number of nodes). -/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. -pub async fn bitcoin_get_balance(arg: GetBalanceRequest, cycles: u128) -> CallResult<(Satoshi,)> { +/// This call requires cycles payment. +/// This method handles the cycles cost under the hood. +/// Check [API fees & Pricing](https://internetcomputer.org/docs/current/developer-docs/integrations/bitcoin/bitcoin-how-it-works/#api-fees--pricing) for more details. +pub async fn bitcoin_get_balance(arg: GetBalanceRequest) -> CallResult<(Satoshi,)> { + let cycles = match arg.network { + BitcoinNetwork::Mainnet => GET_BALANCE_MAINNET, + BitcoinNetwork::Testnet => GET_BALANCE_TESTNET, + BitcoinNetwork::Regtest => 0, + }; call_with_payment128( Principal::management_canister(), "bitcoin_get_balance", @@ -22,12 +45,15 @@ pub async fn bitcoin_get_balance(arg: GetBalanceRequest, cycles: u128) -> CallRe /// See [IC method `bitcoin_get_utxos`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_utxos). /// -/// This call requires cycles payment. The required cycles varies according to the subnet size (number of nodes). -/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. -pub async fn bitcoin_get_utxos( - arg: GetUtxosRequest, - cycles: u128, -) -> CallResult<(GetUtxosResponse,)> { +/// This call requires cycles payment. +/// This method handles the cycles cost under the hood. +/// Check [API fees & Pricing](https://internetcomputer.org/docs/current/developer-docs/integrations/bitcoin/bitcoin-how-it-works/#api-fees--pricing) for more details. +pub async fn bitcoin_get_utxos(arg: GetUtxosRequest) -> CallResult<(GetUtxosResponse,)> { + let cycles = match arg.network { + BitcoinNetwork::Mainnet => GET_UTXO_MAINNET, + BitcoinNetwork::Testnet => GET_UTXO_TESTNET, + BitcoinNetwork::Regtest => 0, + }; call_with_payment128( Principal::management_canister(), "bitcoin_get_utxos", @@ -37,11 +63,28 @@ pub async fn bitcoin_get_utxos( .await } +fn send_transaction_fee(arg: &SendTransactionRequest) -> u128 { + let (submission, payload) = match arg.network { + BitcoinNetwork::Mainnet => ( + SEND_TRANSACTION_SUBMISSION_MAINNET, + SEND_TRANSACTION_PAYLOAD_MAINNET, + ), + BitcoinNetwork::Testnet => ( + SEND_TRANSACTION_SUBMISSION_TESTNET, + SEND_TRANSACTION_PAYLOAD_TESTNET, + ), + BitcoinNetwork::Regtest => (0, 0), + }; + submission + payload * arg.transaction.len() as u128 +} + /// See [IC method `bitcoin_send_transaction`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_send_transaction). /// -/// This call requires cycles payment. The required cycles varies according to the subnet size (number of nodes). -/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. -pub async fn bitcoin_send_transaction(arg: SendTransactionRequest, cycles: u128) -> CallResult<()> { +/// This call requires cycles payment. +/// This method handles the cycles cost under the hood. +/// Check [API fees & Pricing](https://internetcomputer.org/docs/current/developer-docs/integrations/bitcoin/bitcoin-how-it-works/#api-fees--pricing) for more details. +pub async fn bitcoin_send_transaction(arg: SendTransactionRequest) -> CallResult<()> { + let cycles = send_transaction_fee(&arg); call_with_payment128( Principal::management_canister(), "bitcoin_send_transaction", @@ -53,12 +96,17 @@ pub async fn bitcoin_send_transaction(arg: SendTransactionRequest, cycles: u128) /// See [IC method `bitcoin_get_current_fee_percentiles`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_current_fee_percentiles). /// -/// This call requires cycles payment. The required cycles varies according to the subnet size (number of nodes). -/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. +/// This call requires cycles payment. +/// This method handles the cycles cost under the hood. +/// Check [API fees & Pricing](https://internetcomputer.org/docs/current/developer-docs/integrations/bitcoin/bitcoin-how-it-works/#api-fees--pricing) for more details. pub async fn bitcoin_get_current_fee_percentiles( arg: GetCurrentFeePercentilesRequest, - cycles: u128, ) -> CallResult<(Vec,)> { + let cycles = match arg.network { + BitcoinNetwork::Mainnet => GET_CURRENT_FEE_PERCENTILES_MAINNET, + BitcoinNetwork::Testnet => GET_CURRENT_FEE_PERCENTILES_TESTNET, + BitcoinNetwork::Regtest => 0, + }; call_with_payment128( Principal::management_canister(), "bitcoin_get_current_fee_percentiles", From 155c2dfff918a7a9bd49062bea2dba9e3ea490a0 Mon Sep 17 00:00:00 2001 From: Islam El-Ashi Date: Thu, 22 Jun 2023 12:29:52 +0200 Subject: [PATCH 158/234] feat: Hardcodes the fee for `sign_with_ecdsa`. (#407) * enhancements to bitcoin and ecdsa * cargo fmt * add back bitcoin prefix * bump ver and changelog * doc * fix example * fmt --------- Co-authored-by: Linwei Shang --- examples/management_canister/src/caller/lib.rs | 5 +---- src/ic-cdk/CHANGELOG.md | 8 +++++++- src/ic-cdk/Cargo.toml | 2 +- src/ic-cdk/src/api/management_canister/ecdsa/mod.rs | 12 ++++++------ 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index dbf72e119..7ca43760e 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -155,10 +155,7 @@ mod ecdsa { derivation_path, key_id, }; - let SignWithEcdsaResponse { signature } = sign_with_ecdsa(arg, 10_000_000_000u128 / 13) - .await - .unwrap() - .0; + let SignWithEcdsaResponse { signature } = sign_with_ecdsa(arg).await.unwrap().0; assert_eq!(signature.len(), 64); } } diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index d0439a938..a67e668ad 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,7 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -## [0.9.1] - 2023-06-21 +## [0.9.2] - 2023-06-22 + +### Changed + +- Hardcodes the fee for `sign_with_ecdsa`. (#407) + +## [0.9.1] - 2023-06-21 (yanked) ### Changed diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index ec86fc863..1eb68eedd 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.9.1" +version = "0.9.2" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." diff --git a/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs b/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs index a679ed3bf..edd19ae94 100644 --- a/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs +++ b/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs @@ -6,6 +6,8 @@ use candid::Principal; mod types; pub use types::*; +const SIGN_WITH_ECDSA_FEE: u128 = 26_153_846_153; + /// Return a SEC1 encoded ECDSA public key for the given canister using the given derivation path. /// /// See [IC method `ecdsa_public_key`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-ecdsa_public_key). @@ -19,17 +21,15 @@ pub async fn ecdsa_public_key( /// /// See [IC method `sign_with_ecdsa`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-sign_with_ecdsa). /// -/// This call requires cycles payment. The required cycles varies according to the subnet size (number of nodes). +/// This call requires cycles payment. +/// This method handles the cycles cost under the hood. /// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. -pub async fn sign_with_ecdsa( - arg: SignWithEcdsaArgument, - cycles: u128, -) -> CallResult<(SignWithEcdsaResponse,)> { +pub async fn sign_with_ecdsa(arg: SignWithEcdsaArgument) -> CallResult<(SignWithEcdsaResponse,)> { call_with_payment128( Principal::management_canister(), "sign_with_ecdsa", (arg,), - cycles, + SIGN_WITH_ECDSA_FEE, ) .await } From c96af21d19717a28e3ced4e15d76972dcd065e54 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Thu, 22 Jun 2023 16:28:13 -0700 Subject: [PATCH 159/234] Check panic after await freeing resources (#408) --- e2e-tests/canisters/async.rs | 15 +++++++-------- scripts/download_state_machine_binary.sh | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/e2e-tests/canisters/async.rs b/e2e-tests/canisters/async.rs index d1562dbc9..d8cd29424 100644 --- a/e2e-tests/canisters/async.rs +++ b/e2e-tests/canisters/async.rs @@ -23,14 +23,13 @@ fn invocation_count() -> u64 { #[update] #[allow(clippy::await_holding_lock)] async fn panic_after_async() { - let value = { - let mut lock = RESOURCE - .write() - .unwrap_or_else(|_| ic_cdk::api::trap("failed to obtain a write lock")); - *lock += 1; - *lock - // Drop the lock before the await point. - }; + let mut lock = RESOURCE + .write() + .unwrap_or_else(|_| ic_cdk::api::trap("failed to obtain a write lock")); + *lock += 1; + let value = *lock; + // Do not drop the lock before the await point. + let _: (u64,) = ic_cdk::call(ic_cdk::api::id(), "inc", (value,)) .await .expect("failed to call self"); diff --git a/scripts/download_state_machine_binary.sh b/scripts/download_state_machine_binary.sh index a9098adfb..b44136a01 100755 --- a/scripts/download_state_machine_binary.sh +++ b/scripts/download_state_machine_binary.sh @@ -8,7 +8,7 @@ cd "$SCRIPTS_DIR/.." uname_sys=$(uname -s | tr '[:upper:]' '[:lower:]') echo "uname_sys: $uname_sys" -commit_sha="4bffd861d15a28682761c97bd0e6608bf324c5c2" +commit_sha="b314222935b7d06c70036b0b54aa80a33252d79c" curl -sLO "https://download.dfinity.systems/ic/$commit_sha/binaries/x86_64-$uname_sys/ic-test-state-machine.gz" gzip -d ic-test-state-machine.gz From d06afe82b1d4db75fc2017c55970cde633517f49 Mon Sep 17 00:00:00 2001 From: witter-deland <87846830+witter-deland@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:21:41 +0800 Subject: [PATCH 160/234] feat: Add some conversion methods to AccountIdentifier in ic-ledger-types (#352) * [enhancement] AccountIdentifier * fix: compile error * update change log * [add] unit tests --------- Co-authored-by: Linwei Shang --- library/ic-ledger-types/CHANGELOG.md | 2 + library/ic-ledger-types/src/lib.rs | 261 +++++++++++++++++++++++++-- 2 files changed, 248 insertions(+), 15 deletions(-) diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index 1d4727a58..6fe7b548c 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [unreleased] +### Add from_hex/from_slice/to_hex methods to AccountIdentifier in ic-ledger-types + ## [0.6.0] - 2023-06-20 ### Changed diff --git a/library/ic-ledger-types/src/lib.rs b/library/ic-ledger-types/src/lib.rs index dda19ef0d..4452154f7 100644 --- a/library/ic-ledger-types/src/lib.rs +++ b/library/ic-ledger-types/src/lib.rs @@ -9,16 +9,18 @@ clippy::missing_safety_doc )] +use std::convert::TryFrom; +use std::fmt::{self, Display, Formatter}; +use std::ops::{Add, AddAssign, Sub, SubAssign}; + use candid::{types::reference::Func, CandidType, Principal}; -use ic_cdk::api::call::CallResult; use serde::{Deserialize, Serialize}; use serde_bytes::ByteBuf; use sha2::Digest; -use std::convert::TryFrom; -use std::fmt; -use std::ops::{Add, AddAssign, Sub, SubAssign}; -/// The subaccont that is used by default. +use ic_cdk::api::call::CallResult; + +/// The subaccount that is used by default. pub const DEFAULT_SUBACCOUNT: Subaccount = Subaccount([0; 32]); /// The default fee for ledger transactions. @@ -116,8 +118,8 @@ impl SubAssign for Tokens { } } -impl fmt::Display for Tokens { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl Display for Tokens { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, "{}.{:08}", @@ -170,6 +172,78 @@ impl AccountIdentifier { result[4..32].copy_from_slice(hash.as_ref()); Self(result) } + + /// Convert hex string into AccountIdentifier. + pub fn from_hex(hex_str: &str) -> Result { + let hex: Vec = hex::decode(hex_str).map_err(|e| e.to_string())?; + Self::from_slice(&hex[..]).map_err(|err| match err { + // Since the input was provided in hex, return an error that is hex-friendly. + AccountIdParseError::InvalidLength(_) => format!( + "{} has a length of {} but we expected a length of 64 or 56", + hex_str, + hex_str.len() + ), + AccountIdParseError::InvalidChecksum(err) => err.to_string(), + }) + } + + /// Converts a blob into an `AccountIdentifier`. + /// + /// The blob can be either: + /// + /// 1. The 32-byte canonical format (4 byte checksum + 28 byte hash). + /// 2. The 28-byte hash. + /// + /// If the 32-byte canonical format is provided, the checksum is verified. + pub fn from_slice(v: &[u8]) -> Result { + // Try parsing it as a 32-byte blob. + match v.try_into() { + Ok(h) => { + // It's a 32-byte blob. Validate the checksum. + check_sum(h).map_err(AccountIdParseError::InvalidChecksum) + } + Err(_) => { + // Try parsing it as a 28-byte hash. + match <&[u8] as TryInto<[u8; 28]>>::try_into(v) { + Ok(hash) => AccountIdentifier::try_from(hash) + .map_err(|_| AccountIdParseError::InvalidLength(v.to_vec())), + Err(_) => Err(AccountIdParseError::InvalidLength(v.to_vec())), + } + } + } + } + + /// Convert AccountIdentifier into hex string. + pub fn to_hex(&self) -> String { + hex::encode(self.0) + } + + /// Returns the checksum of the account identifier. + pub fn generate_checksum(&self) -> [u8; 4] { + let mut hasher = crc32fast::Hasher::new(); + hasher.update(&self.0[4..]); + hasher.finalize().to_be_bytes() + } +} + +fn check_sum(hex: [u8; 32]) -> Result { + // Get the checksum provided + let found_checksum = &hex[0..4]; + + let mut hasher = crc32fast::Hasher::new(); + hasher.update(&hex[4..]); + let expected_checksum = hasher.finalize().to_be_bytes(); + + // Check the generated checksum matches + if expected_checksum == found_checksum { + Ok(AccountIdentifier(hex)) + } else { + Err(ChecksumError { + input: hex, + expected_checksum, + found_checksum: found_checksum.try_into().unwrap(), + }) + } } impl TryFrom<[u8; 32]> for AccountIdentifier { @@ -188,18 +262,76 @@ impl TryFrom<[u8; 32]> for AccountIdentifier { } } +impl TryFrom<[u8; 28]> for AccountIdentifier { + type Error = String; + + fn try_from(bytes: [u8; 28]) -> Result { + let mut hasher = crc32fast::Hasher::new(); + hasher.update(bytes.as_slice()); + let crc32_bytes = hasher.finalize().to_be_bytes(); + + let mut aid_bytes = [0u8; 32]; + aid_bytes[..4].copy_from_slice(&crc32_bytes[..4]); + aid_bytes[4..].copy_from_slice(&bytes[..]); + + Ok(Self(aid_bytes)) + } +} + impl AsRef<[u8]> for AccountIdentifier { fn as_ref(&self) -> &[u8] { &self.0 } } -impl fmt::Display for AccountIdentifier { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl Display for AccountIdentifier { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{}", hex::encode(self.as_ref())) } } +/// An error for reporting invalid checksums. +#[derive(Debug, PartialEq, Eq)] +pub struct ChecksumError { + input: [u8; 32], + expected_checksum: [u8; 4], + found_checksum: [u8; 4], +} + +impl Display for ChecksumError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "Checksum failed for {}, expected check bytes {} but found {}", + hex::encode(&self.input[..]), + hex::encode(self.expected_checksum), + hex::encode(self.found_checksum), + ) + } +} + +/// An error for reporting invalid Account Identifiers. +#[derive(Debug, PartialEq, Eq)] +pub enum AccountIdParseError { + /// The checksum failed to verify. + InvalidChecksum(ChecksumError), + /// The length of the input was invalid. + InvalidLength(Vec), +} + +impl Display for AccountIdParseError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::InvalidChecksum(err) => write!(f, "{}", err), + Self::InvalidLength(input) => write!( + f, + "Received an invalid AccountIdentifier with length {} bytes instead of the expected 28 or 32.", + input.len() + ), + } + } +} + /// Arguments for the `account_balance` call. #[derive(CandidType, Serialize, Deserialize, Clone, Debug)] pub struct AccountBalanceArgs { @@ -276,8 +408,8 @@ pub enum TransferError { }, } -impl fmt::Display for TransferError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl Display for TransferError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::BadFee { expected_fee } => { write!(f, "transaction fee should be {}", expected_fee) @@ -478,8 +610,8 @@ pub enum GetBlocksError { }, } -impl fmt::Display for GetBlocksError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl Display for GetBlocksError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::BadFirstBlockIndex { requested_index, @@ -687,9 +819,10 @@ pub async fn query_archived_blocks( #[cfg(test)] mod tests { - use super::*; use std::string::ToString; + use super::*; + #[test] fn test_account_id() { assert_eq!( @@ -699,7 +832,7 @@ mod tests { "iooej-vlrze-c5tme-tn7qt-vqe7z-7bsj5-ebxlc-hlzgs-lueo3-3yast-pae" ) .unwrap(), - &DEFAULT_SUBACCOUNT + &DEFAULT_SUBACCOUNT, ) .to_string() ); @@ -751,4 +884,102 @@ mod tests { "d8646d1cbe44002026fa3e0d86d51a560b1c31d669bc8b7f66421c1b2feaa59f" ) } + + #[test] + fn check_round_trip() { + let bytes: [u8; 32] = [ + 237, 196, 46, 168, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, + ]; + let ai = AccountIdentifier::from_slice(bytes.as_ref()) + .expect("Failed to create account identifier"); + let res = ai.to_hex(); + assert_eq!( + AccountIdentifier::from_hex(&res), + Ok(ai), + "The account identifier doesn't change after going back and forth between a string" + ) + } + + #[test] + fn test_account_id_from_slice() { + let length_27 = b"123456789_123456789_1234567".to_vec(); + assert_eq!( + AccountIdentifier::from_slice(&length_27), + Err(AccountIdParseError::InvalidLength(length_27)) + ); + + let length_28 = b"123456789_123456789_12345678".to_vec(); + assert_eq!( + AccountIdentifier::from_slice(&length_28), + Ok(AccountIdentifier::try_from( + <&[u8] as TryInto<[u8; 28]>>::try_into(&length_28).unwrap() + ) + .unwrap()) + ); + + let length_29 = b"123456789_123456789_123456789".to_vec(); + assert_eq!( + AccountIdentifier::from_slice(&length_29), + Err(AccountIdParseError::InvalidLength(length_29)) + ); + + let length_32 = [0; 32].to_vec(); + assert_eq!( + AccountIdentifier::from_slice(&length_32), + Err(AccountIdParseError::InvalidChecksum(ChecksumError { + input: length_32.try_into().unwrap(), + expected_checksum: [128, 112, 119, 233], + found_checksum: [0, 0, 0, 0], + })) + ); + + // A 32-byte address with a valid checksum + let length_32 = [ + 128, 112, 119, 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, + ] + .to_vec(); + assert_eq!( + AccountIdentifier::from_slice(&length_32), + Ok(AccountIdentifier::try_from( + <&[u8] as TryInto<[u8; 28]>>::try_into(&[0u8; 28]).unwrap() + ) + .unwrap()) + ); + } + + #[test] + fn test_account_id_from_hex() { + let length_56 = "00000000000000000000000000000000000000000000000000000000"; + let aid_bytes = [ + 128, 112, 119, 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, + ]; + assert_eq!( + AccountIdentifier::from_hex(length_56), + Ok(AccountIdentifier(aid_bytes)) + ); + + let length_57 = "000000000000000000000000000000000000000000000000000000000"; + assert!(AccountIdentifier::from_hex(length_57).is_err()); + + let length_58 = "0000000000000000000000000000000000000000000000000000000000"; + assert_eq!( + AccountIdentifier::from_hex(length_58), + Err("0000000000000000000000000000000000000000000000000000000000 has a length of 58 but we expected a length of 64 or 56".to_string()) + ); + + let length_64 = "0000000000000000000000000000000000000000000000000000000000000000"; + assert!(AccountIdentifier::from_hex(length_64) + .unwrap_err() + .contains("Checksum failed")); + + // Try again with correct checksum + let length_64 = "807077e900000000000000000000000000000000000000000000000000000000"; + assert_eq!( + AccountIdentifier::from_hex(length_64), + Ok(AccountIdentifier(aid_bytes)) + ); + } } From 838ad9e7428a84b75aa4a4dc6ffeea5b1fbd447e Mon Sep 17 00:00:00 2001 From: AlexandraZapuc <61285418+AlexandraZapuc@users.noreply.github.com> Date: Wed, 5 Jul 2023 17:28:36 +0200 Subject: [PATCH 161/234] chore: Update example http_request_required_cycles (#409) * Update example http_request_required_cycles * fmt * comment --------- Co-authored-by: Linwei Shang --- examples/management_canister/src/caller/lib.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index 7ca43760e..ba6a9cada 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -88,9 +88,12 @@ mod http_request { }; let arg_raw = ic_cdk::export::candid::utils::encode_args((arg,)) .expect("Failed to encode arguments."); - 400_000_000u128 / 13 - + 100_000u128 / 13 - * (arg_raw.len() as u128 + "http_request".len() as u128 + max_response_bytes) + // The fee is for a 13-node subnet to demonstrate a typical usage. + (3_000_000u128 + + 60_000u128 * 13 + + (arg_raw.len() as u128 + "http_request".len() as u128) * 400 + + max_response_bytes * 800) + * 13 } #[update] From 83f45987f7bacfc2299a76caceea4d23edd147c0 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 13 Jul 2023 12:55:18 -0400 Subject: [PATCH 162/234] feat: upgrade candid to v0.9 (#411) * feat(breaking): bump CDK to use candid 0.9-beta (#367) * bump CDK to use candid 0.9-beta * make ic-ledger-types not breaking * chore: release continue (#370) * fix * bump ver * Add readme to ic-cdk-timers --------- Co-authored-by: Adam Spofford * version and changelog * fix chess * disable examples using import --------- Co-authored-by: Linwei Shang Co-authored-by: Adam Spofford * test * add wasmtime in CI * revert * use patched ic-test-state-machine-client * feat: ic-cdk-bindgen replace import macro (#390) * import did file * fix * test * fix counter example * rename to ic-cdk-bindgen * fix profile example * no re-export * enable all example tests in CI * remove import and fix tests * fix clippy * fix ic-certified-map doc test * fmt --------- Co-authored-by: Linwei Shang * feat: add export_candid macro (#386) * export candid * fix build.sh * actor macro * add wasmtime in CI * fix * fix * fix * remove actor macro * fix * ic-cdk/wasi enables export_candid * git forget declarations/ * fmt * Warning features in Cargo.toml * bump ic0 version --------- Co-authored-by: Linwei Shang * prepare for release * TODO comment * changelog * doc export_candid * format changelog * bump library and changelog * explain why no doc for TransformFunc * find solution for doc TransformFunc * remove TODO * doc hidden wasi mod --------- Co-authored-by: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Co-authored-by: Adam Spofford Co-authored-by: Yan Chen --- .github/workflows/examples.yml | 7 + .gitignore | 3 + Cargo.toml | 4 + e2e-tests/Cargo.toml | 6 +- e2e-tests/canisters/async.rs | 3 +- e2e-tests/canisters/canister_info.rs | 4 +- e2e-tests/tests/e2e.rs | 50 ++-- .../src/asset_storage_rs/Cargo.toml | 2 +- .../asset_storage/src/asset_storage_rs/lib.rs | 8 +- examples/build.sh | 15 +- examples/chess/src/chess_rs/Cargo.toml | 3 +- examples/chess/src/chess_rs/lib.rs | 5 +- examples/counter/Cargo.toml | 11 +- examples/counter/src/counter_rs/Cargo.toml | 5 +- examples/counter/src/counter_rs/lib.rs | 9 +- examples/counter/src/inter2_rs/Cargo.toml | 8 +- examples/counter/src/inter2_rs/build.rs | 11 + examples/counter/src/inter2_rs/lib.rs | 12 +- examples/counter/src/inter_rs/Cargo.toml | 8 +- examples/counter/src/inter_rs/build.rs | 11 + examples/counter/src/inter_rs/lib.rs | 12 +- .../management_canister/src/caller/Cargo.toml | 1 + .../management_canister/src/caller/lib.rs | 5 +- examples/print/src/print_rs/Cargo.toml | 2 - examples/print/src/print_rs/lib.rs | 2 + examples/profile/Cargo.toml | 11 +- .../profile/src/profile_inter_rs/Cargo.toml | 9 +- .../profile/src/profile_inter_rs/build.rs | 11 + examples/profile/src/profile_inter_rs/lib.rs | 20 +- examples/profile/src/profile_rs/Cargo.toml | 7 +- examples/profile/src/profile_rs/lib.rs | 12 +- library/ic-certified-map/CHANGELOG.md | 3 + library/ic-certified-map/Cargo.toml | 6 +- library/ic-certified-map/src/lib.rs | 2 +- library/ic-ledger-types/CHANGELOG.md | 6 +- library/ic-ledger-types/Cargo.toml | 6 +- library/ic-ledger-types/src/lib.rs | 6 +- src/ic-cdk-bindgen/Cargo.toml | 16 ++ src/ic-cdk-bindgen/LICENSE | 1 + src/ic-cdk-bindgen/README.md | 33 +++ src/ic-cdk-bindgen/src/lib.rs | 82 +++++++ src/ic-cdk-macros/CHANGELOG.md | 8 + src/ic-cdk-macros/Cargo.toml | 19 +- src/ic-cdk-macros/src/export.rs | 25 +- src/ic-cdk-macros/src/import.rs | 227 ------------------ src/ic-cdk-macros/src/lib.rs | 63 +++-- src/ic-cdk-timers/Cargo.toml | 4 +- src/ic-cdk/CHANGELOG.md | 49 ++++ src/ic-cdk/Cargo.toml | 14 +- .../management_canister/http_request/types.rs | 35 ++- src/ic-cdk/src/api/mod.rs | 4 + src/ic-cdk/src/api/wasi.rs | 33 +++ src/ic-cdk/src/lib.rs | 7 - src/ic0/Cargo.toml | 8 +- src/ic0/src/ic0.rs | 6 +- src/ic0/util/ic0build.rs | 6 +- 56 files changed, 519 insertions(+), 427 deletions(-) create mode 100644 examples/counter/src/inter2_rs/build.rs create mode 100644 examples/counter/src/inter_rs/build.rs create mode 100644 examples/profile/src/profile_inter_rs/build.rs create mode 100644 src/ic-cdk-bindgen/Cargo.toml create mode 120000 src/ic-cdk-bindgen/LICENSE create mode 100644 src/ic-cdk-bindgen/README.md create mode 100644 src/ic-cdk-bindgen/src/lib.rs delete mode 100644 src/ic-cdk-macros/src/import.rs create mode 100644 src/ic-cdk/src/api/wasi.rs diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index af6108f4d..47270e3a0 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -13,6 +13,7 @@ concurrency: env: rust-version: 1.66.1 dfx-version: 0.14.1 + wasmtime-version: 10.0.1 jobs: test: @@ -55,6 +56,12 @@ jobs: cargo install ic-wasm fi + - name: Install wasmtime + run: | + wget https://github.com/bytecodealliance/wasmtime/releases/download/v${{env.wasmtime-version}}/wasmtime-v${{env.wasmtime-version}}-x86_64-linux.tar.xz + tar xf wasmtime-v${{env.wasmtime-version}}-x86_64-linux.tar.xz + mv wasmtime-v${{env.wasmtime-version}}-x86_64-linux/wasmtime /usr/local/bin/ + - name: Install DFX run: | export DFX_VERSION=${{env.dfx-version }} diff --git a/.gitignore b/.gitignore index bc533ffc9..6e4090482 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ Cargo.lock .DS_Store ic-test-state-machine + +# Generated bindings +**/declarations/ diff --git a/Cargo.toml b/Cargo.toml index aa3892b7a..0810284f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "src/ic0", "src/ic-cdk", + "src/ic-cdk-bindgen", "src/ic-cdk-macros", "src/ic-cdk-timers", "library/ic-certified-map", @@ -15,3 +16,6 @@ debug = false panic = "abort" lto = true opt-level = 'z' + +[workspace.dependencies] +candid = "0.9" diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 79f8f3587..53c6c6418 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -8,10 +8,10 @@ license = "Apache-2.0" repository = "https://github.com/dfinity/cdk-rs" [dependencies] +candid = "0.9" cargo_metadata = "0.14.2" escargot = { version = "0.5.7", features = ["print"] } ic-cdk = { path = "../src/ic-cdk" } -ic-cdk-macros = { path = "../src/ic-cdk-macros" } ic-cdk-timers = { path = "../src/ic-cdk-timers" } lazy_static = "1.4.0" serde_bytes = "0.11" @@ -42,6 +42,6 @@ name = "canister_info" path = "canisters/canister_info.rs" [dev-dependencies] -candid = "0.8" hex = "0.4.3" -ic-test-state-machine-client = "1" +# TODO: Use the public crate when this [PR](https://github.com/dfinity/test-state-machine-client/pull/19) merge. +ic-test-state-machine-client = { git = "https://github.com/lwshang/test-state-machine-client", branch = "lwshang/candid_0.9" } diff --git a/e2e-tests/canisters/async.rs b/e2e-tests/canisters/async.rs index d8cd29424..73873dd71 100644 --- a/e2e-tests/canisters/async.rs +++ b/e2e-tests/canisters/async.rs @@ -1,4 +1,5 @@ -use ic_cdk::{export::Principal, query, update}; +use candid::Principal; +use ic_cdk::{query, update}; use lazy_static::lazy_static; use std::sync::RwLock; diff --git a/e2e-tests/canisters/canister_info.rs b/e2e-tests/canisters/canister_info.rs index d7208a206..90c19a16a 100644 --- a/e2e-tests/canisters/canister_info.rs +++ b/e2e-tests/canisters/canister_info.rs @@ -1,10 +1,10 @@ +use candid::Principal; use ic_cdk::api::management_canister::main::{ canister_info, create_canister, install_code, uninstall_code, update_settings, CanisterIdRecord, CanisterInfoRequest, CanisterInfoResponse, CanisterInstallMode::{Install, Reinstall, Upgrade}, CanisterSettings, CreateCanisterArgument, InstallCodeArgument, UpdateSettingsArgument, }; -use ic_cdk::export::Principal; #[ic_cdk::update] async fn info(canister_id: Principal) -> CanisterInfoResponse { @@ -15,7 +15,7 @@ async fn info(canister_id: Principal) -> CanisterInfoResponse { canister_info(request).await.unwrap().0 } -#[ic_cdk_macros::update] +#[ic_cdk::update] async fn canister_lifecycle() -> Principal { let canister_id = create_canister( CreateCanisterArgument { settings: None }, diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 241637070..39f637a95 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -36,13 +36,13 @@ ERROR: Could not find state machine binary to run e2e tests. fn test_storage_roundtrip() { let env = env(); let wasm = cargo_build_canister("simple-kv-store"); - let canister_id = env.create_canister(); - env.install_canister(canister_id, wasm.clone(), vec![]); + let canister_id = env.create_canister(None); + env.install_canister(canister_id, wasm.clone(), vec![], None); let () = call_candid(&env, canister_id, "insert", (&"candid", &b"did")) .expect("failed to insert 'candid'"); - env.upgrade_canister(canister_id, wasm, vec![]) + env.upgrade_canister(canister_id, wasm, vec![], None) .expect("failed to upgrade the simple-kv-store canister"); let (result,): (Option,) = @@ -54,8 +54,8 @@ fn test_storage_roundtrip() { fn test_panic_after_async_frees_resources() { let env = env(); let wasm = cargo_build_canister("async"); - let canister_id = env.create_canister(); - env.install_canister(canister_id, wasm, vec![]); + let canister_id = env.create_canister(None); + env.install_canister(canister_id, wasm, vec![], None); for i in 1..3 { match call_candid(&env, canister_id, "panic_after_async", ()) { @@ -101,8 +101,8 @@ fn test_panic_after_async_frees_resources() { fn test_raw_api() { let env = env(); let wasm = cargo_build_canister("reverse"); - let canister_id = env.create_canister(); - env.install_canister(canister_id, wasm, vec![]); + let canister_id = env.create_canister(None); + env.install_canister(canister_id, wasm, vec![], None); let result = env .query_call( @@ -129,10 +129,10 @@ fn test_raw_api() { fn test_notify_calls() { let env = env(); let wasm = cargo_build_canister("async"); - let sender_id = env.create_canister(); - env.install_canister(sender_id, wasm.clone(), vec![]); - let receiver_id = env.create_canister(); - env.install_canister(receiver_id, wasm, vec![]); + let sender_id = env.create_canister(None); + env.install_canister(sender_id, wasm.clone(), vec![], None); + let receiver_id = env.create_canister(None); + env.install_canister(receiver_id, wasm, vec![], None); let (n,): (u64,) = query_candid(&env, receiver_id, "notifications_received", ()) .expect("failed to query 'notifications_received'"); @@ -152,10 +152,10 @@ fn test_notify_calls() { fn test_composite_query() { let env = env(); let wasm = cargo_build_canister("async"); - let sender_id = env.create_canister(); - env.install_canister(sender_id, wasm.clone(), vec![]); - let receiver_id = env.create_canister(); - env.install_canister(receiver_id, wasm, vec![]); + let sender_id = env.create_canister(None); + env.install_canister(sender_id, wasm.clone(), vec![], None); + let receiver_id = env.create_canister(None); + env.install_canister(receiver_id, wasm, vec![], None); let (greeting,): (String,) = query_candid(&env, sender_id, "greet_self", (receiver_id,)) .expect("failed to query 'greet_self'"); @@ -166,8 +166,8 @@ fn test_composite_query() { fn test_api_call() { let env = env(); let wasm = cargo_build_canister("api-call"); - let canister_id = env.create_canister(); - env.install_canister(canister_id, wasm, vec![]); + let canister_id = env.create_canister(None); + env.install_canister(canister_id, wasm, vec![], None); let (result,): (u64,) = query_candid(&env, canister_id, "instruction_counter", ()) .expect("failed to query instruction_counter"); assert!(result > 0); @@ -187,8 +187,8 @@ fn test_api_call() { fn test_timers() { let env = env(); let wasm = cargo_build_canister("timers"); - let canister_id = env.create_canister(); - env.install_canister(canister_id, wasm, vec![]); + let canister_id = env.create_canister(None); + env.install_canister(canister_id, wasm, vec![], None); call_candid::<(), ()>(&env, canister_id, "schedule", ()).expect("Failed to call schedule"); advance_seconds(&env, 5); @@ -218,8 +218,8 @@ fn test_timers() { fn test_timers_can_cancel_themselves() { let env = env(); let wasm = cargo_build_canister("timers"); - let canister_id = env.create_canister(); - env.install_canister(canister_id, wasm, vec![]); + let canister_id = env.create_canister(None); + env.install_canister(canister_id, wasm, vec![], None); call_candid::<_, ()>(&env, canister_id, "set_self_cancelling_timer", ()) .expect("Failed to call set_self_cancelling_timer"); @@ -242,8 +242,8 @@ fn test_scheduling_many_timers() { let timers_to_schedule = 1_000; let env = env(); let wasm = cargo_build_canister("timers"); - let canister_id = env.create_canister(); - env.install_canister(canister_id, wasm, vec![]); + let canister_id = env.create_canister(None); + env.install_canister(canister_id, wasm, vec![], None); let () = call_candid( &env, @@ -273,9 +273,9 @@ fn advance_seconds(env: &StateMachine, seconds: u32) { fn test_canister_info() { let env = env(); let wasm = cargo_build_canister("canister_info"); - let canister_id = env.create_canister(); + let canister_id = env.create_canister(None); env.add_cycles(canister_id, 1_000_000_000_000); - env.install_canister(canister_id, wasm, vec![]); + env.install_canister(canister_id, wasm, vec![], None); let new_canister: (Principal,) = call_candid(&env, canister_id, "canister_lifecycle", ()) .expect("Error calling canister_lifecycle"); diff --git a/examples/asset_storage/src/asset_storage_rs/Cargo.toml b/examples/asset_storage/src/asset_storage_rs/Cargo.toml index d365ba543..1b715d723 100644 --- a/examples/asset_storage/src/asset_storage_rs/Cargo.toml +++ b/examples/asset_storage/src/asset_storage_rs/Cargo.toml @@ -10,5 +10,5 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] +candid = "0.9" ic-cdk = { path = "../../../../src/ic-cdk" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } diff --git a/examples/asset_storage/src/asset_storage_rs/lib.rs b/examples/asset_storage/src/asset_storage_rs/lib.rs index a37feec57..1a71ada4b 100644 --- a/examples/asset_storage/src/asset_storage_rs/lib.rs +++ b/examples/asset_storage/src/asset_storage_rs/lib.rs @@ -1,7 +1,5 @@ -use ic_cdk::{ - api::call::ManualReply, export::Principal, init, post_upgrade, pre_upgrade, query, storage, - update, -}; +use candid::Principal; +use ic_cdk::{api::call::ManualReply, init, post_upgrade, pre_upgrade, query, storage, update}; use std::cell::RefCell; use std::collections::{BTreeMap, BTreeSet}; @@ -54,3 +52,5 @@ fn post_upgrade() { let (old_users,): (BTreeSet,) = storage::stable_restore().unwrap(); USERS.with(|users| *users.borrow_mut() = old_users); } + +ic_cdk::export_candid!(); diff --git a/examples/build.sh b/examples/build.sh index e49c6fb6d..31eeada52 100755 --- a/examples/build.sh +++ b/examples/build.sh @@ -5,13 +5,26 @@ name="$1" package="$2" root="$(dirname "$0")/.." example_root="$(dirname "$0")/$name" +did_file="/tmp/a.did" + +# This script generates the did file, build the project (passed as $1) and then run the ic-wasm to shrink and attach metadata. +cargo build --manifest-path="$example_root/Cargo.toml" \ + --target wasm32-unknown-unknown \ + --release \ + --package "$package" --features "ic-cdk/wasi" + +wasmtime "$example_root/target/wasm32-unknown-unknown/release/$package.wasm" > $did_file -# This script builds an example project (passed as $1) and then run the ic-cdk-optimizer on it. cargo build --manifest-path="$example_root/Cargo.toml" \ --target wasm32-unknown-unknown \ --release \ --package "$package" +ic-wasm "$example_root/target/wasm32-unknown-unknown/release/$package.wasm" \ + -o "$example_root/target/wasm32-unknown-unknown/release/$package.wasm" \ + metadata candid:service -v public -f $did_file + ic-wasm "$example_root/target/wasm32-unknown-unknown/release/$package.wasm" \ -o "$example_root/target/wasm32-unknown-unknown/release/$package-opt.wasm" \ shrink + diff --git a/examples/chess/src/chess_rs/Cargo.toml b/examples/chess/src/chess_rs/Cargo.toml index c82931418..d9eba418a 100644 --- a/examples/chess/src/chess_rs/Cargo.toml +++ b/examples/chess/src/chess_rs/Cargo.toml @@ -10,9 +10,8 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.8.0" +candid = "0.9.0" ic-cdk = { path = "../../../../src/ic-cdk" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } serde = "1.0.111" tanton = "1.0.0" getrandom = { version = "0.2", features = ["custom"] } # tanton requires this to compile on wasm target diff --git a/examples/chess/src/chess_rs/lib.rs b/examples/chess/src/chess_rs/lib.rs index 3b481ecb8..bd2fb37e3 100644 --- a/examples/chess/src/chess_rs/lib.rs +++ b/examples/chess/src/chess_rs/lib.rs @@ -1,4 +1,5 @@ -use ic_cdk::{export::candid::CandidType, query, update}; +use candid::CandidType; +use ic_cdk::{query, update}; use serde::Serialize; use std::cell::RefCell; use std::collections::BTreeMap; @@ -74,3 +75,5 @@ fn ai_move(name: String) { fn get_fen(name: String) -> Option { STORE.with(|game_store| game_store.borrow().get(&name).map(|game| game.board.fen())) } + +ic_cdk::export_candid!(); diff --git a/examples/counter/Cargo.toml b/examples/counter/Cargo.toml index 12ee45194..eb7dd6932 100644 --- a/examples/counter/Cargo.toml +++ b/examples/counter/Cargo.toml @@ -1,6 +1,7 @@ [workspace] -members = [ - "src/counter_rs", - "src/inter_rs", - "src/inter2_rs", -] +members = ["src/counter_rs", "src/inter_rs", "src/inter2_rs"] + +[workspace.dependencies] +candid = "0.9" +ic-cdk = { path = "../../src/ic-cdk" } +ic-cdk-bindgen = { path = "../../src/ic-cdk-bindgen" } diff --git a/examples/counter/src/counter_rs/Cargo.toml b/examples/counter/src/counter_rs/Cargo.toml index 3ab795b28..bb514ed8a 100644 --- a/examples/counter/src/counter_rs/Cargo.toml +++ b/examples/counter/src/counter_rs/Cargo.toml @@ -10,7 +10,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.8.0" -ic-cdk = { path = "../../../../src/ic-cdk" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } +candid = { workspace = true } +ic-cdk = { workspace = true } lazy_static = "1.4.0" diff --git a/examples/counter/src/counter_rs/lib.rs b/examples/counter/src/counter_rs/lib.rs index 57afc8aa4..2d0359cd8 100644 --- a/examples/counter/src/counter_rs/lib.rs +++ b/examples/counter/src/counter_rs/lib.rs @@ -1,8 +1,5 @@ -use ic_cdk::{ - api::call::ManualReply, - export::{candid, Principal}, - init, query, update, -}; +use candid::Principal; +use ic_cdk::{api::call::ManualReply, init, query, update}; use std::cell::{Cell, RefCell}; thread_local! { @@ -30,3 +27,5 @@ fn read() -> ManualReply { fn write(input: candid::Nat) { COUNTER.with(|counter| *counter.borrow_mut() = input); } + +ic_cdk::export_candid!(); diff --git a/examples/counter/src/inter2_rs/Cargo.toml b/examples/counter/src/inter2_rs/Cargo.toml index 3e2217f8a..b6f68b4e6 100644 --- a/examples/counter/src/inter2_rs/Cargo.toml +++ b/examples/counter/src/inter2_rs/Cargo.toml @@ -10,6 +10,8 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.8.0" -ic-cdk = { path = "../../../../src/ic-cdk" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } +candid = { workspace = true } +ic-cdk = { workspace = true } + +[build-dependencies] +ic-cdk-bindgen = { workspace = true } diff --git a/examples/counter/src/inter2_rs/build.rs b/examples/counter/src/inter2_rs/build.rs new file mode 100644 index 000000000..948b69034 --- /dev/null +++ b/examples/counter/src/inter2_rs/build.rs @@ -0,0 +1,11 @@ +use ic_cdk_bindgen::{Builder, Config}; +use std::path::PathBuf; + +fn main() { + let manifest_dir = + PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").expect("Cannot find manifest dir")); + let counter = Config::new("inter_mo"); + let mut builder = Builder::new(); + builder.add(counter); + builder.build(Some(manifest_dir.join("declarations"))); +} diff --git a/examples/counter/src/inter2_rs/lib.rs b/examples/counter/src/inter2_rs/lib.rs index 946acc6b1..2781e825a 100644 --- a/examples/counter/src/inter2_rs/lib.rs +++ b/examples/counter/src/inter2_rs/lib.rs @@ -1,19 +1,19 @@ -use ic_cdk::{export::candid, import, update}; +use ic_cdk::update; -#[import(canister = "inter_mo")] -struct CounterCanister; +mod declarations; +use declarations::inter_mo::inter_mo; #[update] async fn read() -> candid::Nat { - CounterCanister::read().await.0 + inter_mo.read().await.unwrap().0 } #[update] async fn inc() { - CounterCanister::inc().await + inter_mo.inc().await.unwrap() } #[update] async fn write(input: candid::Nat) { - CounterCanister::write(input).await + inter_mo.write(input).await.unwrap() } diff --git a/examples/counter/src/inter_rs/Cargo.toml b/examples/counter/src/inter_rs/Cargo.toml index a7b1ebc9e..6c90a1f5a 100644 --- a/examples/counter/src/inter_rs/Cargo.toml +++ b/examples/counter/src/inter_rs/Cargo.toml @@ -10,6 +10,8 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.8.0" -ic-cdk = { path = "../../../../src/ic-cdk" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } +candid = { workspace = true } +ic-cdk = { workspace = true } + +[build-dependencies] +ic-cdk-bindgen = { workspace = true } diff --git a/examples/counter/src/inter_rs/build.rs b/examples/counter/src/inter_rs/build.rs new file mode 100644 index 000000000..9b9493ff0 --- /dev/null +++ b/examples/counter/src/inter_rs/build.rs @@ -0,0 +1,11 @@ +use ic_cdk_bindgen::{Builder, Config}; +use std::path::PathBuf; + +fn main() { + let manifest_dir = + PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").expect("Cannot find manifest dir")); + let counter = Config::new("counter_mo"); + let mut builder = Builder::new(); + builder.add(counter); + builder.build(Some(manifest_dir.join("declarations"))); +} diff --git a/examples/counter/src/inter_rs/lib.rs b/examples/counter/src/inter_rs/lib.rs index b89dc49b6..b36d64159 100644 --- a/examples/counter/src/inter_rs/lib.rs +++ b/examples/counter/src/inter_rs/lib.rs @@ -1,19 +1,19 @@ -use ic_cdk::{export::candid, import, update}; +use ic_cdk::update; -#[import(canister = "counter_mo")] -struct CounterCanister; +mod declarations; +use declarations::counter_mo::counter_mo; #[update] async fn read() -> candid::Nat { - CounterCanister::read().await.0 + counter_mo.read().await.unwrap().0 } #[update] async fn inc() { - CounterCanister::inc().await + counter_mo.inc().await.unwrap() } #[update] async fn write(input: candid::Nat) { - CounterCanister::write(input).await + counter_mo.write(input).await.unwrap() } diff --git a/examples/management_canister/src/caller/Cargo.toml b/examples/management_canister/src/caller/Cargo.toml index 56fc03b6c..4e57ba562 100644 --- a/examples/management_canister/src/caller/Cargo.toml +++ b/examples/management_canister/src/caller/Cargo.toml @@ -10,5 +10,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] +candid = "0.9" ic-cdk = { path = "../../../../src/ic-cdk", features = ["transform-closure"] } sha2 = "0.10" diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index ba6a9cada..c4409c47b 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -86,8 +86,7 @@ mod http_request { Some(ref n) => *n as u128, None => 2 * 1024 * 1024u128, // default 2MiB }; - let arg_raw = ic_cdk::export::candid::utils::encode_args((arg,)) - .expect("Failed to encode arguments."); + let arg_raw = candid::utils::encode_args((arg,)).expect("Failed to encode arguments."); // The fee is for a 13-node subnet to demonstrate a typical usage. (3_000_000u128 + 60_000u128 * 13 @@ -211,3 +210,5 @@ mod bitcoin { }; } } + +ic_cdk::export_candid!(); diff --git a/examples/print/src/print_rs/Cargo.toml b/examples/print/src/print_rs/Cargo.toml index bd6d482f2..3dd3a6261 100644 --- a/examples/print/src/print_rs/Cargo.toml +++ b/examples/print/src/print_rs/Cargo.toml @@ -11,5 +11,3 @@ crate-type = ["cdylib"] [dependencies] ic-cdk = { path = "../../../../src/ic-cdk" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } - diff --git a/examples/print/src/print_rs/lib.rs b/examples/print/src/print_rs/lib.rs index c0fb4cfba..5114f52dc 100644 --- a/examples/print/src/print_rs/lib.rs +++ b/examples/print/src/print_rs/lib.rs @@ -2,3 +2,5 @@ fn print() { ic_cdk::print("Hello World"); } + +ic_cdk::export_candid!(::ic_cdk::export::candid); diff --git a/examples/profile/Cargo.toml b/examples/profile/Cargo.toml index 11917b831..6fa009617 100644 --- a/examples/profile/Cargo.toml +++ b/examples/profile/Cargo.toml @@ -1,5 +1,8 @@ [workspace] -members = [ - "src/profile_rs", - "src/profile_inter_rs", -] +members = ["src/profile_rs", "src/profile_inter_rs"] + +[workspace.dependencies] +candid = "0.9" +ic-cdk = { path = "../../src/ic-cdk" } +ic-cdk-bindgen = { path = "../../src/ic-cdk-bindgen" } +serde = "1" diff --git a/examples/profile/src/profile_inter_rs/Cargo.toml b/examples/profile/src/profile_inter_rs/Cargo.toml index 6780a4bcb..ed40ee0f5 100644 --- a/examples/profile/src/profile_inter_rs/Cargo.toml +++ b/examples/profile/src/profile_inter_rs/Cargo.toml @@ -10,6 +10,9 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.8.0" -ic-cdk = { path = "../../../../src/ic-cdk" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } +candid = { workspace = true } +ic-cdk = { workspace = true } +serde = { workspace = true } + +[build-dependencies] +ic-cdk-bindgen = { workspace = true } diff --git a/examples/profile/src/profile_inter_rs/build.rs b/examples/profile/src/profile_inter_rs/build.rs new file mode 100644 index 000000000..c76667add --- /dev/null +++ b/examples/profile/src/profile_inter_rs/build.rs @@ -0,0 +1,11 @@ +use ic_cdk_bindgen::{Builder, Config}; +use std::path::PathBuf; + +fn main() { + let manifest_dir = + PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").expect("Cannot find manifest dir")); + let counter = Config::new("profile_rs"); + let mut builder = Builder::new(); + builder.add(counter); + builder.build(Some(manifest_dir.join("declarations"))); +} diff --git a/examples/profile/src/profile_inter_rs/lib.rs b/examples/profile/src/profile_inter_rs/lib.rs index 65e6e58b5..348b9ee2a 100644 --- a/examples/profile/src/profile_inter_rs/lib.rs +++ b/examples/profile/src/profile_inter_rs/lib.rs @@ -1,24 +1,24 @@ -use ic_cdk::{import, update}; +use ic_cdk::update; -#[import(canister = "profile_rs")] -struct ProfileCanister; +mod declarations; +use declarations::profile_rs::{profile_rs, Profile}; #[update(name = "getSelf")] -async fn get_self() -> Box { - ProfileCanister::getSelf().await.0 +async fn get_self() -> Profile { + profile_rs.getSelf().await.unwrap().0 } #[update] -async fn get(name: String) -> Box { - ProfileCanister::get(name).await.0 +async fn get(name: String) -> Profile { + profile_rs.get(name).await.unwrap().0 } #[update] async fn update(profile: Profile) { - ProfileCanister::update(Box::new(profile)).await + profile_rs.update(profile).await.unwrap() } #[update] -async fn search(text: String) -> Option> { - ProfileCanister::search(text).await.0 +async fn search(text: String) -> Option { + profile_rs.search(text).await.unwrap().0 } diff --git a/examples/profile/src/profile_rs/Cargo.toml b/examples/profile/src/profile_rs/Cargo.toml index b88a89d89..701f1bfa7 100644 --- a/examples/profile/src/profile_rs/Cargo.toml +++ b/examples/profile/src/profile_rs/Cargo.toml @@ -10,7 +10,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.8.0" -ic-cdk = { path = "../../../../src/ic-cdk" } -ic-cdk-macros = { path = "../../../../src/ic-cdk-macros" } -serde = "1.0.111" +candid = { workspace = true } +ic-cdk = { workspace = true } +serde = { workspace = true } diff --git a/examples/profile/src/profile_rs/lib.rs b/examples/profile/src/profile_rs/lib.rs index 64a4e2369..b1cf44117 100644 --- a/examples/profile/src/profile_rs/lib.rs +++ b/examples/profile/src/profile_rs/lib.rs @@ -1,11 +1,5 @@ -use ic_cdk::{ - api::call::ManualReply, - export::{ - candid::{CandidType, Deserialize}, - Principal, - }, - query, update, -}; +use candid::{CandidType, Deserialize, Principal}; +use ic_cdk::{api::call::ManualReply, query, update}; use std::cell::RefCell; use std::collections::BTreeMap; @@ -86,3 +80,5 @@ fn search(text: String) -> ManualReply> { ManualReply::one(None::) }) } + +ic_cdk::export_candid!(); diff --git a/library/ic-certified-map/CHANGELOG.md b/library/ic-certified-map/CHANGELOG.md index 20e8b933f..3ce069f69 100644 --- a/library/ic-certified-map/CHANGELOG.md +++ b/library/ic-certified-map/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Changed +- Upgrade `ic-cdk` to v0.10 and `candid` to v0.9. + ## [0.3.4] - 2023-03-01 ### Added - Derive common traits for structs. diff --git a/library/ic-certified-map/Cargo.toml b/library/ic-certified-map/Cargo.toml index a4fec4f18..abd17ab4f 100644 --- a/library/ic-certified-map/Cargo.toml +++ b/library/ic-certified-map/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-certified-map" -version = "0.3.4" +version = "0.4.0" edition = "2021" authors = ["DFINITY Stiftung "] description = "Merkleized map data structure." @@ -22,6 +22,6 @@ sha2 = "0.10" [dev-dependencies] hex = "0.4" serde_cbor = "0.11" -ic-cdk = { path = "../../src/ic-cdk", version = "0.9" } -candid = "0.8" +ic-cdk = { path = "../../src/ic-cdk", version = "0.10" } +candid = "0.9" serde = "1" diff --git a/library/ic-certified-map/src/lib.rs b/library/ic-certified-map/src/lib.rs index c84f8254c..9aa87d1b3 100644 --- a/library/ic-certified-map/src/lib.rs +++ b/library/ic-certified-map/src/lib.rs @@ -20,7 +20,7 @@ //! # use std::cell::*; //! # use ic_cdk::*; //! # use ic_certified_map::*; -//! # use ic_cdk::export::candid::CandidType; +//! # use candid::CandidType; //! # use serde::Serialize; //! //! thread_local! { diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index 6fe7b548c..960d94c9d 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -5,8 +5,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [unreleased] -### Add from_hex/from_slice/to_hex methods to AccountIdentifier in ic-ledger-types +### Added +- from_hex/from_slice/to_hex methods to AccountIdentifier in ic-ledger-types + +### Changed +- Upgrade `ic-cdk` to v0.10 and `candid` to v0.9. ## [0.6.0] - 2023-06-20 ### Changed diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index df047e143..d0a7ae546 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.6.0" +version = "0.7.0" edition = "2021" authors = ["DFINITY Stiftung "] description = "Types for interacting with the ICP ledger canister." @@ -17,8 +17,8 @@ rust-version = "1.65.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ic-cdk = { path = "../../src/ic-cdk", version = "0.9" } -candid = "0.8.0" +ic-cdk = { path = "../../src/ic-cdk", version = "0.10.0" } +candid = "0.9.0" crc32fast = "1.2.0" hex = "0.4" serde = "1" diff --git a/library/ic-ledger-types/src/lib.rs b/library/ic-ledger-types/src/lib.rs index 4452154f7..722c10c85 100644 --- a/library/ic-ledger-types/src/lib.rs +++ b/library/ic-ledger-types/src/lib.rs @@ -653,11 +653,7 @@ impl From for Func { impl CandidType for QueryArchiveFn { fn _ty() -> candid::types::Type { - candid::types::Type::Func(candid::types::Function { - modes: vec![candid::parser::types::FuncMode::Query], - args: vec![GetBlocksArgs::_ty()], - rets: vec![GetBlocksResult::_ty()], - }) + candid::func!((GetBlocksArgs) -> (GetBlocksResult) query) } fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> diff --git a/src/ic-cdk-bindgen/Cargo.toml b/src/ic-cdk-bindgen/Cargo.toml new file mode 100644 index 000000000..9df297c20 --- /dev/null +++ b/src/ic-cdk-bindgen/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "ic-cdk-bindgen" +version = "0.1.0" +authors = ["DFINITY Stiftung "] +edition = "2021" +description = "Internet Computer Binding Generator." +license = "Apache-2.0" +readme = "README.md" +categories = ["api-bindings", "development-tools::ffi"] +keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] +include = ["src", "Cargo.toml", "LICENSE", "README.md"] +repository = "https://github.com/dfinity/cdk-rs" +rust-version = "1.66.1" + +[dependencies] +candid = { workspace = true, features = ["parser"] } diff --git a/src/ic-cdk-bindgen/LICENSE b/src/ic-cdk-bindgen/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/src/ic-cdk-bindgen/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/src/ic-cdk-bindgen/README.md b/src/ic-cdk-bindgen/README.md new file mode 100644 index 000000000..65141eaba --- /dev/null +++ b/src/ic-cdk-bindgen/README.md @@ -0,0 +1,33 @@ +# ic-cdk-bindgen + +Generate Rust bindings from Candid to make inter-canister calls. + +## How to use + +1. Canister project add `ic-cdk-bindgen` as a build dependency. + +```toml +[build-dependencies] +ic-cdk-bindgen = "0.1" +``` + +2. Add `build.rs` to generate Rust bindings in the source directory with config options. + +```rs +use ic_cdk_bindgen::{Builder, Config}; +fn main() { + let counter = Config::new("counter"); + let mut builder = Builder::new(); + builder.add(counter); + builder.build(None); // default write to src/declarations +} +``` + +3. In Canister code, + +```rs +mod declarations; +use declarations::counter::counter; + +counter.inc().await? +``` diff --git a/src/ic-cdk-bindgen/src/lib.rs b/src/ic-cdk-bindgen/src/lib.rs new file mode 100644 index 000000000..789b319df --- /dev/null +++ b/src/ic-cdk-bindgen/src/lib.rs @@ -0,0 +1,82 @@ +use candid::{bindings::rust, pretty_check_file, Principal}; +use std::env; +use std::fs; +use std::io::Write; +use std::path::PathBuf; + +#[derive(Clone)] +pub struct Config { + pub canister_name: String, + pub candid_path: PathBuf, + pub skip_existing_files: bool, + pub binding: rust::Config, +} +impl Config { + pub fn new(canister_name: &str) -> Self { + let candid_path_var_name = format!("CANISTER_CANDID_PATH_{}", canister_name); + let candid_path = + PathBuf::from(env::var(candid_path_var_name).expect("Cannot find candid path")); + let canister_id_var_name = format!("CANISTER_ID_{}", canister_name); + let canister_id = + Principal::from_text(env::var(canister_id_var_name).expect("Cannot find canister id")) + .unwrap(); + Config { + canister_name: canister_name.to_string(), + candid_path, + skip_existing_files: false, + binding: rust::Config { + // User will depend on candid crate directly + candid_crate: "candid".to_string(), + type_attributes: "".to_string(), + canister_id: Some(canister_id), + service_name: canister_name.to_string(), + target: rust::Target::CanisterCall, + }, + } + } +} + +#[derive(Default)] +pub struct Builder { + configs: Vec, +} + +impl Builder { + pub fn new() -> Self { + Builder { + configs: Vec::new(), + } + } + pub fn add(&mut self, config: Config) -> &mut Self { + self.configs.push(config); + self + } + pub fn build(self, out_path: Option) { + let out_path = out_path.unwrap_or_else(|| { + let manifest_dir = + PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("Cannot find manifest dir")); + manifest_dir.join("src").join("declarations") + }); + fs::create_dir_all(&out_path).unwrap(); + for conf in self.configs.iter() { + let (env, actor) = + pretty_check_file(&conf.candid_path).expect("Cannot parse candid file"); + let content = rust::compile(&conf.binding, &env, &actor); + let generated_path = out_path.join(format!("{}.rs", conf.canister_name)); + if !(conf.skip_existing_files && generated_path.exists()) { + fs::write(generated_path, content).expect("Cannot store generated binding"); + } + } + let mut module = fs::File::create(out_path.join("mod.rs")).unwrap(); + module.write_all(b"#![allow(unused_imports)]\n").unwrap(); + module + .write_all(b"#![allow(non_upper_case_globals)]\n") + .unwrap(); + module.write_all(b"#![allow(non_snake_case)]\n").unwrap(); + for conf in self.configs.iter() { + module.write_all(b"#[rustfmt::skip]\n").unwrap(); // so that we get a better diff + let line = format!("pub mod {};\n", conf.canister_name); + module.write_all(line.as_bytes()).unwrap(); + } + } +} diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index 2e09893ed..d6cfde184 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Added + +- `export_candid` macro. (#386) + +### Changed + +- Remove `import` macro. (#390) + ## [0.6.10] - 2023-03-01 ### Changed diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 20476be1a..f85ccdcd7 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.6.10" # no need to sync with ic-cdk +version = "0.7.0" # no need to sync with ic-cdk authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit macros." @@ -8,7 +8,12 @@ homepage = "https://docs.rs/ic-cdk-macros" documentation = "https://docs.rs/ic-cdk-macros" license = "Apache-2.0" readme = "README.md" -categories = ["api-bindings", "data-structures", "no-std", "development-tools::ffi"] +categories = [ + "api-bindings", + "data-structures", + "no-std", + "development-tools::ffi", +] keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] repository = "https://github.com/dfinity/cdk-rs" @@ -18,7 +23,7 @@ rust-version = "1.65.0" proc-macro = true [dependencies] -candid = "0.8.0" +candid = "0.9.0" syn = { version = "1.0.58", features = ["fold", "full"] } quote = "1.0" proc-macro2 = "1.0" @@ -27,4 +32,10 @@ serde = "1.0.111" [dev-dependencies] trybuild = "1.0" -ic-cdk = { path = "../ic-cdk", version = "0.9" } +ic-cdk = { path = "../ic-cdk", version = "0.10" } + +[features] +# This feature is not additive as normal crate features. +# Enable it may cause other dependent projects malfunctioning. +# It is only to be used by `ic-cdk`. +export_candid = [] diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index 3e9e80f44..e6891ea3f 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -135,15 +135,12 @@ fn dfn_macro( let outer_function_ident = Ident::new(&format!("{}_{}_", name, crate::id()), Span::call_site()); + let function_name = attrs.name.unwrap_or_else(|| name.to_string()); let export_name = if method.is_lifecycle() { format!("canister_{}", method) } else if method == MethodType::Query && attrs.composite { - format!( - "canister_composite_query {}", - attrs.name.unwrap_or_else(|| name.to_string()) - ) + format!("canister_composite_query {function_name}",) } else { - let function_name = attrs.name.unwrap_or_else(|| name.to_string()); if function_name.starts_with("") { return Err(Error::new( Span::call_site(), @@ -194,6 +191,24 @@ fn dfn_macro( quote! {} }; + #[cfg(feature = "export_candid")] + let candid_method_attr = match method { + MethodType::Query => { + quote! { #[::candid::candid_method(query, rename = #function_name)] } + } + MethodType::Update => { + quote! { #[::candid::candid_method(update, rename = #function_name)] } + } + MethodType::Init => quote! { #[::candid::candid_method(init)] }, + _ => quote! {}, + }; + + #[cfg(feature = "export_candid")] + let item = quote! { + #candid_method_attr + #item + }; + Ok(quote! { #[export_name = #export_name] fn #outer_function_ident() { diff --git a/src/ic-cdk-macros/src/import.rs b/src/ic-cdk-macros/src/import.rs deleted file mode 100644 index ed3803941..000000000 --- a/src/ic-cdk-macros/src/import.rs +++ /dev/null @@ -1,227 +0,0 @@ -use proc_macro2::{Span, TokenStream}; -use quote::quote; -use serde::Deserialize; -use serde_tokenstream::from_tokenstream; -use std::path::PathBuf; -use std::str::FromStr; -use syn::Error; - -#[derive(Default, Deserialize)] -struct ImportAttributes { - pub canister: Option, - pub canister_id: Option, - pub candid_path: Option, -} - -fn get_env_id_and_candid(canister_name: &str) -> Result<(String, PathBuf), Error> { - let canister_id_var_name = format!("CANISTER_ID_{}", canister_name); - let candid_path_var_name = format!("CANISTER_CANDID_PATH_{}", canister_name); - - Ok(( - std::env::var(canister_id_var_name).map_err(|_| { - Error::new( - Span::call_site(), - format!( - "Could not find DFX bindings for canister named '{}'. Did you build using DFX?", - canister_name - ), - ) - })?, - std::env::var_os(candid_path_var_name) - .ok_or_else(|| Error::new(Span::call_site(), "Could not find DFX bindings.")) - .map(PathBuf::from)?, - )) -} - -struct RustLanguageBinding { - visibility: String, - canister_id: String, -} - -impl candid::codegen::rust::RustBindings for RustLanguageBinding { - fn actor(&self, name: &str, all_functions: &[String]) -> Result { - let mut all_functions_str = String::new(); - for f in all_functions { - all_functions_str += f; - } - - Ok(format!( - r#"{vis} struct {name} {{ }} - impl {name} {{ - {functions} - }}"#, - vis = self.visibility, - name = name, - functions = all_functions_str - )) - } - - fn actor_function_body( - &self, - name: &str, - arguments: &[(String, String)], - _returns: &str, - _is_query: bool, - ) -> Result { - let canister_id = &self.canister_id; - - let arguments = if arguments.is_empty() { - "()".to_string() - } else { - format!( - "({},)", - arguments - .iter() - .map(|(name, _)| name.clone()) - .collect::>() - .join(",") - ) - }; - - let call = "ic_cdk::call"; - - // We check the validity of the canister_id early so it fails if the - // ID isn't in the right text format. - let principal: candid::Principal = candid::Principal::from_text(canister_id).unwrap(); - - Ok(format!( - r#" - {{ - {call}( - ic_cdk::export::Principal::from_text("{principal}").unwrap() as ic_cdk::export::Principal, - "{name}", - {arguments} - ) - .await - .unwrap() - }} - "#, - call = call, - principal = &principal.to_text(), - name = name.escape_debug(), - arguments = arguments, - )) - } - - fn actor_function( - &self, - name: &str, - arguments: &[(String, String)], - returns: &[String], - is_query: bool, - ) -> Result { - let id = candid::codegen::rust::candid_id_to_rust(name); - - let arguments_list = arguments - .iter() - .map(|(name, ty)| format!("{} : {}", name, ty)) - .collect::>() - .join(" , "); - - let body = self.actor_function_body(name, arguments, &returns.join(","), is_query)?; - - Ok(format!( - "async fn {id}( {arguments} ) {return_type} {body}", - id = id, - arguments = arguments_list, - body = body, - return_type = if returns.is_empty() { - String::new() - } else { - format!("-> ({},)", returns.to_vec().join(",")) - } - )) - } - - fn record( - &self, - id: &str, - fields: &[(String, String)], - ) -> Result { - let all_fields = fields - .iter() - .map(|(name, ty)| format!("pub {} : {}", name, ty)) - .collect::>() - .join(" , "); - // The following #[serde(crate = ...)] line was from https://github.com/serde-rs/serde/issues/1465#issuecomment-800686252 - // It is necessary when use re-exported serde - Ok(format!( - r#" - #[derive(Clone, Debug, Default, ic_cdk::export::candid::CandidType, ic_cdk::export::serde::Deserialize)] - #[serde(crate = "ic_cdk::export::serde")] - pub struct {} {{ {} }} - "#, - id, all_fields - )) - } -} - -pub(crate) fn ic_import(attr: TokenStream, item: TokenStream) -> Result { - let config = from_tokenstream::(&attr)?; - - // We expect both fields to have values for now. - let (canister_id, candid_path) = { - if let Some(canister_name) = config.canister { - get_env_id_and_candid(&canister_name)? - } else if let Some(canister_id) = config.canister_id { - if let Some(candid_path) = config.candid_path { - (canister_id, candid_path) - } else { - return Err(Error::new( - Span::call_site(), - "Must specify both candid and canister_id.", - )); - } - } else { - return Err(Error::new( - Span::call_site(), - "Must specify both candid and canister_id.", - )); - } - }; - - let item = syn::parse2::(item)?; - - // Validate that the item is a struct. - let item = match item { - syn::Item::Struct(item) => item, - _ => { - return Err(Error::new( - Span::call_site(), - "import must be used on a struct.", - )) - } - }; - - let visibility = { - let vis = item.vis; - format!("{}", quote! { #vis }) - }; - let struct_name = item.ident.to_string(); - - let candid_str = std::fs::read_to_string(candid_path).unwrap(); - let prog = candid::IDLProg::from_str(&candid_str).map_err(|e| { - Error::new( - Span::call_site(), - format!("Could not parse the candid file: {}", e), - ) - })?; - - let bindings = Box::new(RustLanguageBinding { - visibility, - canister_id, - }); - - let config = candid::codegen::rust::Config::default() - .with_actor_name(struct_name) - .with_biguint_type("candid::Nat".to_string()) - .with_bigint_type("candid::Int".to_string()) - .with_bindings(bindings); - - let rust_str = candid::codegen::idl_to_rust(&prog, &config) - .map_err(|e| Error::new(Span::call_site(), e.to_string()))?; - - let rust_str = format!("{} {}", "type principal = Vec;", rust_str); - - Ok(TokenStream::from_str(&rust_str).unwrap()) -} diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index fe598404d..1718f6cab 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -34,7 +34,6 @@ use std::sync::atomic::{AtomicU32, Ordering}; use syn::Error; mod export; -mod import; // To generate unique identifiers for functions and arguments static NEXT_ID: AtomicU32 = AtomicU32::new(0); @@ -72,6 +71,36 @@ where result.map_or_else(|e| e.to_compile_error().into(), Into::into) } +/// Create a WASI start function which print the Candid interface of the canister. +/// +/// Requiring "wasi" feature enabled. Or the function will have empty body. +/// +/// Call this macro only if you want the Candid export behavior. +/// Only call it once at the end of canister code outside query/update definition. +#[cfg(feature = "export_candid")] +#[proc_macro] +pub fn export_candid(input: TokenStream) -> TokenStream { + let input: proc_macro2::TokenStream = input.into(); + quote::quote! { + ::candid::export_service!(#input); + + #[no_mangle] + pub unsafe extern "C" fn _start() { + let result = __export_service(); + let ret = unsafe { ::ic_cdk::api::wasi::print(&result) }; + ::ic_cdk::api::wasi::proc_exit(ret as u32); + } + } + .into() +} + +#[doc(hidden)] +#[cfg(not(feature = "export_candid"))] +#[proc_macro] +pub fn export_candid(_: TokenStream) -> TokenStream { + quote::quote! {}.into() +} + /// Register a query call entry point. /// /// This attribute macro will export a function with name `canister_query ` @@ -119,7 +148,7 @@ where /// /// ```rust /// # use ic_cdk::query; -/// # fn wallet_canister_principal() -> ic_cdk::export::Principal { unimplemented!() } +/// # fn wallet_canister_principal() -> candid::Principal { unimplemented!() } /// #[query(composite = true)] /// async fn composite_query_function() { /// let (wallet_name,): (Option,) = ic_cdk::call(wallet_canister_principal(), "name", ()).await.unwrap(); @@ -434,33 +463,3 @@ pub fn heartbeat(attr: TokenStream, item: TokenStream) -> TokenStream { pub fn inspect_message(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_inspect_message, "ic_inspect_message", attr, item) } - -/// Import another canister as a rust struct. -/// -/// All public interfaces defined in corresponding candid file can be accessed through the annotated struct. -/// -/// # Example -/// -/// You can specify the canister with it's name. -/// -/// Please be noted that this approach relies on the project organization by [dfx](https://github.com/dfinity/sdk). -/// -/// During `dfx build`, the imported canister will be correctly resolved. -/// -/// ```rust,ignore -/// # use ic_cdk::import; -/// #[import(canister = "some_canister")] -/// struct SomeCanister; -/// ``` -/// -/// Or you can specify both the `canister_id` and the `candid_path`. -/// -/// ```rust,ignore -/// # use ic_cdk::import; -/// #[import(canister_id = "abcde-cai", candid_path = "path/to/some_canister.did")] -/// struct SomeCanister; -/// ``` -#[proc_macro_attribute] -pub fn import(attr: TokenStream, item: TokenStream) -> TokenStream { - handle_debug_and_errors(import::ic_import, "ic_import", attr, item) -} diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index 24799ea1f..9769fb0c5 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.3.0" +version = "0.4.0" authors = ["DFINITY Stiftung "] edition = "2021" description = "Timers library for the Rust CDK." @@ -15,7 +15,7 @@ repository = "https://github.com/dfinity/cdk-rs" rust-version = "1.60.0" [dependencies] -ic-cdk = { path = "../../src/ic-cdk", version = "0.9" } +ic-cdk = { path = "../../src/ic-cdk", version = "0.10" } serde = "1.0.110" serde_bytes = "0.11.7" ic0 = { path = "../ic0", version = "0.18.9" } diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index a67e668ad..158921c5e 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,55 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Changed + +- Upgrade `candid` to `0.9`. (#411) +- Remove `export` module. Please use candid directly in your project instead of using `ic_cdk::export::candid`. +- Remove `ic_cdk_macro::import` module. See below for a new way to import canisters. + +### Added + +- Export Candid: (#386) + * A wasi feature that builds the canister as a standalone WASI binary. Running the binary in wasmtime outputs the canister interface + * Build step: + ``` + cargo build --target wasm32-unknown-unknown \ + --release \ + --package "$package" --features "ic-cdk/wasi" + + wasmtime "target/wasm32-unknown-unknown/release/$package.wasm" > $did_file + + cargo build --target wasm32-unknown-unknown \ + --release \ + --package "$package" + + ic-wasm "target/wasm32-unknown-unknown/release/$package.wasm" \ + -o "target/wasm32-unknown-unknown/release/$package.wasm" \ + metadata candid:service -v public -f $did_file + ``` + * In the canister code, users have to add `ic_cdk::export_candid!()` at the end of `lib.rs`. In the future we may lift this requirement to provide a better DX. + +- Import Candid: (#390) + + * Canister project adds `ic_cdk_bindgen` as a build dependency to generate canister bindings + * build.rs + ``` + use ic_cdk_bindgen::{Builder, Config}; + fn main() { + let counter = Config::new("counter"); + let mut builder = Builder::new(); + builder.add(counter); + builder.build(None); // default write to src/declarations + } + ``` + * In the canister code, + ``` + mod declarations; + use declarations::counter::counter; + + counter.inc().await? + ``` + ## [0.9.2] - 2023-06-22 ### Changed diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 1eb68eedd..9c5b03add 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.9.2" +version = "0.10.0" authors = ["DFINITY Stiftung "] edition = "2021" description = "Canister Developer Kit for the Internet Computer." @@ -20,9 +20,9 @@ repository = "https://github.com/dfinity/cdk-rs" rust-version = "1.65.0" [dependencies] -candid = "0.8" -ic0 = { path = "../ic0", version = "0.18.10" } -ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.6.7" } +candid = "0.9" +ic0 = { path = "../ic0", version = "0.18.11" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.7.0" } serde = "1.0.110" serde_bytes = "0.11.7" slotmap = { version = "1.0.6", optional = true } @@ -32,8 +32,12 @@ rstest = "0.12.0" [features] transform-closure = ["dep:slotmap"] +# The feature below is not additive as normal crate features. +# Enable it may cause other dependent projects malfunctioning. +# It is only to be used by canister IDL generation. +wasi = ["ic0/wasi", "ic-cdk-macros/export_candid"] [package.metadata.docs.rs] -all-features = true +features = ["transform-closure"] default-target = "wasm32-unknown-unknown" rustdoc-args = ["--cfg=docsrs"] diff --git a/src/ic-cdk/src/api/management_canister/http_request/types.rs b/src/ic-cdk/src/api/management_canister/http_request/types.rs index e05b1585b..1e4fafe8c 100644 --- a/src/ic-cdk/src/api/management_canister/http_request/types.rs +++ b/src/ic-cdk/src/api/management_canister/http_request/types.rs @@ -1,29 +1,22 @@ use crate::id; -use candid::{ - parser::types::FuncMode, - types::{Function, Serializer, Type}, - CandidType, Func, -}; +use candid::CandidType; use serde::{Deserialize, Serialize}; -/// "transform" function of type: `func (http_request) -> (http_response) query` -#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct TransformFunc(pub candid::Func); +mod transform { + #![allow(missing_docs)] -impl CandidType for TransformFunc { - fn _ty() -> Type { - Type::Func(Function { - modes: vec![FuncMode::Query], - args: vec![TransformArgs::ty()], - rets: vec![HttpResponse::ty()], - }) - } + // The struct `TransformFunc` is defined by a macro. + // Adding doc comment directly above the macro doesn't work. + // The workaround is to re-export it and document there. + // TODO: upgrade Rust toolchain (https://dfinity.atlassian.net/browse/SDK-1183) + use super::*; - fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> { - serializer.serialize_function(self.0.principal.as_slice(), &self.0.method) - } + candid::define_function!(pub TransformFunc : (TransformArgs) -> (HttpResponse) query); } +/// "transform" function of type: `func (http_response) -> (http_response) query` +pub use transform::TransformFunc; + /// Type used for encoding/decoding: /// `record { /// response : http_response; @@ -59,7 +52,7 @@ impl TransformContext { pub fn from_name(candid_function_name: String, context: Vec) -> Self { Self { context, - function: TransformFunc(Func { + function: TransformFunc(candid::Func { method: candid_function_name, principal: id(), }), @@ -108,7 +101,7 @@ pub enum HttpMethod { HEAD, } -/// Argument type of [http_request]. +/// Argument type of [super::http_request]. #[derive(CandidType, Deserialize, Debug, PartialEq, Eq, Clone, Default)] pub struct CanisterHttpRequestArgument { /// The requested URL. diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index 1ce2f9daa..947eaa099 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -6,6 +6,10 @@ pub mod call; pub mod management_canister; pub mod stable; +#[cfg(feature = "wasi")] +#[doc(hidden)] +pub mod wasi; + /// Prints the given message. pub fn print>(s: S) { let s = s.as_ref(); diff --git a/src/ic-cdk/src/api/wasi.rs b/src/ic-cdk/src/api/wasi.rs new file mode 100644 index 000000000..2ac01c837 --- /dev/null +++ b/src/ic-cdk/src/api/wasi.rs @@ -0,0 +1,33 @@ +//! This module is only for internal usage of [crate::export_candid] macro. +//! +//! A simple WASI binding. It's only enabled by the "wasi" feature to allow building +//! the canister as a standalone WASI binary that can output its Candid interface in wasmtime. +//! +//! NEVER use them in Canister code. + +type Fd = u32; +type Size = usize; +pub type Errno = i32; +pub type Rval = u32; + +#[derive(Debug)] +#[repr(C)] +pub struct Ciovec { + buf: *const u8, + buf_len: Size, +} + +#[link(wasm_import_module = "wasi_snapshot_preview1")] +extern "C" { + pub fn fd_write(fd: Fd, iovs_ptr: *const Ciovec, iovs_len: Size, nwritten: *mut Size) -> Errno; + pub fn proc_exit(rval: Rval); +} +pub unsafe fn print(text: &str) -> Errno { + let ciovec = Ciovec { + buf: text.as_ptr(), + buf_len: text.len(), + }; + let ciovecs = [ciovec]; + let mut nwritten = 0; + unsafe { fd_write(1, ciovecs.as_ptr(), ciovecs.len(), &mut nwritten) } +} diff --git a/src/ic-cdk/src/lib.rs b/src/ic-cdk/src/lib.rs index 0b4d38717..b15390382 100644 --- a/src/ic-cdk/src/lib.rs +++ b/src/ic-cdk/src/lib.rs @@ -33,13 +33,6 @@ pub use api::{caller, id, print, trap}; static DONE: AtomicBool = AtomicBool::new(false); -/// Re-exports crates those are necessary for using ic-cdk -pub mod export { - pub use candid; - pub use candid::Principal; - pub use serde; -} - /// Setup the stdlib hooks. pub fn setup() { if !DONE.swap(true, Ordering::SeqCst) { diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml index 01836584a..848c86c7e 100644 --- a/src/ic0/Cargo.toml +++ b/src/ic0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic0" -version = "0.18.10" +version = "0.18.11" authors = ["DFINITY Stiftung "] edition = "2021" description = "Internet Computer System API Binding." @@ -16,6 +16,12 @@ rust-version = "1.60.0" quote = { version = "1.0" } syn = { version = "1.0", features = ["parsing", "full", "extra-traits"] } +[features] +# This feature is not additive as normal crate features. +# Enable it may cause other dependent projects malfunctioning. +# It is only to be used by `ic-cdk`. +wasi = [] + # This is not a real example but a utility for auto-generating ic0.rs [[example]] name = "ic0build" diff --git a/src/ic0/src/ic0.rs b/src/ic0/src/ic0.rs index f5c2ba03c..371f5a345 100644 --- a/src/ic0/src/ic0.rs +++ b/src/ic0/src/ic0.rs @@ -1,6 +1,6 @@ // This file is generated from ic0.txt. // Don't manually modify it. -#[cfg(target_arch = "wasm32")] +#[cfg(all(target_arch = "wasm32", not(feature = "wasi")))] #[link(wasm_import_module = "ic0")] extern "C" { pub fn msg_arg_data_size() -> i32; @@ -63,7 +63,7 @@ extern "C" { pub fn trap(src: i32, size: i32); } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(all(target_arch = "wasm32", not(feature = "wasi"))))] #[allow(unused_variables)] #[allow(clippy::missing_safety_doc)] #[allow(clippy::too_many_arguments)] @@ -226,5 +226,5 @@ mod non_wasm { } } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(all(target_arch = "wasm32", not(feature = "wasi"))))] pub use non_wasm::*; diff --git a/src/ic0/util/ic0build.rs b/src/ic0/util/ic0build.rs index 2d509730a..d4c0100f0 100644 --- a/src/ic0/util/ic0build.rs +++ b/src/ic0/util/ic0build.rs @@ -118,7 +118,7 @@ fn main() { f, r#"// This file is generated from ic0.txt. // Don't manually modify it. -#[cfg(target_arch = "wasm32")] +#[cfg(all(target_arch = "wasm32", not(feature = "wasi")))] #[link(wasm_import_module = "ic0")] extern "C" {{"#, ) @@ -147,7 +147,7 @@ extern "C" {{"#, writeln!( f, r#" -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(all(target_arch = "wasm32", not(feature = "wasi"))))] #[allow(unused_variables)] #[allow(clippy::missing_safety_doc)] #[allow(clippy::too_many_arguments)] @@ -182,7 +182,7 @@ mod non_wasm{{"#, f, r#"}} -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(all(target_arch = "wasm32", not(feature = "wasi"))))] pub use non_wasm::*; "# ) From bfa8bf6067b86993844c7881bf1303e21bd9fc24 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 13 Jul 2023 18:07:13 -0400 Subject: [PATCH 163/234] chore: Rust v1.65.0 and cargo workspace (#415) * rust 1.70.0 * rust update notice * link LICENSE * rust v1.65.0 * workspace.dependencies --- .github/workflows/ci.yml | 2 +- .github/workflows/examples.yml | 2 +- Cargo.toml | 19 +++ e2e-tests/Cargo.toml | 12 +- legacy/ic-cdk-optimizer/LICENSE | 202 +--------------------------- library/ic-certified-map/Cargo.toml | 29 ++-- library/ic-certified-map/LICENSE | 202 +--------------------------- library/ic-ledger-types/Cargo.toml | 22 +-- library/ic-ledger-types/LICENSE | 202 +--------------------------- rust-toolchain.toml | 7 +- src/ic-cdk-bindgen/Cargo.toml | 10 +- src/ic-cdk-macros/Cargo.toml | 20 +-- src/ic-cdk-macros/LICENSE | 202 +--------------------------- src/ic-cdk-timers/Cargo.toml | 29 ++-- src/ic-cdk/Cargo.toml | 20 +-- src/ic-cdk/LICENSE | 202 +--------------------------- src/ic0/Cargo.toml | 14 +- 17 files changed, 114 insertions(+), 1082 deletions(-) mode change 100644 => 120000 legacy/ic-cdk-optimizer/LICENSE mode change 100644 => 120000 library/ic-certified-map/LICENSE mode change 100644 => 120000 library/ic-ledger-types/LICENSE mode change 100644 => 120000 src/ic-cdk-macros/LICENSE mode change 100644 => 120000 src/ic-cdk/LICENSE diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80b641ab6..135c18e27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ concurrency: cancel-in-progress: true env: - rust-version: 1.66.1 + rust-version: 1.65.0 jobs: build: diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 47270e3a0..14b64a276 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -11,7 +11,7 @@ concurrency: cancel-in-progress: true env: - rust-version: 1.66.1 + rust-version: 1.65.0 dfx-version: 0.14.1 wasmtime-version: 10.0.1 diff --git a/Cargo.toml b/Cargo.toml index 0810284f7..894ec1597 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,13 @@ members = [ "e2e-tests", ] +[workspace.package] +authors = ["DFINITY Stiftung "] +edition = "2021" +repository = "https://github.com/dfinity/cdk-rs" +rust-version = "1.65.0" +license = "Apache-2.0" + [profile.canister-release] inherits = "release" debug = false @@ -18,4 +25,16 @@ lto = true opt-level = 'z' [workspace.dependencies] +ic0 = { path = "src/ic0", version = "0.18.11" } +ic-cdk = { path = "src/ic-cdk", version = "0.10" } +ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.4.0" } + candid = "0.9" +futures = "0.3" +hex = "0.4" +quote = "1" +serde = "1" +serde_bytes = "0.11" +sha2 = "0.10" +slotmap = "1" +syn = "1" diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 53c6c6418..c3d061116 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -8,14 +8,14 @@ license = "Apache-2.0" repository = "https://github.com/dfinity/cdk-rs" [dependencies] -candid = "0.9" +candid.workspace = true cargo_metadata = "0.14.2" escargot = { version = "0.5.7", features = ["print"] } -ic-cdk = { path = "../src/ic-cdk" } -ic-cdk-timers = { path = "../src/ic-cdk-timers" } +ic-cdk.workspace = true +ic-cdk-timers.workspace = true lazy_static = "1.4.0" -serde_bytes = "0.11" -futures = "0.3" +serde_bytes.workspace = true +futures.workspace = true [[bin]] name = "simple-kv-store" @@ -42,6 +42,6 @@ name = "canister_info" path = "canisters/canister_info.rs" [dev-dependencies] -hex = "0.4.3" +hex.workspace = true # TODO: Use the public crate when this [PR](https://github.com/dfinity/test-state-machine-client/pull/19) merge. ic-test-state-machine-client = { git = "https://github.com/lwshang/test-state-machine-client", branch = "lwshang/candid_0.9" } diff --git a/legacy/ic-cdk-optimizer/LICENSE b/legacy/ic-cdk-optimizer/LICENSE deleted file mode 100644 index b27ba1fe8..000000000 --- a/legacy/ic-cdk-optimizer/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2020 DFINITY LLC. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/legacy/ic-cdk-optimizer/LICENSE b/legacy/ic-cdk-optimizer/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/legacy/ic-cdk-optimizer/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/library/ic-certified-map/Cargo.toml b/library/ic-certified-map/Cargo.toml index abd17ab4f..c72a6e3bf 100644 --- a/library/ic-certified-map/Cargo.toml +++ b/library/ic-certified-map/Cargo.toml @@ -1,27 +1,30 @@ [package] name = "ic-certified-map" version = "0.4.0" -edition = "2021" -authors = ["DFINITY Stiftung "] +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true description = "Merkleized map data structure." homepage = "https://docs.rs/ic-certified-map" documentation = "https://docs.rs/ic-certified-map" -license = "Apache-2.0" readme = "README.md" -categories = ["data-structures", "cryptography", "cryptography::cryptocurrencies"] +categories = [ + "data-structures", + "cryptography", + "cryptography::cryptocurrencies", +] keywords = ["internet-computer", "types", "dfinity", "map"] include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"] -repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.60.0" [dependencies] -serde = "1" -serde_bytes = "0.11" -sha2 = "0.10" +serde.workspace = true +serde_bytes.workspace = true +sha2.workspace = true [dev-dependencies] -hex = "0.4" +hex.workspace = true serde_cbor = "0.11" -ic-cdk = { path = "../../src/ic-cdk", version = "0.10" } -candid = "0.9" -serde = "1" +ic-cdk.workspace = true +candid.workspace = true diff --git a/library/ic-certified-map/LICENSE b/library/ic-certified-map/LICENSE deleted file mode 100644 index b27ba1fe8..000000000 --- a/library/ic-certified-map/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2020 DFINITY LLC. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/library/ic-certified-map/LICENSE b/library/ic-certified-map/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/library/ic-certified-map/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index d0a7ae546..f119798aa 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,26 +1,26 @@ [package] name = "ic-ledger-types" version = "0.7.0" -edition = "2021" -authors = ["DFINITY Stiftung "] +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true description = "Types for interacting with the ICP ledger canister." homepage = "https://docs.rs/ic-ledger-types" documentation = "https://docs.rs/ic-ledger-types" -license = "Apache-2.0" readme = "README.md" keywords = ["internet-computer", "ledger"] categories = ["cryptography::cryptocurrencies", "data-structures"] include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"] -repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.65.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ic-cdk = { path = "../../src/ic-cdk", version = "0.10.0" } -candid = "0.9.0" +ic-cdk.workspace = true +candid.workspace = true crc32fast = "1.2.0" -hex = "0.4" -serde = "1" -serde_bytes = "0.11" -sha2 = "0.9" +hex.workspace = true +serde.workspace = true +serde_bytes.workspace = true +sha2.workspace = true diff --git a/library/ic-ledger-types/LICENSE b/library/ic-ledger-types/LICENSE deleted file mode 100644 index b27ba1fe8..000000000 --- a/library/ic-ledger-types/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2020 DFINITY LLC. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/library/ic-ledger-types/LICENSE b/library/ic-ledger-types/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/library/ic-ledger-types/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f86079475..ac0d4e3cf 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,9 @@ [toolchain] -channel = "1.66.1" +channel = "1.65.0" targets = ["wasm32-unknown-unknown"] components = ["rustfmt", "clippy"] + +# Sync rust-version in following files +# Cargo.toml +# .github/workflows/ci.yml +# .github/workflows/examples.yml diff --git a/src/ic-cdk-bindgen/Cargo.toml b/src/ic-cdk-bindgen/Cargo.toml index 9df297c20..aceb0cbed 100644 --- a/src/ic-cdk-bindgen/Cargo.toml +++ b/src/ic-cdk-bindgen/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "ic-cdk-bindgen" version = "0.1.0" -authors = ["DFINITY Stiftung "] -edition = "2021" +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true description = "Internet Computer Binding Generator." -license = "Apache-2.0" readme = "README.md" categories = ["api-bindings", "development-tools::ffi"] keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] -repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.66.1" [dependencies] candid = { workspace = true, features = ["parser"] } diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index f85ccdcd7..74624d355 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,12 +1,14 @@ [package] name = "ic-cdk-macros" version = "0.7.0" # no need to sync with ic-cdk -authors = ["DFINITY Stiftung "] -edition = "2021" +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true description = "Canister Developer Kit macros." homepage = "https://docs.rs/ic-cdk-macros" documentation = "https://docs.rs/ic-cdk-macros" -license = "Apache-2.0" readme = "README.md" categories = [ "api-bindings", @@ -16,23 +18,21 @@ categories = [ ] keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] -repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.65.0" [lib] proc-macro = true [dependencies] -candid = "0.9.0" -syn = { version = "1.0.58", features = ["fold", "full"] } -quote = "1.0" +candid.workspace = true proc-macro2 = "1.0" +quote.workspace = true +serde.workspace = true serde_tokenstream = "0.1.0" -serde = "1.0.111" +syn = { workspace = true, features = ["fold", "full"] } [dev-dependencies] trybuild = "1.0" -ic-cdk = { path = "../ic-cdk", version = "0.10" } +ic-cdk.workspace = true [features] # This feature is not additive as normal crate features. diff --git a/src/ic-cdk-macros/LICENSE b/src/ic-cdk-macros/LICENSE deleted file mode 100644 index b27ba1fe8..000000000 --- a/src/ic-cdk-macros/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2020 DFINITY LLC. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/src/ic-cdk-macros/LICENSE b/src/ic-cdk-macros/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/src/ic-cdk-macros/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index 9769fb0c5..c4934f458 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,26 +1,31 @@ [package] name = "ic-cdk-timers" version = "0.4.0" -authors = ["DFINITY Stiftung "] -edition = "2021" +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true description = "Timers library for the Rust CDK." homepage = "https://docs.rs/ic-cdk" documentation = "https://docs.rs/ic-cdk-timers" -license = "Apache-2.0" readme = "README.md" -categories = ["api-bindings", "data-structures", "no-std", "development-tools::ffi"] +categories = [ + "api-bindings", + "data-structures", + "no-std", + "development-tools::ffi", +] keywords = ["internet-computer", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] -repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.60.0" [dependencies] -ic-cdk = { path = "../../src/ic-cdk", version = "0.10" } -serde = "1.0.110" -serde_bytes = "0.11.7" -ic0 = { path = "../ic0", version = "0.18.9" } -slotmap = { version = "1.0.6" } -futures = { version = "0.3.25" } +ic0.workspace = true +ic-cdk.workspace = true +serde.workspace = true +serde_bytes.workspace = true +slotmap.workspace = true +futures.workspace = true [package.metadata.docs.rs] default-target = "wasm32-unknown-unknown" diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 9c5b03add..0682552ee 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,12 +1,14 @@ [package] name = "ic-cdk" version = "0.10.0" -authors = ["DFINITY Stiftung "] -edition = "2021" +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true description = "Canister Developer Kit for the Internet Computer." homepage = "https://docs.rs/ic-cdk" documentation = "https://docs.rs/ic-cdk" -license = "Apache-2.0" readme = "README.md" categories = [ "api-bindings", @@ -16,16 +18,14 @@ categories = [ ] keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] -repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.65.0" [dependencies] -candid = "0.9" -ic0 = { path = "../ic0", version = "0.18.11" } +candid.workspace = true +ic0.workspace = true ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.7.0" } -serde = "1.0.110" -serde_bytes = "0.11.7" -slotmap = { version = "1.0.6", optional = true } +serde.workspace = true +serde_bytes.workspace = true +slotmap = { workspace = true, optional = true } [dev-dependencies] rstest = "0.12.0" diff --git a/src/ic-cdk/LICENSE b/src/ic-cdk/LICENSE deleted file mode 100644 index b27ba1fe8..000000000 --- a/src/ic-cdk/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2020 DFINITY LLC. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/src/ic-cdk/LICENSE b/src/ic-cdk/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/src/ic-cdk/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml index 848c86c7e..6b6819d23 100644 --- a/src/ic0/Cargo.toml +++ b/src/ic0/Cargo.toml @@ -1,20 +1,20 @@ [package] name = "ic0" version = "0.18.11" -authors = ["DFINITY Stiftung "] -edition = "2021" +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true description = "Internet Computer System API Binding." -license = "Apache-2.0" readme = "README.md" categories = ["api-bindings", "development-tools::ffi"] keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] -repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.60.0" [dev-dependencies] -quote = { version = "1.0" } -syn = { version = "1.0", features = ["parsing", "full", "extra-traits"] } +quote.workspace = true +syn = { workspace = true, features = ["parsing", "full", "extra-traits"] } [features] # This feature is not additive as normal crate features. From 185f49f1b05838a540033f8e7a38720992d55eae Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 13 Jul 2023 18:33:07 -0400 Subject: [PATCH 164/234] update README and CHANGELOG (#416) --- README.md | 10 +++++++--- library/ic-certified-map/CHANGELOG.md | 2 ++ library/ic-ledger-types/CHANGELOG.md | 2 ++ src/ic-cdk-bindgen/CHANGELOG.md | 11 +++++++++++ src/ic-cdk-macros/CHANGELOG.md | 2 ++ src/ic-cdk-timers/CHANGELOG.md | 6 ++++++ src/ic-cdk-timers/README.md | 2 +- src/ic-cdk/CHANGELOG.md | 2 ++ 8 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 src/ic-cdk-bindgen/CHANGELOG.md diff --git a/README.md b/README.md index 145f363a1..606eda182 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,12 @@ To be a `canister`, a wasm module should communicate with the execution environm This repo provides libraries and tools to facilitate developing canisters in Rust. +- [`ic0`](src/ic0): +Internet Computer System API binding. - [`ic-cdk`](src/ic-cdk): -Bindings of the System API. +Internet Computer Canister Development Kit +- [`ic-cdk-bindgen`](src/ic-cdk-bindgen): +Generate Rust bindings from Candid to make inter-canister calls. - [`ic-cdk-macros`](src/ic-cdk-macros): Annotate functions with attribute macros to make them exposed public interfaces. - [`ic-cdk-timers`](src/ic-cdk-timers): @@ -46,8 +50,8 @@ In Cargo.toml: crate-type = ["cdylib"] [dependencies] -candid = "0.8.0" # this is required if you want to use the `#[import]` macro -ic-cdk = "0.6" +candid = "0.9" # this version is required if you want to define Candid data types +ic-cdk = "0.10" ``` Then in your rust source code: diff --git a/library/ic-certified-map/CHANGELOG.md b/library/ic-certified-map/CHANGELOG.md index 3ce069f69..e47783d12 100644 --- a/library/ic-certified-map/CHANGELOG.md +++ b/library/ic-certified-map/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [0.4.0] - 2023-07-13 + ### Changed - Upgrade `ic-cdk` to v0.10 and `candid` to v0.9. diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index 960d94c9d..d4ae8d089 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.7.0] - 2023-07-13 + ### Added - from_hex/from_slice/to_hex methods to AccountIdentifier in ic-ledger-types diff --git a/src/ic-cdk-bindgen/CHANGELOG.md b/src/ic-cdk-bindgen/CHANGELOG.md new file mode 100644 index 000000000..a097f8970 --- /dev/null +++ b/src/ic-cdk-bindgen/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [unreleased] + +## [0.1.0] - 2023-07-13 + +- First release. diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index d6cfde184..4eb9b661c 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.7.0] - 2023-07-13 + ### Added - `export_candid` macro. (#386) diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index ec6060990..341af576b 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.4.0] - 2023-07-13 + +### Changed + +- Upgrade `ic-cdk` to v0.10. + ## [0.3.0] - 2023-06-20 ### Changed diff --git a/src/ic-cdk-timers/README.md b/src/ic-cdk-timers/README.md index eaa5766ba..bf0cdb021 100644 --- a/src/ic-cdk-timers/README.md +++ b/src/ic-cdk-timers/README.md @@ -16,7 +16,7 @@ In `Cargo.toml`: ```toml [dependencies] -ic-cdk-timers = "0.1.1" +ic-cdk-timers = "0.4.0" ``` To schedule a one-shot task to be executed 1s later: diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 158921c5e..f83fe9de5 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.10.0] - 2023-07-13 + ### Changed - Upgrade `candid` to `0.9`. (#411) From 779306cddffdbedd5f28933ddeb023259d57535f Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 27 Jul 2023 15:02:17 -0400 Subject: [PATCH 165/234] fix: only update/query macros can take guard function (#418) * fix: only update/query take guard function * trim docs * test * fix doc:wq * bump ver * changelog * fix docs --- src/ic-cdk-macros/CHANGELOG.md | 6 ++ src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-macros/src/export.rs | 7 ++ src/ic-cdk-macros/src/lib.rs | 88 +------------------ .../no_guard_function_for_lifecycle.rs | 22 +++++ .../no_guard_function_for_lifecycle.stderr | 29 ++++++ 6 files changed, 69 insertions(+), 85 deletions(-) create mode 100644 src/ic-cdk-macros/tests/compile_fail/no_guard_function_for_lifecycle.rs create mode 100644 src/ic-cdk-macros/tests/compile_fail/no_guard_function_for_lifecycle.stderr diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index 4eb9b661c..b9cafea9c 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.7.1] - 2023-07-27 + +### Fixed + +- Only update/query macros can take guard function. (#417) + ## [0.7.0] - 2023-07-13 ### Added diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 74624d355..ffae31ae2 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.7.0" # no need to sync with ic-cdk +version = "0.7.1" # no need to sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index e6891ea3f..a410d62e5 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -178,6 +178,13 @@ fn dfn_macro( }; let guard = if let Some(guard_name) = attrs.guard { + // ic_cdk::api::call::reject calls ic0::msg_reject which is only allowed in update/query + if method.is_lifecycle() { + return Err(Error::new( + attr.span(), + format!("#[{}] cannot have a guard function.", method), + )); + } let guard_ident = syn::Ident::new(&guard_name, Span::call_site()); quote! { diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index 1718f6cab..63b2bad5a 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -1,8 +1,8 @@ -//! This crate provide a set of attribute macros to faciliate canister development. +//! This crate provide a set of attribute macros to facilitate canister development. //! //! The macros fall into two categories: //! * To register functions as canister entry points -//! * To import another canister as a rust struct for inter-canister operation. +//! * To export candid definitions //! //! ## Register functions as canister entry points //! @@ -16,9 +16,9 @@ //! * [`update`](attr.update.html) //! * [`query`](attr.query.html) //! -//! ## Import another canister as a rust struct +//! ## Export candid definitions //! -//! * [`import`](attr.import.html) +//! * [`export_candid`](attr.export_candid.html) #![warn( elided_lifetimes_in_paths, @@ -262,22 +262,6 @@ pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream { /// } /// ``` /// -/// You can specify a guard function to be executed before the init function. -/// When the guard function returns an error, the init function will not proceed. -/// -/// ```rust -/// # use ic_cdk::init; -/// fn guard_function() -> Result<(), String> { -/// // ... -/// # unimplemented!() -/// } -/// #[init(guard = "guard_function")] -/// fn init_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` -/// /// The init function may accept an argument, if that argument is a `CandidType`: /// /// ```rust @@ -323,22 +307,6 @@ pub fn init(attr: TokenStream, item: TokenStream) -> TokenStream { /// # unimplemented!() /// } /// ``` -/// -/// You can specify a guard function to be executed before the pre_upgrade function. -/// When the guard function returns an error, the pre_upgrade function will not proceed. -/// -/// ```rust -/// # use ic_cdk::pre_upgrade; -/// fn guard_function() -> Result<(), String> { -/// // ... -/// # unimplemented!() -/// } -/// #[pre_upgrade(guard = "guard_function")] -/// fn pre_upgrade_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` #[proc_macro_attribute] pub fn pre_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_pre_upgrade, "ic_pre_upgrade", attr, item) @@ -363,22 +331,6 @@ pub fn pre_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { /// # unimplemented!() /// } /// ``` -/// -/// You can specify a guard function to be executed before the post_upgrade function. -/// When the guard function returns an error, the post_upgrade function will not proceed. -/// -/// ```rust -/// # use ic_cdk::post_upgrade; -/// fn guard_function() -> Result<(), String> { -/// // ... -/// # unimplemented!() -/// } -/// #[post_upgrade(guard = "guard_function")] -/// fn post_upgrade_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` #[proc_macro_attribute] pub fn post_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_post_upgrade, "ic_post_upgrade", attr, item) @@ -403,22 +355,6 @@ pub fn post_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { /// # unimplemented!() /// } /// ``` -/// -/// You can specify a guard function to be executed before the heartbeat function. -/// When the guard function returns an error, the heartbeat function will not proceed. -/// -/// ```rust -/// # use ic_cdk::heartbeat; -/// fn guard_function() -> Result<(), String> { -/// // ... -/// # unimplemented!() -/// } -/// #[heartbeat(guard = "guard_function")] -/// fn heartbeat_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` #[proc_macro_attribute] pub fn heartbeat(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_heartbeat, "ic_heartbeat", attr, item) @@ -443,22 +379,6 @@ pub fn heartbeat(attr: TokenStream, item: TokenStream) -> TokenStream { /// # unimplemented!() /// } /// ``` -/// -/// You can specify a guard function to be executed before the inspect_message function. -/// When the guard function returns an error, the inspect_message function will not proceed. -/// -/// ```rust -/// # use ic_cdk::*; -/// fn guard_function() -> Result<(), String> { -/// // ... -/// # unimplemented!() -/// } -/// #[inspect_message(guard = "guard_function")] -/// fn inspect_message_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` #[proc_macro_attribute] pub fn inspect_message(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_inspect_message, "ic_inspect_message", attr, item) diff --git a/src/ic-cdk-macros/tests/compile_fail/no_guard_function_for_lifecycle.rs b/src/ic-cdk-macros/tests/compile_fail/no_guard_function_for_lifecycle.rs new file mode 100644 index 000000000..d4d275e56 --- /dev/null +++ b/src/ic-cdk-macros/tests/compile_fail/no_guard_function_for_lifecycle.rs @@ -0,0 +1,22 @@ +use ic_cdk::{heartbeat, init, inspect_message, post_upgrade, pre_upgrade}; + +fn guard_function() -> Result<(), String> { + unimplemented!() +} + +#[init(guard = "guard_function")] +fn init() {} + +#[pre_upgrade(guard = "guard_function")] +fn pre_upgrade() {} + +#[post_upgrade(guard = "guard_function")] +fn post_upgrade() {} + +#[heartbeat(guard = "guard_function")] +fn heartbeat() {} + +#[inspect_message(guard = "guard_function")] +fn inspect_message() {} + +fn main() {} diff --git a/src/ic-cdk-macros/tests/compile_fail/no_guard_function_for_lifecycle.stderr b/src/ic-cdk-macros/tests/compile_fail/no_guard_function_for_lifecycle.stderr new file mode 100644 index 000000000..fd9aee99f --- /dev/null +++ b/src/ic-cdk-macros/tests/compile_fail/no_guard_function_for_lifecycle.stderr @@ -0,0 +1,29 @@ +error: #[init] cannot have a guard function. + --> tests/compile_fail/no_guard_function_for_lifecycle.rs:7:8 + | +7 | #[init(guard = "guard_function")] + | ^^^^^ + +error: #[pre_upgrade] cannot have a guard function. + --> tests/compile_fail/no_guard_function_for_lifecycle.rs:10:15 + | +10 | #[pre_upgrade(guard = "guard_function")] + | ^^^^^ + +error: #[post_upgrade] cannot have a guard function. + --> tests/compile_fail/no_guard_function_for_lifecycle.rs:13:16 + | +13 | #[post_upgrade(guard = "guard_function")] + | ^^^^^ + +error: #[heartbeat] cannot have a guard function. + --> tests/compile_fail/no_guard_function_for_lifecycle.rs:16:13 + | +16 | #[heartbeat(guard = "guard_function")] + | ^^^^^ + +error: #[inspect_message] cannot have a guard function. + --> tests/compile_fail/no_guard_function_for_lifecycle.rs:19:19 + | +19 | #[inspect_message(guard = "guard_function")] + | ^^^^^ From e29d873d147a1c72125a4f8522463cda61cc7b9e Mon Sep 17 00:00:00 2001 From: Severin Siffert Date: Fri, 4 Aug 2023 14:26:45 +0200 Subject: [PATCH 166/234] chore: update Rust toolchain (#420) --- .github/workflows/ci.yml | 2 +- .github/workflows/examples.yml | 2 +- Cargo.toml | 2 +- rust-toolchain.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 135c18e27..1d4f1db26 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ concurrency: cancel-in-progress: true env: - rust-version: 1.65.0 + rust-version: 1.71.1 jobs: build: diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 14b64a276..9685d65cd 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -11,7 +11,7 @@ concurrency: cancel-in-progress: true env: - rust-version: 1.65.0 + rust-version: 1.71.1 dfx-version: 0.14.1 wasmtime-version: 10.0.1 diff --git a/Cargo.toml b/Cargo.toml index 894ec1597..b0846e8f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ authors = ["DFINITY Stiftung "] edition = "2021" repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.65.0" +rust-version = "1.71.1" license = "Apache-2.0" [profile.canister-release] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index ac0d4e3cf..53ad48c8e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.65.0" +channel = "1.71.1" targets = ["wasm32-unknown-unknown"] components = ["rustfmt", "clippy"] From 0f674bd5adfd5323ee3d1777acd5a850fa3cbd01 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 4 Aug 2023 14:25:58 -0400 Subject: [PATCH 167/234] Revert MSRV (#421) --- .github/workflows/ci.yml | 2 +- .github/workflows/examples.yml | 2 +- Cargo.toml | 7 ++++++- rust-toolchain.toml | 6 ++---- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d4f1db26..135c18e27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ concurrency: cancel-in-progress: true env: - rust-version: 1.71.1 + rust-version: 1.65.0 jobs: build: diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 9685d65cd..14b64a276 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -11,7 +11,7 @@ concurrency: cancel-in-progress: true env: - rust-version: 1.71.1 + rust-version: 1.65.0 dfx-version: 0.14.1 wasmtime-version: 10.0.1 diff --git a/Cargo.toml b/Cargo.toml index b0846e8f3..3739a4709 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,12 @@ members = [ authors = ["DFINITY Stiftung "] edition = "2021" repository = "https://github.com/dfinity/cdk-rs" -rust-version = "1.71.1" +# MSRV +# Avoid updating this field unless we use new Rust features +# Sync rust-version in following CI files: +# .github/workflows/ci.yml +# .github/workflows/examples.yml +rust-version = "1.65.0" license = "Apache-2.0" [profile.canister-release] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 53ad48c8e..bce0b458d 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -3,7 +3,5 @@ channel = "1.71.1" targets = ["wasm32-unknown-unknown"] components = ["rustfmt", "clippy"] -# Sync rust-version in following files -# Cargo.toml -# .github/workflows/ci.yml -# .github/workflows/examples.yml +# The version only influences the local develop environment. +# No need to sync with Cargo.toml and CI. From e64b92359e726001bd2e6e90cb1c1a116d4f452e Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Wed, 23 Aug 2023 14:36:00 -0700 Subject: [PATCH 168/234] fix: export composite query correctly (#419) * fix: export composite query correctly * changelog --- src/ic-cdk-macros/CHANGELOG.md | 4 ++++ src/ic-cdk-macros/src/export.rs | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index b9cafea9c..79a292309 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Fixed + +- Export composite_query to Candid. (#419) + ## [0.7.1] - 2023-07-27 ### Fixed diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index a410d62e5..7ad6c645d 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -200,9 +200,10 @@ fn dfn_macro( #[cfg(feature = "export_candid")] let candid_method_attr = match method { - MethodType::Query => { - quote! { #[::candid::candid_method(query, rename = #function_name)] } + MethodType::Query if attrs.composite => { + quote! { #[::candid::candid_method(composite_query, rename = #function_name)] } } + MethodType::Query => quote! { #[::candid::candid_method(query, rename = #function_name)] }, MethodType::Update => { quote! { #[::candid::candid_method(update, rename = #function_name)] } } From b2645739019a1def229f3b647f0370e27ab3ce1c Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 18 Sep 2023 12:28:41 -0400 Subject: [PATCH 169/234] feat: introduce candid-extractor for candid export (#424) * remove wasi feature * export_candid * examples and CI * speed up ic-wasm install * fix * add candid-extractor crate * update readme and ic0.txt * update CI * fix CI * try again * fix ci * fix * bump versions and update changelog * update date * Update src/ic-cdk-timers/CHANGELOG.md Co-authored-by: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> --------- Co-authored-by: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> --- .github/workflows/ci.yml | 4 +- .github/workflows/examples.yml | 54 +++++- Cargo.toml | 9 +- README.md | 4 +- examples/build.sh | 11 +- examples/counter/src/inter2_rs/build.rs | 4 +- .../profile/src/profile_inter_rs/build.rs | 4 +- examples/profile/src/profile_inter_rs/lib.rs | 2 +- ic0.txt | 68 ++++++++ library/ic-ledger-types/CHANGELOG.md | 5 + library/ic-ledger-types/Cargo.toml | 2 +- src/candid-extractor/Cargo.toml | 25 +++ src/candid-extractor/LICENSE | 1 + src/candid-extractor/README.md | 30 ++++ src/candid-extractor/ic0.txt | 1 + src/candid-extractor/ic_mock.wat | 53 ++++++ src/candid-extractor/src/main.rs | 50 ++++++ .../util/generate_mock_wat.rs | 157 ++++++++++++++++++ src/ic-cdk-bindgen/CHANGELOG.md | 4 + src/ic-cdk-bindgen/Cargo.toml | 2 +- src/ic-cdk-macros/CHANGELOG.md | 6 + src/ic-cdk-macros/Cargo.toml | 8 +- src/ic-cdk-macros/src/export.rs | 2 - src/ic-cdk-macros/src/lib.rs | 19 +-- src/ic-cdk-timers/CHANGELOG.md | 6 + src/ic-cdk-timers/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 9 + src/ic-cdk/Cargo.toml | 8 +- src/ic-cdk/src/api/mod.rs | 4 - src/ic-cdk/src/api/wasi.rs | 33 ---- src/ic0/Cargo.toml | 8 +- src/ic0/README.md | 13 +- src/ic0/ic0.txt | 69 +------- src/ic0/src/ic0.rs | 6 +- src/ic0/util/ic0build.rs | 6 +- 35 files changed, 502 insertions(+), 187 deletions(-) create mode 100644 ic0.txt create mode 100644 src/candid-extractor/Cargo.toml create mode 120000 src/candid-extractor/LICENSE create mode 100644 src/candid-extractor/README.md create mode 120000 src/candid-extractor/ic0.txt create mode 100644 src/candid-extractor/ic_mock.wat create mode 100644 src/candid-extractor/src/main.rs create mode 100644 src/candid-extractor/util/generate_mock_wat.rs delete mode 100644 src/ic-cdk/src/api/wasi.rs mode change 100644 => 120000 src/ic0/ic0.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 135c18e27..4f46b27cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,8 +40,8 @@ jobs: target: wasm32-unknown-unknown - name: Run builds run: | - cargo build --workspace --exclude ic-cdk-e2e-tests --target wasm32-unknown-unknown - cargo build --workspace --exclude ic-cdk-e2e-tests --target wasm32-unknown-unknown --release + cargo build --workspace --exclude ic-cdk-e2e-tests --exclude candid-extractor --target wasm32-unknown-unknown + cargo build --workspace --exclude ic-cdk-e2e-tests --exclude candid-extractor --target wasm32-unknown-unknown --release cargo build --example=work test: diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 14b64a276..f2e21bc57 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -13,11 +13,45 @@ concurrency: env: rust-version: 1.65.0 dfx-version: 0.14.1 - wasmtime-version: 10.0.1 + ic-wasm-version: 0.4.0 jobs: + build-candid-extractor: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-candid-extractor-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + restore-keys: | + ${{ runner.os }}-candid-extractor- + ${{ runner.os }}- + + - name: Install Rust + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ env.rust-version }} + + - name: Build candid-extractor + run: cargo build -p candid-extractor --release + + - uses: actions/upload-artifact@v3 + with: + name: candid-extractor + path: target/release/candid-extractor + test: runs-on: ubuntu-latest + needs: build-candid-extractor strategy: fail-fast: false matrix: @@ -52,15 +86,19 @@ jobs: - name: Install ic-wasm # might already in cache run: | - if ! [ -x "$(command -v ic-wasm)" ]; then - cargo install ic-wasm - fi + wget https://github.com/dfinity/ic-wasm/releases/download/${{env.ic-wasm-version }}/ic-wasm-linux64 + chmod 755 ic-wasm-linux64 + mv ic-wasm-linux64 /usr/local/bin/ic-wasm + + - name: Download candid-extractor + uses: actions/download-artifact@v3 + with: + name: candid-extractor - - name: Install wasmtime + - name: Install candid-extractor run: | - wget https://github.com/bytecodealliance/wasmtime/releases/download/v${{env.wasmtime-version}}/wasmtime-v${{env.wasmtime-version}}-x86_64-linux.tar.xz - tar xf wasmtime-v${{env.wasmtime-version}}-x86_64-linux.tar.xz - mv wasmtime-v${{env.wasmtime-version}}-x86_64-linux/wasmtime /usr/local/bin/ + chmod 755 candid-extractor + mv candid-extractor /usr/local/bin/candid-extractor - name: Install DFX run: | diff --git a/Cargo.toml b/Cargo.toml index 3739a4709..51a81f0ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "src/ic-cdk-bindgen", "src/ic-cdk-macros", "src/ic-cdk-timers", + "src/candid-extractor", "library/ic-certified-map", "library/ic-ledger-types", "e2e-tests", @@ -30,11 +31,11 @@ lto = true opt-level = 'z' [workspace.dependencies] -ic0 = { path = "src/ic0", version = "0.18.11" } -ic-cdk = { path = "src/ic-cdk", version = "0.10" } -ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.4.0" } +ic0 = { path = "src/ic0", version = "0.18.12" } +ic-cdk = { path = "src/ic-cdk", version = "0.11" } +ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.5.0" } -candid = "0.9" +candid = "0.9.6" futures = "0.3" hex = "0.4" quote = "1" diff --git a/README.md b/README.md index 606eda182..4a5562967 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ Generate Rust bindings from Candid to make inter-canister calls. Annotate functions with attribute macros to make them exposed public interfaces. - [`ic-cdk-timers`](src/ic-cdk-timers): The library implements multiple and periodic timers. +- [`candid-extractor`](src/candid-extractor/): +A CLI tool to extract candid definition from canister WASM. - [`ic-certified-map`](library/ic-certified-map): An implementation of map which support *certified queries*. - [`ic-ledger-types`](library/ic-ledger-types): @@ -51,7 +53,7 @@ crate-type = ["cdylib"] [dependencies] candid = "0.9" # this version is required if you want to define Candid data types -ic-cdk = "0.10" +ic-cdk = "0.11" ``` Then in your rust source code: diff --git a/examples/build.sh b/examples/build.sh index 31eeada52..66786d692 100755 --- a/examples/build.sh +++ b/examples/build.sh @@ -7,19 +7,13 @@ root="$(dirname "$0")/.." example_root="$(dirname "$0")/$name" did_file="/tmp/a.did" -# This script generates the did file, build the project (passed as $1) and then run the ic-wasm to shrink and attach metadata. -cargo build --manifest-path="$example_root/Cargo.toml" \ - --target wasm32-unknown-unknown \ - --release \ - --package "$package" --features "ic-cdk/wasi" - -wasmtime "$example_root/target/wasm32-unknown-unknown/release/$package.wasm" > $did_file - cargo build --manifest-path="$example_root/Cargo.toml" \ --target wasm32-unknown-unknown \ --release \ --package "$package" +candid-extractor "$example_root/target/wasm32-unknown-unknown/release/$package.wasm" 2>/dev/null > $did_file || true + ic-wasm "$example_root/target/wasm32-unknown-unknown/release/$package.wasm" \ -o "$example_root/target/wasm32-unknown-unknown/release/$package.wasm" \ metadata candid:service -v public -f $did_file @@ -27,4 +21,3 @@ ic-wasm "$example_root/target/wasm32-unknown-unknown/release/$package.wasm" \ ic-wasm "$example_root/target/wasm32-unknown-unknown/release/$package.wasm" \ -o "$example_root/target/wasm32-unknown-unknown/release/$package-opt.wasm" \ shrink - diff --git a/examples/counter/src/inter2_rs/build.rs b/examples/counter/src/inter2_rs/build.rs index 948b69034..250d93a24 100644 --- a/examples/counter/src/inter2_rs/build.rs +++ b/examples/counter/src/inter2_rs/build.rs @@ -4,8 +4,8 @@ use std::path::PathBuf; fn main() { let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").expect("Cannot find manifest dir")); - let counter = Config::new("inter_mo"); + let inter_mo = Config::new("inter_mo"); let mut builder = Builder::new(); - builder.add(counter); + builder.add(inter_mo); builder.build(Some(manifest_dir.join("declarations"))); } diff --git a/examples/profile/src/profile_inter_rs/build.rs b/examples/profile/src/profile_inter_rs/build.rs index c76667add..520412881 100644 --- a/examples/profile/src/profile_inter_rs/build.rs +++ b/examples/profile/src/profile_inter_rs/build.rs @@ -4,8 +4,8 @@ use std::path::PathBuf; fn main() { let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").expect("Cannot find manifest dir")); - let counter = Config::new("profile_rs"); + let profile_rs = Config::new("profile_rs"); let mut builder = Builder::new(); - builder.add(counter); + builder.add(profile_rs); builder.build(Some(manifest_dir.join("declarations"))); } diff --git a/examples/profile/src/profile_inter_rs/lib.rs b/examples/profile/src/profile_inter_rs/lib.rs index 348b9ee2a..04d748b66 100644 --- a/examples/profile/src/profile_inter_rs/lib.rs +++ b/examples/profile/src/profile_inter_rs/lib.rs @@ -5,7 +5,7 @@ use declarations::profile_rs::{profile_rs, Profile}; #[update(name = "getSelf")] async fn get_self() -> Profile { - profile_rs.getSelf().await.unwrap().0 + profile_rs.get_self().await.unwrap().0 } #[update] diff --git a/ic0.txt b/ic0.txt new file mode 100644 index 000000000..eaff356c6 --- /dev/null +++ b/ic0.txt @@ -0,0 +1,68 @@ +ic0.msg_arg_data_size : () -> i32; // I U Q CQ Ry CRy F +ic0.msg_arg_data_copy : (dst : i32, offset : i32, size : i32) -> (); // I U Q CQ Ry CRy F +ic0.msg_caller_size : () -> i32; // * +ic0.msg_caller_copy : (dst : i32, offset: i32, size : i32) -> (); // * +ic0.msg_reject_code : () -> i32; // Ry Rt CRy CRt +ic0.msg_reject_msg_size : () -> i32; // Rt CRt +ic0.msg_reject_msg_copy : (dst : i32, offset : i32, size : i32) -> (); // Rt CRt + +ic0.msg_reply_data_append : (src : i32, size : i32) -> (); // U Q CQ Ry Rt CRy CRt +ic0.msg_reply : () -> (); // U Q CQ Ry Rt CRy CRt +ic0.msg_reject : (src : i32, size : i32) -> (); // U Q CQ Ry Rt CRy CRt + +ic0.msg_cycles_available : () -> i64; // U Rt Ry +ic0.msg_cycles_available128 : (dst : i32) -> (); // U Rt Ry +ic0.msg_cycles_refunded : () -> i64; // Rt Ry +ic0.msg_cycles_refunded128 : (dst : i32) -> (); // Rt Ry +ic0.msg_cycles_accept : (max_amount : i64) -> (amount : i64); // U Rt Ry +ic0.msg_cycles_accept128 : (max_amount_high : i64, max_amount_low: i64, dst : i32) + -> (); // U Rt Ry + +ic0.canister_self_size : () -> i32; // * +ic0.canister_self_copy : (dst : i32, offset : i32, size : i32) -> (); // * +ic0.canister_cycle_balance : () -> i64; // * +ic0.canister_cycle_balance128 : (dst : i32) -> (); // * +ic0.canister_status : () -> i32; // * +ic0.canister_version : () -> i64; // * + +ic0.msg_method_name_size : () -> i32; // F +ic0.msg_method_name_copy : (dst : i32, offset : i32, size : i32) -> (); // F +ic0.accept_message : () -> (); // F + +ic0.call_new : // U CQ Ry Rt CRy CRt T + ( callee_src : i32, + callee_size : i32, + name_src : i32, + name_size : i32, + reply_fun : i32, + reply_env : i32, + reject_fun : i32, + reject_env : i32 + ) -> (); +ic0.call_on_cleanup : (fun : i32, env : i32) -> (); // U CQ Ry Rt CRy CRt T +ic0.call_data_append : (src : i32, size : i32) -> (); // U CQ Ry Rt CRy CRt T +ic0.call_cycles_add : (amount : i64) -> (); // U Ry Rt T +ic0.call_cycles_add128 : (amount_high : i64, amount_low: i64) -> (); // U Ry Rt T +ic0.call_perform : () -> ( err_code : i32 ); // U CQ Ry Rt CRy CRt T + +ic0.stable_size : () -> (page_count : i32); // * s +ic0.stable_grow : (new_pages : i32) -> (old_page_count : i32); // * s +ic0.stable_write : (offset : i32, src : i32, size : i32) -> (); // * s +ic0.stable_read : (dst : i32, offset : i32, size : i32) -> (); // * s +ic0.stable64_size : () -> (page_count : i64); // * s +ic0.stable64_grow : (new_pages : i64) -> (old_page_count : i64); // * s +ic0.stable64_write : (offset : i64, src : i64, size : i64) -> (); // * s +ic0.stable64_read : (dst : i64, offset : i64, size : i64) -> (); // * s + +ic0.certified_data_set : (src: i32, size: i32) -> (); // I G U Ry Rt T +ic0.data_certificate_present : () -> i32; // * +ic0.data_certificate_size : () -> i32; // * +ic0.data_certificate_copy : (dst: i32, offset: i32, size: i32) -> (); // * + +ic0.time : () -> (timestamp : i64); // * +ic0.global_timer_set : (timestamp : i64) -> i64; // I G U Ry Rt C T +ic0.performance_counter : (counter_type : i32) -> (counter : i64); // * s +ic0.is_controller: (src: i32, size: i32) -> ( result: i32); // * s + +ic0.debug_print : (src : i32, size : i32) -> (); // * s +ic0.trap : (src : i32, size : i32) -> (); // * s \ No newline at end of file diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index d4ae8d089..f03a3b3bb 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.8.0] - 2023-09-18 + +### Changed +- Upgrade `ic-cdk` to v0.11. + ## [0.7.0] - 2023-07-13 ### Added diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index f119798aa..74cd797f6 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.7.0" +version = "0.8.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/candid-extractor/Cargo.toml b/src/candid-extractor/Cargo.toml new file mode 100644 index 000000000..224f49036 --- /dev/null +++ b/src/candid-extractor/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "candid-extractor" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true +description = "CLI tool to extract candid definition from canister WASM." +readme = "README.md" +categories = ["development-tools"] +keywords = ["internet-computer", "wasm", "dfinity", "canister", "cdk"] +include = ["src", "Cargo.toml", "LICENSE", "README.md"] + +[dependencies] +anyhow = "1.0.72" +wasmtime = "12" + +[dev-dependencies] +quote.workspace = true +syn = { workspace = true, features = ["parsing", "full", "extra-traits"] } + +[[example]] +name = "generate_mock_wat" +path = "util/generate_mock_wat.rs" diff --git a/src/candid-extractor/LICENSE b/src/candid-extractor/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/src/candid-extractor/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/src/candid-extractor/README.md b/src/candid-extractor/README.md new file mode 100644 index 000000000..534c69126 --- /dev/null +++ b/src/candid-extractor/README.md @@ -0,0 +1,30 @@ +# candid-extractor + +A CLI tool to extract candid definition from canister WASM. + +## Installation + +``` +cargo install candid-extractor +``` + +## Usage + +``` +candid-extractor path/to/canister.wasm +``` + +## Update ic_mock.wat + +`candid-extractor` requires a mock WASM (`ic_mock.wat`) which provides ic0 imports. + +Such `ic_mock.wat` is directly generated from the [system API][1]. + +When interface-spec releases a new version that modify ic0 system API: + +1. replace `ic0.txt` in the root of this project; +2. execute `cargo run --example=generate_mock_wat`; + +`ic_mock.wat` should be updated. + +[1]: https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-imports diff --git a/src/candid-extractor/ic0.txt b/src/candid-extractor/ic0.txt new file mode 120000 index 000000000..ee3cab32a --- /dev/null +++ b/src/candid-extractor/ic0.txt @@ -0,0 +1 @@ +../../ic0.txt \ No newline at end of file diff --git a/src/candid-extractor/ic_mock.wat b/src/candid-extractor/ic_mock.wat new file mode 100644 index 000000000..da53f6bdc --- /dev/null +++ b/src/candid-extractor/ic_mock.wat @@ -0,0 +1,53 @@ +(module + ;; This file is generated from ic0.txt. + ;; Don't manually modify it. + (func (export "msg_arg_data_size") (result i32) i32.const 0) + (func (export "msg_arg_data_copy") (param i32 i32 i32) ) + (func (export "msg_caller_size") (result i32) i32.const 0) + (func (export "msg_caller_copy") (param i32 i32 i32) ) + (func (export "msg_reject_code") (result i32) i32.const 0) + (func (export "msg_reject_msg_size") (result i32) i32.const 0) + (func (export "msg_reject_msg_copy") (param i32 i32 i32) ) + (func (export "msg_reply_data_append") (param i32 i32) ) + (func (export "msg_reply") ) + (func (export "msg_reject") (param i32 i32) ) + (func (export "msg_cycles_available") (result i64) i64.const 0) + (func (export "msg_cycles_available128") (param i32) ) + (func (export "msg_cycles_refunded") (result i64) i64.const 0) + (func (export "msg_cycles_refunded128") (param i32) ) + (func (export "msg_cycles_accept") (param i64) (result i64) i64.const 0) + (func (export "msg_cycles_accept128") (param i64 i64 i32) ) + (func (export "canister_self_size") (result i32) i32.const 0) + (func (export "canister_self_copy") (param i32 i32 i32) ) + (func (export "canister_cycle_balance") (result i64) i64.const 0) + (func (export "canister_cycle_balance128") (param i32) ) + (func (export "canister_status") (result i32) i32.const 0) + (func (export "canister_version") (result i64) i64.const 0) + (func (export "msg_method_name_size") (result i32) i32.const 0) + (func (export "msg_method_name_copy") (param i32 i32 i32) ) + (func (export "accept_message") ) + (func (export "call_new") (param i32 i32 i32 i32 i32 i32 i32 i32) ) + (func (export "call_on_cleanup") (param i32 i32) ) + (func (export "call_data_append") (param i32 i32) ) + (func (export "call_cycles_add") (param i64) ) + (func (export "call_cycles_add128") (param i64 i64) ) + (func (export "call_perform") (result i32) i32.const 0) + (func (export "stable_size") (result i32) i32.const 0) + (func (export "stable_grow") (param i32) (result i32) i32.const 0) + (func (export "stable_write") (param i32 i32 i32) ) + (func (export "stable_read") (param i32 i32 i32) ) + (func (export "stable64_size") (result i64) i64.const 0) + (func (export "stable64_grow") (param i64) (result i64) i64.const 0) + (func (export "stable64_write") (param i64 i64 i64) ) + (func (export "stable64_read") (param i64 i64 i64) ) + (func (export "certified_data_set") (param i32 i32) ) + (func (export "data_certificate_present") (result i32) i32.const 0) + (func (export "data_certificate_size") (result i32) i32.const 0) + (func (export "data_certificate_copy") (param i32 i32 i32) ) + (func (export "time") (result i64) i64.const 0) + (func (export "global_timer_set") (param i64) (result i64) i64.const 0) + (func (export "performance_counter") (param i32) (result i64) i64.const 0) + (func (export "is_controller") (param i32 i32) (result i32) i32.const 0) + (func (export "debug_print") (param i32 i32) ) + (func (export "trap") (param i32 i32) ) +) diff --git a/src/candid-extractor/src/main.rs b/src/candid-extractor/src/main.rs new file mode 100644 index 000000000..b3478acee --- /dev/null +++ b/src/candid-extractor/src/main.rs @@ -0,0 +1,50 @@ +use std::path::Path; + +use anyhow::{bail, Result}; +use wasmtime::*; + +static IC0: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/ic_mock.wat")); + +fn generate_candid

(wasm_path: P) -> Result +where + P: AsRef, +{ + let mut store: Store<()> = Store::<()>::default(); + + let mut linker = Linker::new(store.engine()); + let ic0_module = Module::new(store.engine(), IC0)?; + let ic0 = linker.instantiate(&mut store, &ic0_module)?; + linker.instance(&mut store, "ic0", ic0)?; + + let module = Module::from_file(store.engine(), wasm_path)?; + let canister = linker.instantiate(&mut store, &module)?; + + let get_candid_pointer = + canister.get_typed_func::<(), i32>(&mut store, "get_candid_pointer")?; + let candid_pointer = get_candid_pointer.call(&mut store, ())?; + + let memory = canister + .get_memory(&mut store, "memory") + .ok_or(anyhow::format_err!("failed to find `memory` export"))?; + let memory_buffer = memory.data(&store); + + let mut i = candid_pointer as usize; + let mut str_vec = vec![]; + while memory_buffer[i] != 0 { + str_vec.push(memory_buffer[i]); + i += 1; + } + let s = String::from_utf8(str_vec)?; + Ok(s) +} + +fn main() -> Result<()> { + let args: Vec<_> = std::env::args().collect(); + if args.len() != 2 { + // The first arg will the name of current binary. + bail!("Expecting one argument: path to the canister WASM file"); + } + let c = generate_candid(args.last().unwrap())?; + println!("{c}"); + Ok(()) +} diff --git a/src/candid-extractor/util/generate_mock_wat.rs b/src/candid-extractor/util/generate_mock_wat.rs new file mode 100644 index 000000000..3f2cd54b1 --- /dev/null +++ b/src/candid-extractor/util/generate_mock_wat.rs @@ -0,0 +1,157 @@ +use quote::{quote, ToTokens}; +use syn::parse::{Parse, ParseStream, Result}; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::token::Comma; +use syn::{parenthesized, Error}; +use syn::{FnArg, Ident, Token, TypePath}; + +use std::fs; +use std::io::Write; +use std::path::PathBuf; + +#[derive(Clone, Debug)] +pub struct SystemAPI { + pub name: Ident, + pub arg_types: Vec, + pub output: Option, +} + +impl Parse for SystemAPI { + fn parse(input: ParseStream) -> Result { + let ic0_token: Ident = input.parse()?; + if ic0_token != "ic0" { + return Err(Error::new(ic0_token.span(), "expected `ic0`")); + } + input.parse::()?; + let name: Ident = input.parse()?; + input.parse::()?; + + // args + let content; + parenthesized!(content in input); + let args = Punctuated::::parse_terminated(&content)?; + let args: Vec = args.iter().cloned().collect(); + let mut arg_types = vec![]; + for arg in &args { + match arg { + FnArg::Receiver(r) => return Err(Error::new(r.span(), "receiver not expected")), + FnArg::Typed(pat_type) => match &*pat_type.ty { + syn::Type::Path(ty) => { + type_supported(ty)?; + arg_types.push(ty.clone()); + } + _ => return Err(Error::new(pat_type.span(), "expected type as i32")), + }, + } + } + + input.parse::]>()?; + + // output + let output = if input.peek(syn::token::Paren) { + let content; + parenthesized!(content in input); + if content.is_empty() { + None + } else { + let _output_name: Ident = content.parse()?; + content.parse::()?; + let ty: TypePath = content.parse()?; + if !content.is_empty() { + return Err(Error::new(ty.span(), "expected only one return type")); + } + type_supported(&ty)?; + Some(ty) + } + } else { + let ty: TypePath = input.parse()?; + type_supported(&ty)?; + Some(ty) + }; + + input.parse::()?; + + Ok(Self { + name, + arg_types, + output, + }) + } +} + +fn type_supported(ty: &TypePath) -> Result<()> { + let supported = match ty.path.get_ident() { + Some(i) => i == "i32" || i == "i64", + None => false, + }; + match supported { + true => Ok(()), + false => Err(Error::new(ty.span(), "expected i32 or i64")), + } +} + +#[derive(Clone, Debug)] +pub struct IC0 { + pub apis: Vec, +} + +impl Parse for IC0 { + fn parse(input: ParseStream) -> Result { + Ok(Self { + apis: { + let mut apis = vec![]; + while !input.is_empty() { + apis.push(input.parse()?); + } + apis + }, + }) + } +} + +fn main() { + let s = include_str!("../ic0.txt"); + let ic0: IC0 = syn::parse_str(s).unwrap(); + + let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + d.push("ic_mock.wat"); + + let mut f = fs::File::create(d).unwrap(); + + writeln!( + f, + r#"(module + ;; This file is generated from ic0.txt. + ;; Don't manually modify it."#, + ) + .unwrap(); + + for api in &ic0.apis { + let fn_name = &api.name; + let arg_types = &api.arg_types; + + let params = if arg_types.is_empty() { + quote! {} + } else { + quote! { + (param #(#arg_types)*) + } + }; + + let result = if let Some(output) = &api.output { + format!( + "(result {0}) {0}.const 0", + output.to_token_stream().to_string() + ) + } else { + "".to_string() + }; + + let r = format!(" (func (export \"{fn_name}\") {params} {result})"); + + writeln!(f, "{}", r).unwrap(); + } + + writeln!(f, ")").unwrap(); +} diff --git a/src/ic-cdk-bindgen/CHANGELOG.md b/src/ic-cdk-bindgen/CHANGELOG.md index a097f8970..c600ccc06 100644 --- a/src/ic-cdk-bindgen/CHANGELOG.md +++ b/src/ic-cdk-bindgen/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.1.1] - 2023-09-18 + +- Update `candid` dependency to 0.9.6 which change the Rust bindings. + ## [0.1.0] - 2023-07-13 - First release. diff --git a/src/ic-cdk-bindgen/Cargo.toml b/src/ic-cdk-bindgen/Cargo.toml index aceb0cbed..76e94a59e 100644 --- a/src/ic-cdk-bindgen/Cargo.toml +++ b/src/ic-cdk-bindgen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-bindgen" -version = "0.1.0" +version = "0.1.1" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index 79a292309..2d9f47ec7 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.8.0] - 2023-09-18 + +### Changed + +- Remove `export_candid` feature. (#424) + ### Fixed - Export composite_query to Candid. (#419) diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index ffae31ae2..8e85ee76f 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.7.1" # no need to sync with ic-cdk +version = "0.8.0" # no need to sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true @@ -33,9 +33,3 @@ syn = { workspace = true, features = ["fold", "full"] } [dev-dependencies] trybuild = "1.0" ic-cdk.workspace = true - -[features] -# This feature is not additive as normal crate features. -# Enable it may cause other dependent projects malfunctioning. -# It is only to be used by `ic-cdk`. -export_candid = [] diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index 7ad6c645d..38c432d7b 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -198,7 +198,6 @@ fn dfn_macro( quote! {} }; - #[cfg(feature = "export_candid")] let candid_method_attr = match method { MethodType::Query if attrs.composite => { quote! { #[::candid::candid_method(composite_query, rename = #function_name)] } @@ -211,7 +210,6 @@ fn dfn_macro( _ => quote! {}, }; - #[cfg(feature = "export_candid")] let item = quote! { #candid_method_attr #item diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index 63b2bad5a..68d531e82 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -71,13 +71,10 @@ where result.map_or_else(|e| e.to_compile_error().into(), Into::into) } -/// Create a WASI start function which print the Candid interface of the canister. -/// -/// Requiring "wasi" feature enabled. Or the function will have empty body. +/// Create a `get_candid_pointer` method so that `dfx` can execute it to extract candid definition. /// /// Call this macro only if you want the Candid export behavior. /// Only call it once at the end of canister code outside query/update definition. -#[cfg(feature = "export_candid")] #[proc_macro] pub fn export_candid(input: TokenStream) -> TokenStream { let input: proc_macro2::TokenStream = input.into(); @@ -85,22 +82,14 @@ pub fn export_candid(input: TokenStream) -> TokenStream { ::candid::export_service!(#input); #[no_mangle] - pub unsafe extern "C" fn _start() { - let result = __export_service(); - let ret = unsafe { ::ic_cdk::api::wasi::print(&result) }; - ::ic_cdk::api::wasi::proc_exit(ret as u32); + pub fn get_candid_pointer() -> *mut std::os::raw::c_char { + let c_string = std::ffi::CString::new(__export_service()).unwrap(); + c_string.into_raw() } } .into() } -#[doc(hidden)] -#[cfg(not(feature = "export_candid"))] -#[proc_macro] -pub fn export_candid(_: TokenStream) -> TokenStream { - quote::quote! {}.into() -} - /// Register a query call entry point. /// /// This attribute macro will export a function with name `canister_query ` diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index 341af576b..09ddcdbad 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.5.0] - 2023-09-18 + +### Changed + +- Upgrade `ic-cdk` to v0.11. + ## [0.4.0] - 2023-07-13 ### Changed diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index c4934f458..fcb0f6266 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.4.0" +version = "0.5.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index f83fe9de5..7b93ba3f0 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.11.0] - 2023-09-18 + +### Changed + +- Candid Export workflow is changed. (#424) + * No need to compile for WASI separately. + * Canisters should still invoke `ic_cdk::export_candid!()` to export candid. + * Then use [`candid-extractor`](../candid-extractor/) to extract candid from the canister WASM. + ## [0.10.0] - 2023-07-13 ### Changed diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 0682552ee..c0062919e 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.10.0" +version = "0.11.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -22,7 +22,7 @@ include = ["src", "Cargo.toml", "LICENSE", "README.md"] [dependencies] candid.workspace = true ic0.workspace = true -ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.7.0" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.8.0" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true } @@ -32,10 +32,6 @@ rstest = "0.12.0" [features] transform-closure = ["dep:slotmap"] -# The feature below is not additive as normal crate features. -# Enable it may cause other dependent projects malfunctioning. -# It is only to be used by canister IDL generation. -wasi = ["ic0/wasi", "ic-cdk-macros/export_candid"] [package.metadata.docs.rs] features = ["transform-closure"] diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index 947eaa099..1ce2f9daa 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -6,10 +6,6 @@ pub mod call; pub mod management_canister; pub mod stable; -#[cfg(feature = "wasi")] -#[doc(hidden)] -pub mod wasi; - /// Prints the given message. pub fn print>(s: S) { let s = s.as_ref(); diff --git a/src/ic-cdk/src/api/wasi.rs b/src/ic-cdk/src/api/wasi.rs deleted file mode 100644 index 2ac01c837..000000000 --- a/src/ic-cdk/src/api/wasi.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! This module is only for internal usage of [crate::export_candid] macro. -//! -//! A simple WASI binding. It's only enabled by the "wasi" feature to allow building -//! the canister as a standalone WASI binary that can output its Candid interface in wasmtime. -//! -//! NEVER use them in Canister code. - -type Fd = u32; -type Size = usize; -pub type Errno = i32; -pub type Rval = u32; - -#[derive(Debug)] -#[repr(C)] -pub struct Ciovec { - buf: *const u8, - buf_len: Size, -} - -#[link(wasm_import_module = "wasi_snapshot_preview1")] -extern "C" { - pub fn fd_write(fd: Fd, iovs_ptr: *const Ciovec, iovs_len: Size, nwritten: *mut Size) -> Errno; - pub fn proc_exit(rval: Rval); -} -pub unsafe fn print(text: &str) -> Errno { - let ciovec = Ciovec { - buf: text.as_ptr(), - buf_len: text.len(), - }; - let ciovecs = [ciovec]; - let mut nwritten = 0; - unsafe { fd_write(1, ciovecs.as_ptr(), ciovecs.len(), &mut nwritten) } -} diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml index 6b6819d23..4eb6953bb 100644 --- a/src/ic0/Cargo.toml +++ b/src/ic0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic0" -version = "0.18.11" +version = "0.18.12" authors.workspace = true edition.workspace = true license.workspace = true @@ -16,12 +16,6 @@ include = ["src", "Cargo.toml", "LICENSE", "README.md"] quote.workspace = true syn = { workspace = true, features = ["parsing", "full", "extra-traits"] } -[features] -# This feature is not additive as normal crate features. -# Enable it may cause other dependent projects malfunctioning. -# It is only to be used by `ic-cdk`. -wasi = [] - # This is not a real example but a utility for auto-generating ic0.rs [[example]] name = "ic0build" diff --git a/src/ic0/README.md b/src/ic0/README.md index 786868d36..bbb6ea1a4 100644 --- a/src/ic0/README.md +++ b/src/ic0/README.md @@ -4,20 +4,19 @@ Internet Computer System API binding. ## What -`ic0` is simply an unsafe Rust translation of Internet Computer System API as described in the [Specification](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-imports). +`ic0` is simply an unsafe Rust translation of the System API as described in the [IC interface specification][1]. ## Update and Version Strategy -`ic0` keeps in step with [interface-spec][1]. Particularly, `ic0` is directly generated from [ic0.txt][2] in that repo. +`ic0` keeps in step with the IC interface specification. Particularly, `ic0` is directly generated from [system API][1] in that repo. -When interface-spec releases a new version that modify [ic0.txt][2]: +When interface-spec releases a new version that modify [system API][1]: -1. replace `ic0.txt` in the root of this crate; +1. replace `ic0.txt` in the root of this project; 2. execute `cargo run --example=ic0build`; `src/ic0.rs` should be updated. -The version of `ic0` crate will also bump to the same version as [interface-spec][1]. +The version of `ic0` crate will also bump to the same version as the IC interface specification. -[1]: https://github.com/dfinity/interface-spec -[2]: https://github.com/dfinity/interface-spec/blob/master/spec/ic0.txt +[1]: https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-imports diff --git a/src/ic0/ic0.txt b/src/ic0/ic0.txt deleted file mode 100644 index 9c4a5c3a4..000000000 --- a/src/ic0/ic0.txt +++ /dev/null @@ -1,68 +0,0 @@ -ic0.msg_arg_data_size : () -> i32; // I U Q Ry F -ic0.msg_arg_data_copy : (dst : i32, offset : i32, size : i32) -> (); // I U Q Ry F -ic0.msg_caller_size : () -> i32; // I G U Q F -ic0.msg_caller_copy : (dst : i32, offset: i32, size : i32) -> (); // I G U Q F -ic0.msg_reject_code : () -> i32; // Ry Rt -ic0.msg_reject_msg_size : () -> i32; // Rt -ic0.msg_reject_msg_copy : (dst : i32, offset : i32, size : i32) -> (); // Rt - -ic0.msg_reply_data_append : (src : i32, size : i32) -> (); // U Q Ry Rt -ic0.msg_reply : () -> (); // U Q Ry Rt -ic0.msg_reject : (src : i32, size : i32) -> (); // U Q Ry Rt - -ic0.msg_cycles_available : () -> i64; // U Rt Ry -ic0.msg_cycles_available128 : (dst : i32) -> (); // U Rt Ry -ic0.msg_cycles_refunded : () -> i64; // Rt Ry -ic0.msg_cycles_refunded128 : (dst : i32) -> (); // Rt Ry -ic0.msg_cycles_accept : (max_amount : i64) -> (amount : i64); // U Rt Ry -ic0.msg_cycles_accept128 : (max_amount_high : i64, max_amount_low: i64, dst : i32) - -> (); // U Rt Ry - -ic0.canister_self_size : () -> i32; // * -ic0.canister_self_copy : (dst : i32, offset : i32, size : i32) -> (); // * -ic0.canister_cycle_balance : () -> i64; // * -ic0.canister_cycle_balance128 : (dst : i32) -> (); // * -ic0.canister_status : () -> i32; // * -ic0.canister_version : () -> i64; // * - -ic0.msg_method_name_size : () -> i32; // F -ic0.msg_method_name_copy : (dst : i32, offset : i32, size : i32) -> (); // F -ic0.accept_message : () -> (); // F - -ic0.call_new : // U Ry Rt T - ( callee_src : i32, - callee_size : i32, - name_src : i32, - name_size : i32, - reply_fun : i32, - reply_env : i32, - reject_fun : i32, - reject_env : i32 - ) -> (); -ic0.call_on_cleanup : (fun : i32, env : i32) -> (); // U Ry Rt T -ic0.call_data_append : (src : i32, size : i32) -> (); // U Ry Rt T -ic0.call_cycles_add : (amount : i64) -> (); // U Ry Rt T -ic0.call_cycles_add128 : (amount_high : i64, amount_low: i64) -> (); // U Ry Rt T -ic0.call_perform : () -> ( err_code : i32 ); // U Ry Rt T - -ic0.stable_size : () -> (page_count : i32); // * s -ic0.stable_grow : (new_pages : i32) -> (old_page_count : i32); // * s -ic0.stable_write : (offset : i32, src : i32, size : i32) -> (); // * s -ic0.stable_read : (dst : i32, offset : i32, size : i32) -> (); // * s -ic0.stable64_size : () -> (page_count : i64); // * s -ic0.stable64_grow : (new_pages : i64) -> (old_page_count : i64); // * s -ic0.stable64_write : (offset : i64, src : i64, size : i64) -> (); // * s -ic0.stable64_read : (dst : i64, offset : i64, size : i64) -> (); // * s - -ic0.certified_data_set : (src: i32, size: i32) -> (); // I G U Ry Rt T -ic0.data_certificate_present : () -> i32; // * -ic0.data_certificate_size : () -> i32; // * -ic0.data_certificate_copy : (dst: i32, offset: i32, size: i32) -> (); // * - -ic0.time : () -> (timestamp : i64); // * -ic0.global_timer_set : (timestamp : i64) -> i64; // I G U Ry Rt C T -ic0.performance_counter : (counter_type : i32) -> (counter : i64); // * s -ic0.is_controller: (src: i32, size: i32) -> ( result: i32); // * s - -ic0.debug_print : (src : i32, size : i32) -> (); // * s -ic0.trap : (src : i32, size : i32) -> (); // * s \ No newline at end of file diff --git a/src/ic0/ic0.txt b/src/ic0/ic0.txt new file mode 120000 index 000000000..ee3cab32a --- /dev/null +++ b/src/ic0/ic0.txt @@ -0,0 +1 @@ +../../ic0.txt \ No newline at end of file diff --git a/src/ic0/src/ic0.rs b/src/ic0/src/ic0.rs index 371f5a345..f5c2ba03c 100644 --- a/src/ic0/src/ic0.rs +++ b/src/ic0/src/ic0.rs @@ -1,6 +1,6 @@ // This file is generated from ic0.txt. // Don't manually modify it. -#[cfg(all(target_arch = "wasm32", not(feature = "wasi")))] +#[cfg(target_arch = "wasm32")] #[link(wasm_import_module = "ic0")] extern "C" { pub fn msg_arg_data_size() -> i32; @@ -63,7 +63,7 @@ extern "C" { pub fn trap(src: i32, size: i32); } -#[cfg(not(all(target_arch = "wasm32", not(feature = "wasi"))))] +#[cfg(not(target_arch = "wasm32"))] #[allow(unused_variables)] #[allow(clippy::missing_safety_doc)] #[allow(clippy::too_many_arguments)] @@ -226,5 +226,5 @@ mod non_wasm { } } -#[cfg(not(all(target_arch = "wasm32", not(feature = "wasi"))))] +#[cfg(not(target_arch = "wasm32"))] pub use non_wasm::*; diff --git a/src/ic0/util/ic0build.rs b/src/ic0/util/ic0build.rs index d4c0100f0..2d509730a 100644 --- a/src/ic0/util/ic0build.rs +++ b/src/ic0/util/ic0build.rs @@ -118,7 +118,7 @@ fn main() { f, r#"// This file is generated from ic0.txt. // Don't manually modify it. -#[cfg(all(target_arch = "wasm32", not(feature = "wasi")))] +#[cfg(target_arch = "wasm32")] #[link(wasm_import_module = "ic0")] extern "C" {{"#, ) @@ -147,7 +147,7 @@ extern "C" {{"#, writeln!( f, r#" -#[cfg(not(all(target_arch = "wasm32", not(feature = "wasi"))))] +#[cfg(not(target_arch = "wasm32"))] #[allow(unused_variables)] #[allow(clippy::missing_safety_doc)] #[allow(clippy::too_many_arguments)] @@ -182,7 +182,7 @@ mod non_wasm{{"#, f, r#"}} -#[cfg(not(all(target_arch = "wasm32", not(feature = "wasi"))))] +#[cfg(not(target_arch = "wasm32"))] pub use non_wasm::*; "# ) From a2623bc5f06ed6cebc6e4e6a8142d4fe96ec0e20 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 19 Sep 2023 17:14:04 -0400 Subject: [PATCH 170/234] chore: CI for release candid-extractor (#427) * include wat * binstall CI * fix url * v0.1.1 * fix CI * versioned runner * include root Cargo.lock * ubuntu 22.04 --- .../workflows/release-candid-extractor.yml | 63 + .gitignore | 3 +- Cargo.lock | 2530 +++++++++++++++++ src/candid-extractor/Cargo.toml | 7 +- 4 files changed, 2600 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/release-candid-extractor.yml create mode 100644 Cargo.lock diff --git a/.github/workflows/release-candid-extractor.yml b/.github/workflows/release-candid-extractor.yml new file mode 100644 index 000000000..0438b283c --- /dev/null +++ b/.github/workflows/release-candid-extractor.yml @@ -0,0 +1,63 @@ +name: Release candid-extractor +on: + push: + tags: + - "candid-extractor-*" + +env: + rust-version: 1.65.0 + +jobs: + release: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + # The indirect dependency `zstd-safe` (introduced by `wasmtime`) needs higher version of GLIBC. + # using ubuntu-20.04 will fail to compile + - os: ubuntu-22.04 + binstall_pkg: candid-extractor-x86_64-unknown-linux-gnu.tar.gz + - os: macos-12 + binstall_pkg: candid-extractor-x86_64-apple-darwin.tar.gz + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-release-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + restore-keys: | + ${{ runner.os }}-release- + ${{ runner.os }}- + + - name: Install Rust + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ env.rust-version }} + + - name: Build + run: | + cargo build -p candid-extractor --release --locked + + - name: Bundle + run: | + cp target/release/candid-extractor . + chmod +x candid-extractor + tar -cvzf ${{ matrix.binstall_pkg }} candid-extractor + + - name: Upload release + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: ${{ matrix.binstall_pkg }} + asset_name: ${{ matrix.binstall_pkg }} + tag: ${{ github.ref }} diff --git a/.gitignore b/.gitignore index 6e4090482..1ce6e64be 100644 --- a/.gitignore +++ b/.gitignore @@ -8,9 +8,10 @@ target/ # DFX .dfx/ +# Include root Cargo.toml to build candid-extractor with `--locked` # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock +examples/*/Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000..0e3bcb38b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2530 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "arbitrary" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "async-trait" +version = "0.1.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.25", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" + +[[package]] +name = "basic-toml" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e819b667739967cd44d308b8c7b71305d8bb0729ac44a248aa08f33d01950b4" +dependencies = [ + "serde", +] + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "binread" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16598dfc8e6578e9b597d9910ba2e73618385dc9f4b1d43dd92c349d6be6418f" +dependencies = [ + "binread_derive", + "lazy_static", + "rustversion", +] + +[[package]] +name = "binread_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" +dependencies = [ + "either", + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "camino" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055" +dependencies = [ + "serde", +] + +[[package]] +name = "candid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f6eec0ae850e006ef0fe306f362884d370624094ec55a6a26de18b251774be" +dependencies = [ + "anyhow", + "binread", + "byteorder", + "candid_derive", + "codespan-reporting", + "convert_case", + "crc32fast", + "data-encoding", + "hex", + "lalrpop", + "lalrpop-util", + "leb128", + "logos", + "num-bigint", + "num-traits", + "num_enum", + "paste", + "pretty", + "serde", + "serde_bytes", + "sha2", + "stacker", + "thiserror", +] + +[[package]] +name = "candid-extractor" +version = "0.1.1" +dependencies = [ + "anyhow", + "quote", + "syn 1.0.107", + "wasmtime", +] + +[[package]] +name = "candid_derive" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "158403ea38fab5904ae47a5d67eb7047650a91681407f5ccbcbcabc4f4ffb489" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn 2.0.25", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cpp_demangle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-bforest" +version = "0.99.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a91a1ccf6fb772808742db2f51e2179f25b1ec559cbe39ea080c72ff61caf8f" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.99.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "169db1a457791bff4fd1fc585bb5cc515609647e0420a7d5c98d7700c59c2d00" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.13.2", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.99.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3486b93751ef19e6d6eef66d2c0e83ed3d2ba01da1919ed2747f2f7bd8ba3419" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.99.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86a1205ab18e7cd25dc4eca5246e56b506ced3feb8d95a8d776195e48d2cd4ef" + +[[package]] +name = "cranelift-control" +version = "0.99.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b108cae0f724ddfdec1871a0dc193a607e0c2d960f083cfefaae8ccf655eff2" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.99.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "720444006240622798665bfc6aa8178e2eed556da342fda62f659c5267c3c659" +dependencies = [ + "serde", +] + +[[package]] +name = "cranelift-frontend" +version = "0.99.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a94c4c5508b7407e125af9d5320694b7423322e59a4ac0d07919ae254347ca" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.99.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1f888d0845dcd6be4d625b91d9d8308f3d95bed5c5d4072ce38e1917faa505" + +[[package]] +name = "cranelift-native" +version = "0.99.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad5966da08f1e96a3ae63be49966a85c9b249fa465f8cf1b66469a82b1004a0" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-wasm" +version = "0.99.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8635c88b424f1d232436f683a301143b36953cd98fc6f86f7bac862dfeb6f5" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools", + "log", + "smallvec", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "data-encoding" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "escargot" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5584ba17d7ab26a8a7284f13e5bd196294dd2f2d79773cff29b9e9edef601a6" +dependencies = [ + "log", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "file-per-thread-logger" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3cc21c33af89af0930c8cae4ade5e6fdc17b5d2c97b3d2e2edb67a1cf683f3" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" + +[[package]] +name = "futures-executor" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" + +[[package]] +name = "futures-macro" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "futures-sink" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" + +[[package]] +name = "futures-task" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" + +[[package]] +name = "futures-util" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "fxprof-processed-profile" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" +dependencies = [ + "bitflags 2.3.3", + "debugid", + "fxhash", + "serde", + "serde_json", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +dependencies = [ + "fallible-iterator", + "indexmap 1.9.2", + "stable_deref_trait", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "ic-cdk" +version = "0.11.0" +dependencies = [ + "candid", + "ic-cdk-macros", + "ic0", + "rstest", + "serde", + "serde_bytes", + "slotmap", +] + +[[package]] +name = "ic-cdk-bindgen" +version = "0.1.1" +dependencies = [ + "candid", +] + +[[package]] +name = "ic-cdk-e2e-tests" +version = "0.1.0" +dependencies = [ + "candid", + "cargo_metadata", + "escargot", + "futures", + "hex", + "ic-cdk", + "ic-cdk-timers", + "ic-test-state-machine-client", + "lazy_static", + "serde_bytes", +] + +[[package]] +name = "ic-cdk-macros" +version = "0.8.0" +dependencies = [ + "candid", + "ic-cdk", + "proc-macro2", + "quote", + "serde", + "serde_tokenstream", + "syn 1.0.107", + "trybuild", +] + +[[package]] +name = "ic-cdk-timers" +version = "0.5.0" +dependencies = [ + "futures", + "ic-cdk", + "ic0", + "serde", + "serde_bytes", + "slotmap", +] + +[[package]] +name = "ic-certified-map" +version = "0.4.0" +dependencies = [ + "candid", + "hex", + "ic-cdk", + "serde", + "serde_bytes", + "serde_cbor", + "sha2", +] + +[[package]] +name = "ic-ledger-types" +version = "0.8.0" +dependencies = [ + "candid", + "crc32fast", + "hex", + "ic-cdk", + "serde", + "serde_bytes", + "sha2", +] + +[[package]] +name = "ic-test-state-machine-client" +version = "3.0.0" +source = "git+https://github.com/lwshang/test-state-machine-client?branch=lwshang/candid_0.9#1bb17d8d2d7ecb762dc9fd6621ff105d12ed5107" +dependencies = [ + "candid", + "ciborium", + "serde", + "serde_bytes", +] + +[[package]] +name = "ic0" +version = "0.18.12" +dependencies = [ + "quote", + "syn 1.0.107", +] + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", + "serde", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix 0.38.4", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "ittapi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41e0d0b7b3b53d92a7e8b80ede3400112a6b8b4c98d1f5b8b16bb787c780582c" +dependencies = [ + "anyhow", + "ittapi-sys", + "log", +] + +[[package]] +name = "ittapi-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f8763c96e54e6d6a0dccc2990d8b5e33e3313aaeae6185921a3f4c1614a77c" +dependencies = [ + "cc", +] + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "lalrpop" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools", + "lalrpop-util", + "petgraph", + "pico-args", + "regex", + "regex-syntax 0.7.4", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" +dependencies = [ + "regex", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "logos" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" +dependencies = [ + "logos-derive", +] + +[[package]] +name = "logos-codegen" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" +dependencies = [ + "beef", + "fnv", + "proc-macro2", + "quote", + "regex-syntax 0.6.29", + "syn 2.0.25", +] + +[[package]] +name = "logos-derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" +dependencies = [ + "logos-codegen", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memfd" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" +dependencies = [ + "rustix 0.37.23", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nom8" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" +dependencies = [ + "memchr", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.25", +] + +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "crc32fast", + "hashbrown 0.13.2", + "indexmap 1.9.2", + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "petgraph" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +dependencies = [ + "fixedbitset", + "indexmap 1.9.2", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "pretty" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "563c9d701c3a31dfffaaf9ce23507ba09cbe0b9125ba176d15e629b0235e9acc" +dependencies = [ + "arrayvec", + "typed-arena", + "unicode-segmentation", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "pulldown-cmark" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +dependencies = [ + "bitflags 1.3.2", + "memchr", + "unicase", +] + +[[package]] +name = "quote" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall 0.2.16", + "thiserror", +] + +[[package]] +name = "regalloc2" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b4dcbd3a2ae7fb94b5813fa0e957c6ab51bf5d0a8ee1b69e0c2d0f1e6eb8485" +dependencies = [ + "hashbrown 0.13.2", + "log", + "rustc-hash", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax 0.7.4", +] + +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.4", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + +[[package]] +name = "rstest" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d912f35156a3f99a66ee3e11ac2e0b3f34ac85a07e05263d05a7e2c8810d616f" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.107", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.37.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys", +] + +[[package]] +name = "rustix" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +dependencies = [ + "bitflags 2.3.3", + "errno", + "libc", + "linux-raw-sys 0.4.3", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.25", +] + +[[package]] +name = "serde_json" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_tokenstream" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "274f512d6748a01e67cbcde5b4307ab2c9d52a98a2b870a980ef0793a351deff" +dependencies = [ + "proc-macro2", + "serde", + "syn 1.0.107", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "winapi", +] + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.12.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.25", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" + +[[package]] +name = "toml_edit" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" +dependencies = [ + "indexmap 1.9.2", + "nom8", + "toml_datetime", +] + +[[package]] +name = "trybuild" +version = "1.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44da5a6f2164c8e14d3bbc0657d69c5966af9f5f6930d4f600b1f5c4a673413" +dependencies = [ + "basic-toml", + "glob", + "once_cell", + "serde", + "serde_derive", + "serde_json", + "termcolor", +] + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "uuid" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-encoder" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41763f20eafed1399fff1afb466496d3a959f58241436cfdc17e3f5ca954de16" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-encoder" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba64e81215916eaeb48fee292f29401d69235d62d8b8fd92a7b2844ec5ae5f7" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasmparser" +version = "0.110.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dfcdb72d96f01e6c85b6bf20102e7423bdbaad5c337301bab2bbf253d26413c" +dependencies = [ + "indexmap 2.0.0", + "semver", +] + +[[package]] +name = "wasmtime" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4e87029cc5760db9a3774aff4708596fe90c20ed2baeef97212e98b812fd0fc" +dependencies = [ + "anyhow", + "async-trait", + "bincode", + "bumpalo", + "cfg-if", + "fxprof-processed-profile", + "indexmap 2.0.0", + "libc", + "log", + "object", + "once_cell", + "paste", + "psm", + "rayon", + "serde", + "serde_json", + "target-lexicon", + "wasm-encoder 0.31.1", + "wasmparser", + "wasmtime-cache", + "wasmtime-component-macro", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-fiber", + "wasmtime-jit", + "wasmtime-runtime", + "wat", + "windows-sys", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d84f68d831200016e120f2ee79d81b50cf4c4123112914aefb168d036d445d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-cache" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31561fbbaa86d3c042696940bc9601146bf4aaec39ae725c86b5f1358d8d7023" +dependencies = [ + "anyhow", + "base64", + "bincode", + "directories-next", + "file-per-thread-logger", + "log", + "rustix 0.38.4", + "serde", + "sha2", + "toml", + "windows-sys", + "zstd", +] + +[[package]] +name = "wasmtime-component-macro" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7e07b8da23838e870c4c092027208ac546398a2ac4f5afff33a1ea1d763ec0" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn 2.0.25", + "wasmtime-component-util", + "wasmtime-wit-bindgen", + "wit-parser", +] + +[[package]] +name = "wasmtime-component-util" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f421bc59c753dcd24e39601928a0f2915adf15f40d8ba0066c4cf23f92c9a0" + +[[package]] +name = "wasmtime-cranelift" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae8ed7a4845f22be6b1ad80f33f43fa03445b03a02f2d40dca695129769cd1a" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli", + "log", + "object", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-cranelift-shared", + "wasmtime-environ", + "wasmtime-versioned-export-macros", +] + +[[package]] +name = "wasmtime-cranelift-shared" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b17099f9320a1c481634d88101258917d5065717cf22b04ed75b1a8ea062b4" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "cranelift-native", + "gimli", + "object", + "target-lexicon", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-environ" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8b9227b1001229ff125e0f76bf1d5b9dc4895e6bcfd5cc35a56f84685964ec7" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli", + "indexmap 2.0.0", + "log", + "object", + "serde", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-fiber" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc8c8410c03a79073ea06806ccde3da4854c646bd646b3b2707b99b3746c3f70" +dependencies = [ + "cc", + "cfg-if", + "rustix 0.38.4", + "wasmtime-asm-macros", + "wasmtime-versioned-export-macros", + "windows-sys", +] + +[[package]] +name = "wasmtime-jit" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cce606b392c321d7272928003543447119ef937a9c3ebfce5c4bb0bf6b0f5bac" +dependencies = [ + "addr2line", + "anyhow", + "bincode", + "cfg-if", + "cpp_demangle", + "gimli", + "ittapi", + "log", + "object", + "rustc-demangle", + "rustix 0.38.4", + "serde", + "target-lexicon", + "wasmtime-environ", + "wasmtime-jit-debug", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef27ea6c34ef888030d15560037fe7ef27a5609fbbba8e1e3e41dc4245f5bb2" +dependencies = [ + "object", + "once_cell", + "rustix 0.38.4", + "wasmtime-versioned-export-macros", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b59f94b0409221873565419168e20b5aedf18c4bd64de5c38acf8f0634efeee3" +dependencies = [ + "cfg-if", + "libc", + "windows-sys", +] + +[[package]] +name = "wasmtime-runtime" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceb587a88ae5bb6ca248455a391aff29ac63329a404b2cdea36d91267c797db4" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "indexmap 2.0.0", + "libc", + "log", + "mach", + "memfd", + "memoffset", + "paste", + "rand", + "rustix 0.38.4", + "sptr", + "wasm-encoder 0.31.1", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-fiber", + "wasmtime-jit-debug", + "wasmtime-versioned-export-macros", + "windows-sys", +] + +[[package]] +name = "wasmtime-types" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77943729d4b46141538e8d0b6168915dc5f88575ecdfea26753fd3ba8bab244a" +dependencies = [ + "cranelift-entity", + "serde", + "thiserror", + "wasmparser", +] + +[[package]] +name = "wasmtime-versioned-export-macros" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca7af9bb3ee875c4907835e607a275d10b04d15623d3aebe01afe8fbd3f85050" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.25", +] + +[[package]] +name = "wasmtime-wit-bindgen" +version = "12.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14770d0820f56ba86cdd9987aef97cc3bacbb0394633c37dbfbc61ef29603a71" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.0.0", + "wit-parser", +] + +[[package]] +name = "wast" +version = "64.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a259b226fd6910225aa7baeba82f9d9933b6d00f2ce1b49b80fa4214328237cc" +dependencies = [ + "leb128", + "memchr", + "unicode-width", + "wasm-encoder 0.32.0", +] + +[[package]] +name = "wat" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53253d920ab413fca1c7dc2161d601c79b4fdf631d0ba51dd4343bf9b556c3f6" +dependencies = [ + "wast", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "wit-parser" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "541efa2046e544de53a9da1e2f6299e63079840360c9e106f1f8275a97771318" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.0.0", + "log", + "pulldown-cmark", + "semver", + "unicode-xid", + "url", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.8+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +dependencies = [ + "cc", + "libc", + "pkg-config", +] diff --git a/src/candid-extractor/Cargo.toml b/src/candid-extractor/Cargo.toml index 224f49036..de2c44d77 100644 --- a/src/candid-extractor/Cargo.toml +++ b/src/candid-extractor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid-extractor" -version = "0.1.0" +version = "0.1.1" authors.workspace = true edition.workspace = true license.workspace = true @@ -10,7 +10,7 @@ description = "CLI tool to extract candid definition from canister WASM." readme = "README.md" categories = ["development-tools"] keywords = ["internet-computer", "wasm", "dfinity", "canister", "cdk"] -include = ["src", "Cargo.toml", "LICENSE", "README.md"] +include = ["src", "Cargo.toml", "LICENSE", "README.md", "ic_mock.wat"] [dependencies] anyhow = "1.0.72" @@ -23,3 +23,6 @@ syn = { workspace = true, features = ["parsing", "full", "extra-traits"] } [[example]] name = "generate_mock_wat" path = "util/generate_mock_wat.rs" + +[package.metadata.binstall] +pkg-url = "{ repo }/releases/download/candid-extractor-v{ version }/{ name }-{ target }{ archive-suffix }" From 0ef03532186b90e80d7450a8b8be0919736f2f45 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 21 Sep 2023 16:19:43 -0400 Subject: [PATCH 171/234] chore: unify Rust toolchain version (#429) * override toolchain in CI * comments * execute rustup override set * remove MSRV of candid-extractor * set MSRV to 1.66.0 and use it everywhere * unify cache key hashFiles * concise Cargo.toml members * candidi-extractor MSRV * fix CI test job * clippy * comment --- .github/workflows/ci.yml | 38 +++---------------- .github/workflows/examples.yml | 19 ++-------- .../workflows/release-candid-extractor.yml | 17 ++------- Cargo.lock | 3 +- Cargo.toml | 16 ++------ e2e-tests/Cargo.toml | 3 +- rust-toolchain.toml | 5 +-- src/candid-extractor/src/main.rs | 2 +- 8 files changed, 21 insertions(+), 82 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f46b27cd..b786b3e39 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,9 +10,6 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -env: - rust-version: 1.65.0 - jobs: build: name: cargo build @@ -29,15 +26,10 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - key: ${{ runner.os }}-build-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + key: ${{ runner.os }}-build-${{ hashFiles('Cargo.lock', 'rust-toolchain.toml') }} restore-keys: | ${{ runner.os }}-build- ${{ runner.os }}- - - name: Install Rust - uses: dtolnay/rust-toolchain@v1 - with: - toolchain: ${{ env.rust-version }} - target: wasm32-unknown-unknown - name: Run builds run: | cargo build --workspace --exclude ic-cdk-e2e-tests --exclude candid-extractor --target wasm32-unknown-unknown @@ -59,23 +51,16 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - key: ${{ runner.os }}-test-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + key: ${{ runner.os }}-test-${{ hashFiles('Cargo.lock', 'rust-toolchain.toml') }} restore-keys: | ${{ runner.os }}-test- ${{ runner.os }}- - - name: Install Rust - uses: dtolnay/rust-toolchain@v1 - with: - toolchain: ${{ env.rust-version }} - - name: Install protoc - run: | - sudo apt-get install -y protobuf-compiler - name: Download ic-test-state-machine run: | bash scripts/download_state_machine_binary.sh - name: Run tests run: | - cargo test --all-targets + cargo test --workspace --exclude candid-extractor --all-targets fmt: name: cargo fmt @@ -92,15 +77,10 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - key: ${{ runner.os }}-fmt-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + key: ${{ runner.os }}-fmt-${{ hashFiles('Cargo.lock', 'rust-toolchain.toml') }} restore-keys: | ${{ runner.os }}-fmt- ${{ runner.os }}- - - name: Install Rust - uses: dtolnay/rust-toolchain@v1 - with: - toolchain: ${{ env.rust-version }} - components: rustfmt - name: Check formatting run: | cargo fmt --all -- --check @@ -120,18 +100,10 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - key: ${{ runner.os }}-clippy-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + key: ${{ runner.os }}-clippy-${{ hashFiles('Cargo.lock', 'rust-toolchain.toml') }} restore-keys: | ${{ runner.os }}-clippy- ${{ runner.os }}- - - name: Install Rust - uses: dtolnay/rust-toolchain@v1 - with: - toolchain: ${{ env.rust-version }} - components: clippy - - name: Install protoc - run: | - sudo apt-get install -y protobuf-compiler - name: Run clippy run: | cargo clippy --tests --benches -- -D warnings diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index f2e21bc57..d8bb85c5a 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -11,7 +11,6 @@ concurrency: cancel-in-progress: true env: - rust-version: 1.65.0 dfx-version: 0.14.1 ic-wasm-version: 0.4.0 @@ -31,16 +30,11 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - key: ${{ runner.os }}-candid-extractor-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + key: ${{ runner.os }}-candid-extractor-${{ hashFiles('Cargo.lock', 'rust-toolchain.toml') }} restore-keys: | ${{ runner.os }}-candid-extractor- ${{ runner.os }}- - - name: Install Rust - uses: dtolnay/rust-toolchain@v1 - with: - toolchain: ${{ env.rust-version }} - - name: Build candid-extractor run: cargo build -p candid-extractor --release @@ -71,18 +65,11 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ examples/${{ matrix.project-name }}/target/ - key: ${{ runner.os }}-${{ matrix.project-name }}-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + key: ${{ runner.os }}-${{ matrix.project-name }}-${{ hashFiles('Cargo.lock', 'rust-toolchain.toml') }} restore-keys: | ${{ runner.os }}-${{ matrix.project-name }}- ${{ runner.os }}- - - name: Install Rust - uses: dtolnay/rust-toolchain@v1 - with: - toolchain: ${{ env.rust-version }} - target: wasm32-unknown-unknown - components: rustfmt - - name: Install ic-wasm # might already in cache run: | @@ -133,7 +120,7 @@ jobs: env: RUST_BACKTRACE: 1 - - name: cargo fmt # no clippy because #[import] makes it fail + - name: cargo fmt # no clippy because build.rs using ic-cdk-bindgen would fail run: | pushd examples/${{ matrix.project-name }} cargo fmt --check diff --git a/.github/workflows/release-candid-extractor.yml b/.github/workflows/release-candid-extractor.yml index 0438b283c..e5ae44bfb 100644 --- a/.github/workflows/release-candid-extractor.yml +++ b/.github/workflows/release-candid-extractor.yml @@ -4,9 +4,6 @@ on: tags: - "candid-extractor-*" -env: - rust-version: 1.65.0 - jobs: release: runs-on: ${{ matrix.os }} @@ -14,8 +11,8 @@ jobs: fail-fast: false matrix: include: - # The indirect dependency `zstd-safe` (introduced by `wasmtime`) needs higher version of GLIBC. - # using ubuntu-20.04 will fail to compile + # The indirect dependency `zstd-safe` (introduced by `wasmtime`) needs higher version of GLIBC. + # using ubuntu-20.04 will fail to compile - os: ubuntu-22.04 binstall_pkg: candid-extractor-x86_64-unknown-linux-gnu.tar.gz - os: macos-12 @@ -34,16 +31,10 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - key: ${{ runner.os }}-release-${{ hashFiles('**/Cargo.toml', 'rust-toolchain.toml') }} + key: ${{ runner.os }}-candid-extractor-${{ hashFiles('Cargo.lock', 'rust-toolchain.toml') }} restore-keys: | - ${{ runner.os }}-release- + ${{ runner.os }}-candid-extractor- ${{ runner.os }}- - - - name: Install Rust - uses: dtolnay/rust-toolchain@v1 - with: - toolchain: ${{ env.rust-version }} - - name: Build run: | cargo build -p candid-extractor --release --locked diff --git a/Cargo.lock b/Cargo.lock index 0e3bcb38b..dd5768168 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -972,7 +972,8 @@ dependencies = [ [[package]] name = "ic-test-state-machine-client" version = "3.0.0" -source = "git+https://github.com/lwshang/test-state-machine-client?branch=lwshang/candid_0.9#1bb17d8d2d7ecb762dc9fd6621ff105d12ed5107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cadf6ac4a193a8a45287da67c6c385f118d9266f46d6d98e40fbbd469d3822e" dependencies = [ "candid", "ciborium", diff --git a/Cargo.toml b/Cargo.toml index 51a81f0ac..4d676c16d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,7 @@ [workspace] members = [ - "src/ic0", - "src/ic-cdk", - "src/ic-cdk-bindgen", - "src/ic-cdk-macros", - "src/ic-cdk-timers", - "src/candid-extractor", - "library/ic-certified-map", - "library/ic-ledger-types", + "src/*", + "library/*", "e2e-tests", ] @@ -17,10 +11,8 @@ edition = "2021" repository = "https://github.com/dfinity/cdk-rs" # MSRV # Avoid updating this field unless we use new Rust features -# Sync rust-version in following CI files: -# .github/workflows/ci.yml -# .github/workflows/examples.yml -rust-version = "1.65.0" +# Sync with rust-toolchain.toml +rust-version = "1.66.0" license = "Apache-2.0" [profile.canister-release] diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index c3d061116..4a44bfa81 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -43,5 +43,4 @@ path = "canisters/canister_info.rs" [dev-dependencies] hex.workspace = true -# TODO: Use the public crate when this [PR](https://github.com/dfinity/test-state-machine-client/pull/19) merge. -ic-test-state-machine-client = { git = "https://github.com/lwshang/test-state-machine-client", branch = "lwshang/candid_0.9" } +ic-test-state-machine-client = "3" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index bce0b458d..4af0f9705 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,7 +1,4 @@ [toolchain] -channel = "1.71.1" +channel = "1.66.0" # sync with rust-version in root Cargo.toml targets = ["wasm32-unknown-unknown"] components = ["rustfmt", "clippy"] - -# The version only influences the local develop environment. -# No need to sync with Cargo.toml and CI. diff --git a/src/candid-extractor/src/main.rs b/src/candid-extractor/src/main.rs index b3478acee..6ef9a2472 100644 --- a/src/candid-extractor/src/main.rs +++ b/src/candid-extractor/src/main.rs @@ -25,7 +25,7 @@ where let memory = canister .get_memory(&mut store, "memory") - .ok_or(anyhow::format_err!("failed to find `memory` export"))?; + .ok_or_else(|| anyhow::format_err!("failed to find `memory` export"))?; let memory_buffer = memory.data(&store); let mut i = candid_pointer as usize; From 847d6898f17ffba73210bab16c9832f6ebdf897e Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:23:47 -0700 Subject: [PATCH 172/234] fix: Remove global state from `ic-cdk-macros` (#430) * Remove global state from ic-cdk-macros * Update version and changelog --- Cargo.lock | 6 +++--- src/ic-cdk-macros/CHANGELOG.md | 6 ++++++ src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-macros/src/export.rs | 8 ++++---- src/ic-cdk-macros/src/lib.rs | 7 ------- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd5768168..bfa39101c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -919,7 +919,7 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.8.0" +version = "0.8.1" dependencies = [ "candid", "ic-cdk", @@ -1475,9 +1475,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "5907a1b7c277254a8b15170f6e7c97cfa60ee7872a3217663bb81151e48184bb" dependencies = [ "proc-macro2", ] diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index 2d9f47ec7..82a803bdf 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.8.1] - 2023-10-02 + +### Fixed + +- Macros no longer use global state in the names of functions. JetBrains IDEs should no longer produce spurious errors. (#430) + ## [0.8.0] - 2023-09-18 ### Changed diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 8e85ee76f..d127d4495 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.8.0" # no need to sync with ic-cdk +version = "0.8.1" # no need to sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index 38c432d7b..f6b2440e5 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -1,5 +1,5 @@ use proc_macro2::{Ident, Span, TokenStream}; -use quote::quote; +use quote::{format_ident, quote}; use serde::Deserialize; use serde_tokenstream::from_tokenstream; use std::fmt::Formatter; @@ -57,7 +57,7 @@ impl std::fmt::Display for MethodType { fn get_args(method: MethodType, signature: &Signature) -> Result)>, Error> { // We only need the tuple of arguments, not their types. Magic of type inference. let mut args = vec![]; - for ref arg in &signature.inputs { + for (i, arg) in signature.inputs.iter().enumerate() { let (ident, ty) = match arg { FnArg::Receiver(r) => { return Err(Error::new( @@ -73,7 +73,7 @@ fn get_args(method: MethodType, signature: &Signature) -> Result u32 { - NEXT_ID.fetch_add(1, Ordering::SeqCst) -} - fn handle_debug_and_errors( cb: F, name: &str, From 9d1b929aba6d3233c5b1403ebf95c5805468efe0 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Wed, 11 Oct 2023 11:09:34 -0700 Subject: [PATCH 173/234] Release ic-cdk@0.11.1, ic0@0.21.0 (#433) --- Cargo.lock | 4 ++-- Cargo.toml | 10 +++------- src/ic-cdk/Cargo.toml | 2 +- src/ic0/Cargo.toml | 2 +- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bfa39101c..0853bd4f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -883,7 +883,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "ic-cdk" -version = "0.11.0" +version = "0.11.1" dependencies = [ "candid", "ic-cdk-macros", @@ -983,7 +983,7 @@ dependencies = [ [[package]] name = "ic0" -version = "0.18.12" +version = "0.21.0" dependencies = [ "quote", "syn 1.0.107", diff --git a/Cargo.toml b/Cargo.toml index 4d676c16d..dce58e555 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,5 @@ [workspace] -members = [ - "src/*", - "library/*", - "e2e-tests", -] +members = ["src/*", "library/*", "e2e-tests"] [workspace.package] authors = ["DFINITY Stiftung "] @@ -23,8 +19,8 @@ lto = true opt-level = 'z' [workspace.dependencies] -ic0 = { path = "src/ic0", version = "0.18.12" } -ic-cdk = { path = "src/ic-cdk", version = "0.11" } +ic0 = { path = "src/ic0", version = "0.21.0" } +ic-cdk = { path = "src/ic-cdk", version = "0.11.1" } ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.5.0" } candid = "0.9.6" diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index c0062919e..5876cd9f5 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.11.0" +version = "0.11.1" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml index 4eb6953bb..700cf38fb 100644 --- a/src/ic0/Cargo.toml +++ b/src/ic0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic0" -version = "0.18.12" +version = "0.21.0" authors.workspace = true edition.workspace = true license.workspace = true From 2f8b47b7b7fc08225c60f97a69b4184f1adb6090 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 11 Oct 2023 16:57:42 -0400 Subject: [PATCH 174/234] feat: cycles_burn (#434) * ic0.txt * safe api * doc * update ic-test-state-machine * test * changelog --- Cargo.lock | 6 ++--- Cargo.toml | 4 +-- e2e-tests/canisters/api_call.rs | 7 ++++- e2e-tests/tests/e2e.rs | 33 ++++++++++++++++++++++++ ic0.txt | 1 + scripts/download_state_machine_binary.sh | 2 +- src/candid-extractor/Cargo.toml | 2 +- src/candid-extractor/ic_mock.wat | 1 + src/ic-cdk/CHANGELOG.md | 16 ++++++++++++ src/ic-cdk/Cargo.toml | 2 +- src/ic-cdk/src/api/mod.rs | 18 +++++++++++++ src/ic0/Cargo.toml | 2 +- src/ic0/src/ic0.rs | 4 +++ 13 files changed, 88 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0853bd4f2..9c766da64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,7 +218,7 @@ dependencies = [ [[package]] name = "candid-extractor" -version = "0.1.1" +version = "0.1.2" dependencies = [ "anyhow", "quote", @@ -883,7 +883,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "ic-cdk" -version = "0.11.1" +version = "0.11.2" dependencies = [ "candid", "ic-cdk-macros", @@ -983,7 +983,7 @@ dependencies = [ [[package]] name = "ic0" -version = "0.21.0" +version = "0.21.1" dependencies = [ "quote", "syn 1.0.107", diff --git a/Cargo.toml b/Cargo.toml index dce58e555..d4ce5c0e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,8 @@ lto = true opt-level = 'z' [workspace.dependencies] -ic0 = { path = "src/ic0", version = "0.21.0" } -ic-cdk = { path = "src/ic-cdk", version = "0.11.1" } +ic0 = { path = "src/ic0", version = "0.21.1" } +ic-cdk = { path = "src/ic-cdk", version = "0.11.2" } ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.5.0" } candid = "0.9.6" diff --git a/e2e-tests/canisters/api_call.rs b/e2e-tests/canisters/api_call.rs index 7603147b1..2f8f90002 100644 --- a/e2e-tests/canisters/api_call.rs +++ b/e2e-tests/canisters/api_call.rs @@ -1,4 +1,4 @@ -use ic_cdk::{api::call::ManualReply, query}; +use ic_cdk::{api::call::ManualReply, query, update}; #[query] fn instruction_counter() -> u64 { @@ -10,4 +10,9 @@ fn manual_reject() -> ManualReply { ManualReply::reject("manual reject") } +#[update] +fn cycles_burn(amount: u128) -> u128 { + ic_cdk::api::cycles_burn(amount) +} + fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 39f637a95..20f2129e3 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -439,3 +439,36 @@ fn test_canister_info() { } ); } + +#[test] +fn test_cycles_burn() { + let env = env(); + let wasm = cargo_build_canister("api-call"); + let canister_id = env.create_canister(None); + env.add_cycles(canister_id, 1500); + + env.install_canister(canister_id, wasm, vec![], None); + eprintln!("Canister installed."); + let balance1 = env.cycle_balance(canister_id); + eprintln!("Balance 1: {balance1}"); + + let attempted = 1000u128; + + // Scenario 1: burn less than balance + let (burned,): (u128,) = call_candid(&env, canister_id, "cycles_burn", (attempted,)) + .expect("Error calling cycles_burn"); + eprintln!("Attempted to burn {attempted}, actually burned {burned}"); + assert_eq!(burned, attempted); + let balance2 = env.cycle_balance(canister_id); + eprintln!("Balance 2: {balance2}"); + + // Scenario 2: burn more than balance + let (burned,): (u128,) = call_candid(&env, canister_id, "cycles_burn", (attempted,)) + .expect("Error calling cycles_burn"); + eprintln!("Attempted to burn {attempted}, actually burned {burned}"); + assert!(burned < attempted); + assert_eq!(burned, balance2); + let balance3 = env.cycle_balance(canister_id); + eprintln!("Balance 3: {balance3}"); + assert_eq!(balance3, 0); +} diff --git a/ic0.txt b/ic0.txt index eaff356c6..29955e510 100644 --- a/ic0.txt +++ b/ic0.txt @@ -17,6 +17,7 @@ ic0.msg_cycles_refunded128 : (dst : i32) -> (); // R ic0.msg_cycles_accept : (max_amount : i64) -> (amount : i64); // U Rt Ry ic0.msg_cycles_accept128 : (max_amount_high : i64, max_amount_low: i64, dst : i32) -> (); // U Rt Ry +ic0.cycles_burn128 : (amount_high : i64, amount_low : i64, dst : i32) -> ();// I G U Ry Rt C T ic0.canister_self_size : () -> i32; // * ic0.canister_self_copy : (dst : i32, offset : i32, size : i32) -> (); // * diff --git a/scripts/download_state_machine_binary.sh b/scripts/download_state_machine_binary.sh index b44136a01..5b8995d9a 100755 --- a/scripts/download_state_machine_binary.sh +++ b/scripts/download_state_machine_binary.sh @@ -8,7 +8,7 @@ cd "$SCRIPTS_DIR/.." uname_sys=$(uname -s | tr '[:upper:]' '[:lower:]') echo "uname_sys: $uname_sys" -commit_sha="b314222935b7d06c70036b0b54aa80a33252d79c" +commit_sha="15e69667ae983fa92c33794a3954d9ca87518af6" curl -sLO "https://download.dfinity.systems/ic/$commit_sha/binaries/x86_64-$uname_sys/ic-test-state-machine.gz" gzip -d ic-test-state-machine.gz diff --git a/src/candid-extractor/Cargo.toml b/src/candid-extractor/Cargo.toml index de2c44d77..024ba79d2 100644 --- a/src/candid-extractor/Cargo.toml +++ b/src/candid-extractor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid-extractor" -version = "0.1.1" +version = "0.1.2" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/candid-extractor/ic_mock.wat b/src/candid-extractor/ic_mock.wat index da53f6bdc..17e1f5d41 100644 --- a/src/candid-extractor/ic_mock.wat +++ b/src/candid-extractor/ic_mock.wat @@ -17,6 +17,7 @@ (func (export "msg_cycles_refunded128") (param i32) ) (func (export "msg_cycles_accept") (param i64) (result i64) i64.const 0) (func (export "msg_cycles_accept128") (param i64 i64 i32) ) + (func (export "cycles_burn128") (param i64 i64 i32) ) (func (export "canister_self_size") (result i32) i32.const 0) (func (export "canister_self_copy") (param i32 i32 i32) ) (func (export "canister_cycle_balance") (result i64) i64.const 0) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 7b93ba3f0..9403d1e0c 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.11.2] - 2023-10-11 + +### Added + +- `cycles_burn` corresponding to system API `ic0.cycles_burn128`. (#434) + +### Changed + +- Upgrade `ic0` to `0.21.1`. (#434) + +## [0.11.1] - 2023-10-11 + +### Changed + +- Upgrade `ic0` to `0.21.0`. (#433) + ## [0.11.0] - 2023-09-18 ### Changed diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 5876cd9f5..7a0d80e3d 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.11.1" +version = "0.11.2" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index 1ce2f9daa..6aa92d828 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -140,3 +140,21 @@ pub fn is_controller(principal: &Principal) -> bool { // SAFETY: `principal.as_bytes()`, being `&[u8]`, is a readable sequence of bytes and therefore safe to pass to `ic0.is_controller`. unsafe { ic0::is_controller(slice.as_ptr() as i32, slice.len() as i32) != 0 } } + +/// Burns cycles from the canister. +/// +/// Returns the amount of cycles that were actually burned. +pub fn cycles_burn(amount: u128) -> u128 { + let amount_high = (amount >> 64) as u64; + let amount_low = (amount & u64::MAX as u128) as u64; + let mut dst = 0u128; + // SAFETY: `dst` is writable and sixteen bytes wide, and therefore safe to pass to ic0.cycles_burn128 + unsafe { + ic0::cycles_burn128( + amount_high as i64, + amount_low as i64, + &mut dst as *mut u128 as i32, + ) + } + dst +} diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml index 700cf38fb..540cb3d99 100644 --- a/src/ic0/Cargo.toml +++ b/src/ic0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic0" -version = "0.21.0" +version = "0.21.1" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic0/src/ic0.rs b/src/ic0/src/ic0.rs index f5c2ba03c..bac51bf5f 100644 --- a/src/ic0/src/ic0.rs +++ b/src/ic0/src/ic0.rs @@ -19,6 +19,7 @@ extern "C" { pub fn msg_cycles_refunded128(dst: i32); pub fn msg_cycles_accept(max_amount: i64) -> i64; pub fn msg_cycles_accept128(max_amount_high: i64, max_amount_low: i64, dst: i32); + pub fn cycles_burn128(amount_high: i64, amount_low: i64, dst: i32); pub fn canister_self_size() -> i32; pub fn canister_self_copy(dst: i32, offset: i32, size: i32); pub fn canister_cycle_balance() -> i64; @@ -116,6 +117,9 @@ mod non_wasm { pub unsafe fn msg_cycles_accept128(max_amount_high: i64, max_amount_low: i64, dst: i32) { panic!("msg_cycles_accept128 should only be called inside canisters."); } + pub unsafe fn cycles_burn128(amount_high: i64, amount_low: i64, dst: i32) { + panic!("cycles_burn128 should only be called inside canisters."); + } pub unsafe fn canister_self_size() -> i32 { panic!("canister_self_size should only be called inside canisters."); } From cf6611b0844eb7bfc5bbb19287f65b425baf3e87 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Thu, 12 Oct 2023 07:17:56 -0700 Subject: [PATCH 175/234] Release ic-cdk-timers@0.5.1 (#437) --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/ic-cdk-timers/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c766da64..2f366beb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -933,7 +933,7 @@ dependencies = [ [[package]] name = "ic-cdk-timers" -version = "0.5.0" +version = "0.5.1" dependencies = [ "futures", "ic-cdk", diff --git a/Cargo.toml b/Cargo.toml index d4ce5c0e9..de9540aad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.21.1" } ic-cdk = { path = "src/ic-cdk", version = "0.11.2" } -ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.5.0" } +ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.5.1" } candid = "0.9.6" futures = "0.3" diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index fcb0f6266..9414d0ad0 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.5.0" +version = "0.5.1" authors.workspace = true edition.workspace = true license.workspace = true From cda6077820369defaa452a3991fad0d740a0b239 Mon Sep 17 00:00:00 2001 From: Andriy Berestovskyy <91958447+dfinity-berestovskyy@users.noreply.github.com> Date: Thu, 12 Oct 2023 18:19:01 +0200 Subject: [PATCH 176/234] feat: RUN-798: Add call context perf counter (#435) * feat: RUN-798: Add call context perf counter * deprecated note * improve doc * fmt * v0.11.3 and changelog --------- Co-authored-by: Linwei Shang --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 13 +++++++++++++ src/ic-cdk/Cargo.toml | 2 +- src/ic-cdk/src/api/call.rs | 11 +++++++---- src/ic-cdk/src/api/mod.rs | 34 ++++++++++++++++++++++++++-------- 6 files changed, 49 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f366beb3..f588f516e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -883,7 +883,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "ic-cdk" -version = "0.11.2" +version = "0.11.3" dependencies = [ "candid", "ic-cdk-macros", diff --git a/Cargo.toml b/Cargo.toml index de9540aad..2b6e4ba0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.21.1" } -ic-cdk = { path = "src/ic-cdk", version = "0.11.2" } +ic-cdk = { path = "src/ic-cdk", version = "0.11.3" } ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.5.1" } candid = "0.9.6" diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 9403d1e0c..4c5d18573 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.11.3] - 2023-10-12 + +### Added + +- Another type of performance counter: "call context instruction counter". + Can be fetched using either method below: (#435) + - `ic_cdk::api::performance_counter(1)`; + - `ic_cdk::api::call_context_instruction_counter()` as a shorthand; + +### Changed + +- Deprecate `ic_cdk::api::call::performance_counter()` in favor of `ic_cdk::api::performance_counter()`. (#435) + ## [0.11.2] - 2023-10-11 ### Added diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 7a0d80e3d..fbfe0149d 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.11.2" +version = "0.11.3" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index f95aa0231..c335e459f 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -530,7 +530,7 @@ pub fn arg_data_raw() -> Vec { bytes } -/// Get the len of the raw-argument-data-bytes. +/// Gets the len of the raw-argument-data-bytes. pub fn arg_data_raw_size() -> usize { // SAFETY: ic0.msg_arg_data_size is always safe to call. unsafe { ic0::msg_arg_data_size() as usize } @@ -577,10 +577,13 @@ pub fn method_name() -> String { String::from_utf8_lossy(&bytes).into_owned() } -/// Get the value of specified performance counter +/// Gets the value of specified performance counter /// -/// Supported counter type: -/// 0 : instruction counter. The number of WebAssembly instructions the system has determined that the canister has executed. +/// See [`crate::api::performance_counter`]. +#[deprecated( + since = "0.11.3", + note = "This method conceptually doesn't belong to this module. Please use `ic_cdk::api::performance_counter` instead." +)] pub fn performance_counter(counter_type: u32) -> u64 { // SAFETY: ic0.performance_counter is always safe to call. unsafe { ic0::performance_counter(counter_type as i32) as u64 } diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index 6aa92d828..98d13ca16 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -24,7 +24,7 @@ pub fn trap(message: &str) -> ! { unreachable!() } -/// Get current timestamp, in nanoseconds since the epoch (1970-01-01) +/// Gets current timestamp, in nanoseconds since the epoch (1970-01-01) pub fn time() -> u64 { // SAFETY: ic0.time is always safe to call. unsafe { ic0::time() as u64 } @@ -54,13 +54,13 @@ pub fn id() -> Principal { Principal::try_from(&bytes).unwrap() } -/// Get the amount of funds available in the canister. +/// Gets the amount of funds available in the canister. pub fn canister_balance() -> u64 { // SAFETY: ic0.canister_cycle_balance is always safe to call. unsafe { ic0::canister_cycle_balance() as u64 } } -/// Get the amount of funds available in the canister. +/// Gets the amount of funds available in the canister. pub fn canister_balance128() -> u128 { let mut recv = 0u128; // SAFETY: recv is writable and the size expected by ic0.canister_cycle_balance128. @@ -118,23 +118,41 @@ pub fn instruction_counter() -> u64 { performance_counter(0) } -/// Get the value of specified performance counter. +/// Returns the number of WebAssembly instructions the canister has executed +/// within the call context of the current Message execution since +/// Call context creation. /// -/// Supported counter type: -/// 0 : instruction counter. The number of WebAssembly instructions the system has determined that the canister has executed. +/// The counter monotonically increases across all message executions +/// in the call context until the corresponding call context is removed. +#[inline] +pub fn call_context_instruction_counter() -> u64 { + performance_counter(1) +} + +/// Gets the value of specified performance counter. +/// +/// Supported counter types: +/// * `0` : current execution instruction counter. The number of WebAssembly +/// instructions the canister has executed since the beginning of the +/// current Message execution. +/// * `1` : call context instruction counter. The number of WebAssembly +/// instructions the canister has executed within the call context +/// of the current Message execution since Call context creation. +/// The counter monotonically increases across all message executions +/// in the call context until the corresponding call context is removed. #[inline] pub fn performance_counter(counter_type: u32) -> u64 { // SAFETY: ic0.performance_counter is always safe to call. unsafe { ic0::performance_counter(counter_type as i32) as u64 } } -/// Get the value of canister version. +/// Gets the value of canister version. pub fn canister_version() -> u64 { // SAFETY: ic0.canister_version is always safe to call. unsafe { ic0::canister_version() as u64 } } -/// Determine if a Principal is a controller of the canister. +/// Determines if a Principal is a controller of the canister. pub fn is_controller(principal: &Principal) -> bool { let slice = principal.as_slice(); // SAFETY: `principal.as_bytes()`, being `&[u8]`, is a readable sequence of bytes and therefore safe to pass to `ic0.is_controller`. From 6bc4b33d2fd2ee08ef492779cf96bbf2f4146a2b Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 26 Oct 2023 15:17:19 -0400 Subject: [PATCH 177/234] test: refactor management_canister tests (#438) * move main/provisonal tests to e2e * refactor management example * use stable rust in examples * periodically run CI to keep cache available * fmt * single quote in yml * 0 for Sunday --- .github/workflows/ci.yml | 2 + .github/workflows/conventional-commits.yml | 2 + Cargo.lock | 1 + e2e-tests/Cargo.toml | 5 ++ e2e-tests/canisters/management_caller.rs | 80 ++++++++++++++++++ e2e-tests/tests/e2e.rs | 13 +++ examples/build.sh | 2 + examples/management_canister/dfx.json | 8 -- .../management_canister/src/caller/lib.rs | 82 +------------------ examples/management_canister/tests/basic.bats | 27 +++--- examples/rust-toolchain.toml | 4 + 11 files changed, 130 insertions(+), 96 deletions(-) create mode 100644 e2e-tests/canisters/management_caller.rs create mode 100644 examples/rust-toolchain.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b786b3e39..88443c83b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,8 @@ on: branches: - main pull_request: + schedule: + - cron: '0 4 * * 0,3' # 4 a.m. UTC every Sun and Wed, keep actions-cache available concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml index f07b90291..840dabf04 100644 --- a/.github/workflows/conventional-commits.yml +++ b/.github/workflows/conventional-commits.yml @@ -7,6 +7,8 @@ on: - reopened - edited - synchronize + schedule: + - cron: '0 4 * * 0,3' # 4 a.m. UTC every Sun and Wed, keep actions-cache available concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/Cargo.lock b/Cargo.lock index f588f516e..7a8aeed9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -915,6 +915,7 @@ dependencies = [ "ic-test-state-machine-client", "lazy_static", "serde_bytes", + "sha2", ] [[package]] diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 4a44bfa81..c82de0d62 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -16,6 +16,7 @@ ic-cdk-timers.workspace = true lazy_static = "1.4.0" serde_bytes.workspace = true futures.workspace = true +sha2.workspace = true [[bin]] name = "simple-kv-store" @@ -41,6 +42,10 @@ path = "canisters/timers.rs" name = "canister_info" path = "canisters/canister_info.rs" +[[bin]] +name = "management_caller" +path = "canisters/management_caller.rs" + [dev-dependencies] hex.workspace = true ic-test-state-machine-client = "3" diff --git a/e2e-tests/canisters/management_caller.rs b/e2e-tests/canisters/management_caller.rs new file mode 100644 index 000000000..5824e99f3 --- /dev/null +++ b/e2e-tests/canisters/management_caller.rs @@ -0,0 +1,80 @@ +use ic_cdk::*; + +mod main { + use super::*; + use ic_cdk::api::management_canister::main::*; + #[update] + async fn execute_main_methods() { + let arg = CreateCanisterArgument { + settings: Some(CanisterSettings { + controllers: Some(vec![ic_cdk::id()]), + compute_allocation: Some(0.into()), + memory_allocation: Some(10000.into()), + freezing_threshold: Some(10000.into()), + }), + }; + let canister_id = create_canister(arg, 100_000_000_000u128 / 13) + .await + .unwrap() + .0 + .canister_id; + + let arg = UpdateSettingsArgument { + canister_id, + settings: CanisterSettings::default(), + }; + update_settings(arg).await.unwrap(); + + let arg = InstallCodeArgument { + mode: CanisterInstallMode::Install, + canister_id, + // A minimal valid wasm module + // wat2wasm "(module)" + wasm_module: b"\x00asm\x01\x00\x00\x00".to_vec(), + arg: vec![], + }; + install_code(arg).await.unwrap(); + let arg = CanisterIdRecord { canister_id }; + uninstall_code(arg).await.unwrap(); + start_canister(arg).await.unwrap(); + stop_canister(arg).await.unwrap(); + let response = canister_status(arg).await.unwrap().0; + assert_eq!(response.status, CanisterStatusType::Stopped); + deposit_cycles(arg, 1_000_000_000_000u128).await.unwrap(); + delete_canister(arg).await.unwrap(); + let response = raw_rand().await.unwrap().0; + assert_eq!(response.len(), 32); + } +} + +mod provisional { + use super::*; + use ic_cdk::api::management_canister::provisional::*; + + #[update] + async fn execute_provisional_methods() { + let settings = CanisterSettings { + controllers: Some(vec![ic_cdk::caller()]), + compute_allocation: Some(50.into()), + memory_allocation: Some(10000.into()), + freezing_threshold: Some(10000.into()), + }; + let arg = ProvisionalCreateCanisterWithCyclesArgument { + amount: Some(1_000_000_000.into()), + settings: Some(settings), + }; + let canister_id = provisional_create_canister_with_cycles(arg) + .await + .unwrap() + .0 + .canister_id; + + let arg = ProvisionalTopUpCanisterArgument { + canister_id, + amount: 1_000_000_000.into(), + }; + provisional_top_up_canister(arg).await.unwrap(); + } +} + +fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 20f2129e3..6957dfcee 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -472,3 +472,16 @@ fn test_cycles_burn() { eprintln!("Balance 3: {balance3}"); assert_eq!(balance3, 0); } + +#[test] +fn call_management() { + let env = env(); + let wasm = cargo_build_canister("management_caller"); + let canister_id = env.create_canister(None); + env.add_cycles(canister_id, 100_000_000_000_000); + env.install_canister(canister_id, wasm, vec![], None); + let () = call_candid(&env, canister_id, "execute_main_methods", ()) + .expect("Error calling execute_main_methods"); + let () = call_candid(&env, canister_id, "execute_provisional_methods", ()) + .expect("Error calling execute_provisional_methods"); +} diff --git a/examples/build.sh b/examples/build.sh index 66786d692..ead0d61d5 100755 --- a/examples/build.sh +++ b/examples/build.sh @@ -7,6 +7,8 @@ root="$(dirname "$0")/.." example_root="$(dirname "$0")/$name" did_file="/tmp/a.did" +cargo update --manifest-path="$example_root/Cargo.toml" + cargo build --manifest-path="$example_root/Cargo.toml" \ --target wasm32-unknown-unknown \ --release \ diff --git a/examples/management_canister/dfx.json b/examples/management_canister/dfx.json index bdcaab5f6..1420a1204 100644 --- a/examples/management_canister/dfx.json +++ b/examples/management_canister/dfx.json @@ -7,13 +7,5 @@ "wasm": "target/wasm32-unknown-unknown/release/caller-opt.wasm", "build": "sh ../build.sh management_canister caller" } - }, - "defaults": { - "canister_http": { - "enabled": true - }, - "bitcoin": { - "enabled": true - } } } \ No newline at end of file diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index c4409c47b..edf0209d1 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -1,82 +1,5 @@ use ic_cdk::*; -mod main { - use super::*; - use ic_cdk::api::management_canister::main::*; - #[update] - async fn execute_main_methods() { - let arg = CreateCanisterArgument { - settings: Some(CanisterSettings { - controllers: Some(vec![ic_cdk::id()]), - compute_allocation: Some(0.into()), - memory_allocation: Some(10000.into()), - freezing_threshold: Some(10000.into()), - }), - }; - let canister_id = create_canister(arg, 100_000_000_000u128 / 13) - .await - .unwrap() - .0 - .canister_id; - - let arg = UpdateSettingsArgument { - canister_id, - settings: CanisterSettings::default(), - }; - update_settings(arg).await.unwrap(); - - let arg = InstallCodeArgument { - mode: CanisterInstallMode::Install, - canister_id, - // A minimal valid wasm module - // wat2wasm "(module)" - wasm_module: b"\x00asm\x01\x00\x00\x00".to_vec(), - arg: vec![], - }; - install_code(arg).await.unwrap(); - let arg = CanisterIdRecord { canister_id }; - uninstall_code(arg).await.unwrap(); - start_canister(arg).await.unwrap(); - stop_canister(arg).await.unwrap(); - let response = canister_status(arg).await.unwrap().0; - assert_eq!(response.status, CanisterStatusType::Stopped); - deposit_cycles(arg, 1_000_000_000_000u128).await.unwrap(); - delete_canister(arg).await.unwrap(); - let response = raw_rand().await.unwrap().0; - assert_eq!(response.len(), 32); - } -} - -mod provisional { - use super::*; - use ic_cdk::api::management_canister::provisional::*; - - #[update] - async fn execute_provisional_methods() { - let settings = CanisterSettings { - controllers: Some(vec![ic_cdk::caller()]), - compute_allocation: Some(50.into()), - memory_allocation: Some(10000.into()), - freezing_threshold: Some(10000.into()), - }; - let arg = ProvisionalCreateCanisterWithCyclesArgument { - amount: Some(1_000_000_000.into()), - settings: Some(settings), - }; - let canister_id = provisional_create_canister_with_cycles(arg) - .await - .unwrap() - .0 - .canister_id; - - let arg = ProvisionalTopUpCanisterArgument { - canister_id, - amount: 1_000_000_000.into(), - }; - provisional_top_up_canister(arg).await.unwrap(); - } -} - mod http_request { use super::*; use ic_cdk::api::management_canister::http_request::*; @@ -206,7 +129,10 @@ mod bitcoin { assert!(response.is_err()); if let Err((rejection_code, rejection_reason)) = response { assert_eq!(rejection_code, RejectionCode::CanisterReject); - assert_eq!(&rejection_reason, "bitcoin_send_transaction failed: Can't deserialize transaction because it's malformed."); + assert_eq!( + &rejection_reason, + "send_transaction failed: MalformedTransaction" + ); }; } } diff --git a/examples/management_canister/tests/basic.bats b/examples/management_canister/tests/basic.bats index 2308ec79e..aa9fdf7ec 100644 --- a/examples/management_canister/tests/basic.bats +++ b/examples/management_canister/tests/basic.bats @@ -1,22 +1,29 @@ # Executed before each test. setup() { cd examples/management_canister - bitcoind -regtest -daemonwait - # Make sure the directory is clean. - dfx start --clean --background } # executed after each test teardown() { dfx stop - bitcoin-cli -regtest stop } -@test "All management canister methods succeed" { +@test "http_request example succeed" { + dfx start --clean --background --enable-canister-http + dfx deploy + dfx canister call caller http_request_example +} + +@test "ecdsa methods succeed" { + dfx start --clean --background + dfx deploy + dfx canister call caller execute_ecdsa_methods +} + +@test "bitcoin methods succeed" { + bitcoind -regtest -daemonwait + dfx start --clean --background --enable-bitcoin dfx deploy - run dfx canister call caller execute_main_methods - run dfx canister call caller execute_provisional_methods - run dfx canister call caller http_request_example - run dfx canister call caller execute_ecdsa_methods - run dfx canister call caller execute_bitcoin_methods + dfx canister call caller execute_bitcoin_methods + bitcoin-cli -regtest stop } diff --git a/examples/rust-toolchain.toml b/examples/rust-toolchain.toml new file mode 100644 index 000000000..ccf20527a --- /dev/null +++ b/examples/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "stable" # sync with rust-version in root Cargo.toml +targets = ["wasm32-unknown-unknown"] +components = ["rustfmt", "clippy"] From a14d272312d682f27270e48ced7bbf5fdccf0ca7 Mon Sep 17 00:00:00 2001 From: Marcin Nowak-Liebiediew Date: Mon, 30 Oct 2023 14:59:10 +0100 Subject: [PATCH 178/234] chore(ci): use `dfinity/setup-dfx` GitHub Action to install `dfx` (#439) --- .github/workflows/examples.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index d8bb85c5a..a528d0816 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -88,10 +88,9 @@ jobs: mv candid-extractor /usr/local/bin/candid-extractor - name: Install DFX - run: | - export DFX_VERSION=${{env.dfx-version }} - echo Install DFX v$DFX_VERSION - yes | sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)" + uses: dfinity/setup-dfx@main + with: + dfx-version: "${{ env.dfx-version }}" - name: Setup BATS uses: mig4/setup-bats@v1.0.2 From 38be74ddcf5e6f0ac342f16443f4727576895397 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 1 Nov 2023 10:55:38 -0400 Subject: [PATCH 179/234] fix (#440) --- .github/workflows/conventional-commits.yml | 2 -- .github/workflows/examples.yml | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml index 840dabf04..f07b90291 100644 --- a/.github/workflows/conventional-commits.yml +++ b/.github/workflows/conventional-commits.yml @@ -7,8 +7,6 @@ on: - reopened - edited - synchronize - schedule: - - cron: '0 4 * * 0,3' # 4 a.m. UTC every Sun and Wed, keep actions-cache available concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index a528d0816..af02095c2 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -5,6 +5,8 @@ on: branches: - main pull_request: + schedule: + - cron: '0 4 * * 0,3' # 4 a.m. UTC every Sun and Wed, keep actions-cache available concurrency: group: ${{ github.workflow }}-${{ github.ref }} From 0b201e947056eed941d7fd1da62354c93ca184a2 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 1 Nov 2023 14:11:53 -0400 Subject: [PATCH 180/234] test: remove vendored actions (#441) * use original action instead of dfinity fork * regex based conventional pr title * bats submodules * use bats from submodule in examples.yml * try fix * checkout submodules only in test --- .github/workflows/ci.yml | 2 +- .github/workflows/conventional-commits.yml | 27 +++++++++++++++------- .github/workflows/examples.yml | 15 +++++------- .gitmodules | 9 ++++++++ examples/bats/bats-assert | 1 + examples/bats/bats-core | 1 + examples/bats/bats-support | 1 + 7 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 .gitmodules create mode 160000 examples/bats/bats-assert create mode 160000 examples/bats/bats-core create mode 160000 examples/bats/bats-support diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88443c83b..6ce363738 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ on: - main pull_request: schedule: - - cron: '0 4 * * 0,3' # 4 a.m. UTC every Sun and Wed, keep actions-cache available + - cron: "0 4 * * 0,3" # 4 a.m. UTC every Sun and Wed, keep actions-cache available concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml index f07b90291..0d9e0330d 100644 --- a/.github/workflows/conventional-commits.yml +++ b/.github/workflows/conventional-commits.yml @@ -14,13 +14,24 @@ concurrency: jobs: check: + name: conventional-pr-title:required runs-on: ubuntu-latest steps: - - uses: dfinity/conventional-pr-title-action@v2.2.3 - with: - success-state: Title follows the specification. - failure-state: Title does not follow the specification. - context-name: conventional-pr-title - preset: conventional-changelog-angular@latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Conventional commit patterns: + # verb: description + # verb!: description of breaking change + # verb(scope): Description of change to $scope + # verb(scope)!: Description of breaking change to $scope + # verb: feat, fix, ... + # scope: refers to the part of code being changed. E.g. " (accounts)" or " (accounts,canisters)" + # !: Indicates that the PR contains a breaking change. + - env: + TITLE: ${{ github.event.pull_request.title }} + run: | + echo "PR title: $TITLE" + if [[ "$TITLE" =~ ^(feat|fix|chore|build|ci|docs|style|refactor|perf|test)(\([-a-zA-Z0-9,]+\))?\!?\: ]]; then + echo pass + else + echo "PR title does not match conventions" + exit 1 + fi diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index af02095c2..64f1e787a 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -6,7 +6,7 @@ on: - main pull_request: schedule: - - cron: '0 4 * * 0,3' # 4 a.m. UTC every Sun and Wed, keep actions-cache available + - cron: "0 4 * * 0,3" # 4 a.m. UTC every Sun and Wed, keep actions-cache available concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -57,6 +57,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v3 + with: + submodules: "recursive" - name: Cache uses: actions/cache@v3 @@ -90,14 +92,9 @@ jobs: mv candid-extractor /usr/local/bin/candid-extractor - name: Install DFX - uses: dfinity/setup-dfx@main - with: - dfx-version: "${{ env.dfx-version }}" - - - name: Setup BATS - uses: mig4/setup-bats@v1.0.2 + uses: dfinity/setup-dfx@main with: - bats-version: 1.2.1 + dfx-version: "${{ env.dfx-version }}" - name: Install bitcoin if: ${{ matrix.project-name == 'management_canister' }} @@ -117,7 +114,7 @@ jobs: - name: Run Tests shell: bash run: | - bats -r examples/${{ matrix.project-name }} + ./examples/bats/bats-core/bin/bats -r examples/${{ matrix.project-name }} env: RUST_BACKTRACE: 1 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..ef90ac626 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "examples/bats/bats-core"] + path = examples/bats/bats-core + url = https://github.com/bats-core/bats-core.git +[submodule "examples/bats/bats-support"] + path = examples/bats/bats-support + url = https://github.com/bats-core/bats-support.git +[submodule "examples/bats/bats-assert"] + path = examples/bats/bats-assert + url = https://github.com/bats-core/bats-assert.git diff --git a/examples/bats/bats-assert b/examples/bats/bats-assert new file mode 160000 index 000000000..e2d855bc7 --- /dev/null +++ b/examples/bats/bats-assert @@ -0,0 +1 @@ +Subproject commit e2d855bc78619ee15b0c702b5c30fb074101159f diff --git a/examples/bats/bats-core b/examples/bats/bats-core new file mode 160000 index 000000000..f1f5115e3 --- /dev/null +++ b/examples/bats/bats-core @@ -0,0 +1 @@ +Subproject commit f1f5115e3621e47fc41a32e36450afa95fdb2830 diff --git a/examples/bats/bats-support b/examples/bats/bats-support new file mode 160000 index 000000000..9bf10e876 --- /dev/null +++ b/examples/bats/bats-support @@ -0,0 +1 @@ +Subproject commit 9bf10e876dd6b624fe44423f0b35e064225f7556 From 56e98996166cba93e3b084e9be4c0ce11b74f41f Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 7 Nov 2023 15:17:58 -0500 Subject: [PATCH 181/234] test: fix print example (#443) * fix * add bats test --- examples/print/Cargo.toml | 8 +++++--- examples/print/src/print_rs/Cargo.toml | 3 ++- examples/print/src/print_rs/lib.rs | 2 +- examples/print/tests/basic.bats | 17 +++++++++++++++++ 4 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 examples/print/tests/basic.bats diff --git a/examples/print/Cargo.toml b/examples/print/Cargo.toml index 74a0decf6..d0d16f486 100644 --- a/examples/print/Cargo.toml +++ b/examples/print/Cargo.toml @@ -1,4 +1,6 @@ [workspace] -members = [ - "src/print_rs", -] +members = ["src/print_rs"] + +[workspace.dependencies] +ic-cdk = { path = "../../src/ic-cdk" } +candid = "0.9" diff --git a/examples/print/src/print_rs/Cargo.toml b/examples/print/src/print_rs/Cargo.toml index 3dd3a6261..17fa426d5 100644 --- a/examples/print/src/print_rs/Cargo.toml +++ b/examples/print/src/print_rs/Cargo.toml @@ -10,4 +10,5 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -ic-cdk = { path = "../../../../src/ic-cdk" } +ic-cdk.workspace = true +candid.workspace = true diff --git a/examples/print/src/print_rs/lib.rs b/examples/print/src/print_rs/lib.rs index 5114f52dc..aa188ba2f 100644 --- a/examples/print/src/print_rs/lib.rs +++ b/examples/print/src/print_rs/lib.rs @@ -3,4 +3,4 @@ fn print() { ic_cdk::print("Hello World"); } -ic_cdk::export_candid!(::ic_cdk::export::candid); +ic_cdk::export_candid!(); diff --git a/examples/print/tests/basic.bats b/examples/print/tests/basic.bats new file mode 100644 index 000000000..db5028e4b --- /dev/null +++ b/examples/print/tests/basic.bats @@ -0,0 +1,17 @@ +# Executed before each test. +setup() { + cd examples/print + # Make sure the directory is clean. + dfx start --clean --background +} + +# executed after each test +teardown() { + dfx stop +} + +@test "Can print" { + dfx deploy + + dfx canister call print print +} From 0b14facb80e161de79264c8f88b1a0c8e18ffcb6 Mon Sep 17 00:00:00 2001 From: maciejdfinity <122265298+maciejdfinity@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:26:11 +0100 Subject: [PATCH 182/234] Adding icrc1_memo to the Transaction (#445) --- library/ic-ledger-types/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/ic-ledger-types/src/lib.rs b/library/ic-ledger-types/src/lib.rs index 722c10c85..f1a171e6d 100644 --- a/library/ic-ledger-types/src/lib.rs +++ b/library/ic-ledger-types/src/lib.rs @@ -502,6 +502,8 @@ pub struct Transaction { pub operation: Option, /// The time at which the client of the ledger constructed the transaction. pub created_at_time: Timestamp, + /// The memo that was provided to the icrc1_transfer endpoint. + pub icrc1_memo: Option, } /// A single record in the ledger. From 917a02e2063ef2d6c868c9e91afa6c6fca141bff Mon Sep 17 00:00:00 2001 From: Stefan Kaestle Date: Mon, 20 Nov 2023 18:19:54 +0100 Subject: [PATCH 183/234] feat: Added query stats to canister status endpoint (#432) * Added query stats to canister status endpoint * Changelog * pub and doc * update ic-state-machine * Adopt new API as discussed with Martin * bump ic-cdk v0.11.4 --------- Co-authored-by: Linwei Shang --- Cargo.lock | 2 +- Cargo.toml | 2 +- scripts/download_state_machine_binary.sh | 4 +++- src/ic-cdk/CHANGELOG.md | 16 +++++++++++----- src/ic-cdk/Cargo.toml | 2 +- .../src/api/management_canister/main/types.rs | 13 +++++++++++++ 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a8aeed9d..10f309979 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -883,7 +883,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "ic-cdk" -version = "0.11.3" +version = "0.11.4" dependencies = [ "candid", "ic-cdk-macros", diff --git a/Cargo.toml b/Cargo.toml index 2b6e4ba0f..da46aae85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.21.1" } -ic-cdk = { path = "src/ic-cdk", version = "0.11.3" } +ic-cdk = { path = "src/ic-cdk", version = "0.11.4" } ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.5.1" } candid = "0.9.6" diff --git a/scripts/download_state_machine_binary.sh b/scripts/download_state_machine_binary.sh index 5b8995d9a..7f9aae609 100755 --- a/scripts/download_state_machine_binary.sh +++ b/scripts/download_state_machine_binary.sh @@ -8,7 +8,9 @@ cd "$SCRIPTS_DIR/.." uname_sys=$(uname -s | tr '[:upper:]' '[:lower:]') echo "uname_sys: $uname_sys" -commit_sha="15e69667ae983fa92c33794a3954d9ca87518af6" +# Check https://gitlab.com/dfinity-lab/public/ic/-/commits/master +# Find the most recent commit with a green check mark (the artifacts were built successfully) +commit_sha="f3216c1d7d83a366b4af0cf24708f84819880246" curl -sLO "https://download.dfinity.systems/ic/$commit_sha/binaries/x86_64-$uname_sys/ic-test-state-machine.gz" gzip -d ic-test-state-machine.gz diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 4c5d18573..aebb0c211 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.11.4] - 2023-11-20 + +### Added + +- `query_stats` in `canister_status` response. (#432) + ## [0.11.3] - 2023-10-12 ### Added @@ -203,7 +209,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- `StableWriter` and `StableReader` are now wrappers around `StableIO`. +- `StableWriter` and `StableReader` are now wrappers around `StableIO`. ## [0.6.5] - 2022-11-04 @@ -309,14 +315,14 @@ BREAKING CHANGE of experimental API: - Add Clone and Copy to RejectionCode (#202) ### Fixed -- Do not call done() in stable_restore() (#216) +- Do not call done() in stable_restore() (#216) - Remove out-of-bounds vulnerability (#208) - Run inter-canister calls without awaiting (#233) ## [0.4.0] - 2022-01-26 ### Changed -- `candid` is required to be included in `[dependencies]` to use the `#[import]` macro (#190) -- Deprecate block_on in favour of the new spawn function (#189) +- `candid` is required to be included in `[dependencies]` to use the `#[import]` macro (#190) +- Deprecate block_on in favour of the new spawn function (#189) - Trap in setup panic hook (#172) ## [0.3.3] - 2021-11-17 @@ -325,5 +331,5 @@ BREAKING CHANGE of experimental API: ## [0.3.2] - 2021-09-16 ### Added -- Add support for 64 bit stable memory (#137) +- Add support for 64 bit stable memory (#137) - Add support for 'heartbeat' and 'inspect_message' (#129) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index fbfe0149d..02605f4a5 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.11.3" +version = "0.11.4" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index 685b1439f..6213b5869 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -164,6 +164,17 @@ pub struct DefiniteCanisterSettings { pub freezing_threshold: Nat, } +/// Query statistics, returned by [canister_status](super::canister_status). +#[derive( + CandidType, Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, +)] +pub struct QueryStats { + num_calls_total: candid::Nat, + num_instructions_total: candid::Nat, + request_payload_bytes_total: candid::Nat, + response_payload_bytes_total: candid::Nat, +} + /// Argument type of [canister_status](super::canister_status). #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, @@ -181,6 +192,8 @@ pub struct CanisterStatusResponse { pub cycles: Nat, /// Amount of cycles burned per day. pub idle_cycles_burned_per_day: Nat, + /// Query statistics + pub query_stats: QueryStats, } /// Details about a canister change initiated by a user. From 710a6cdcc3eb03d2392df1dfd5f047dff9deee80 Mon Sep 17 00:00:00 2001 From: Frederik Rothenberger Date: Thu, 23 Nov 2023 17:40:02 +0100 Subject: [PATCH 184/234] chore: Upgrade candid to v0.10 (#448) * chore: Upgrade candid to v0.10 This upgrades candid to the new libary version which has been split into smaller pieces, hence reducing the size of the dependencies for downstream projects. * Adapt cdk-bindgen to new candid_parser library * Remove setting default value again * Remove candid dependency from ic-cdk-bindgen * Reword changelog entry * Accommodate candid changes with regards to Nat conversions * Update remaining candid references * Update even more candid references * Fix counter example * Fix nat comparison * bump versions and changelog * cargo update * bump ic-cdk-macros * mv compile tests to ic-cdk * bump ic-cdk-bindgen * README --------- Co-authored-by: Linwei Shang --- Cargo.lock | 733 ++++++++---------- Cargo.toml | 7 +- README.md | 4 +- e2e-tests/canisters/management_caller.rs | 16 +- .../src/asset_storage_rs/Cargo.toml | 2 +- examples/chess/src/chess_rs/Cargo.toml | 2 +- examples/counter/Cargo.toml | 2 +- examples/counter/src/counter_rs/lib.rs | 2 +- .../management_canister/src/caller/Cargo.toml | 2 +- .../management_canister/src/caller/lib.rs | 2 +- examples/print/Cargo.toml | 2 +- examples/profile/Cargo.toml | 2 +- library/ic-ledger-types/CHANGELOG.md | 5 + library/ic-ledger-types/Cargo.toml | 2 +- src/ic-cdk-bindgen/CHANGELOG.md | 5 + src/ic-cdk-bindgen/Cargo.toml | 4 +- src/ic-cdk-bindgen/src/lib.rs | 20 +- src/ic-cdk-macros/CHANGELOG.md | 6 + src/ic-cdk-macros/Cargo.toml | 6 +- src/ic-cdk-timers/CHANGELOG.md | 6 + src/ic-cdk-timers/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 6 + src/ic-cdk/Cargo.toml | 5 +- ...fecycle_functions_should_have_no_return.rs | 0 ...cle_functions_should_have_no_return.stderr | 0 .../tests/compile_fail/no_generic.rs | 0 .../tests/compile_fail/no_generic.stderr | 0 .../no_guard_function_for_lifecycle.rs | 0 .../no_guard_function_for_lifecycle.stderr | 0 .../tests/compile_fail/no_self.rs | 0 .../tests/compile_fail/no_self.stderr | 0 .../tests/compile_fail/only_function.rs | 0 .../tests/compile_fail/only_function.stderr | 0 .../tests/compile_test.rs | 0 .../tests/pass/blank_methods.rs | 0 35 files changed, 401 insertions(+), 442 deletions(-) rename src/{ic-cdk-macros => ic-cdk}/tests/compile_fail/lifecycle_functions_should_have_no_return.rs (100%) rename src/{ic-cdk-macros => ic-cdk}/tests/compile_fail/lifecycle_functions_should_have_no_return.stderr (100%) rename src/{ic-cdk-macros => ic-cdk}/tests/compile_fail/no_generic.rs (100%) rename src/{ic-cdk-macros => ic-cdk}/tests/compile_fail/no_generic.stderr (100%) rename src/{ic-cdk-macros => ic-cdk}/tests/compile_fail/no_guard_function_for_lifecycle.rs (100%) rename src/{ic-cdk-macros => ic-cdk}/tests/compile_fail/no_guard_function_for_lifecycle.stderr (100%) rename src/{ic-cdk-macros => ic-cdk}/tests/compile_fail/no_self.rs (100%) rename src/{ic-cdk-macros => ic-cdk}/tests/compile_fail/no_self.stderr (100%) rename src/{ic-cdk-macros => ic-cdk}/tests/compile_fail/only_function.rs (100%) rename src/{ic-cdk-macros => ic-cdk}/tests/compile_fail/only_function.stderr (100%) rename src/{ic-cdk-macros => ic-cdk}/tests/compile_test.rs (100%) rename src/{ic-cdk-macros => ic-cdk}/tests/pass/blank_methods.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 10f309979..d21a9fe0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,20 +13,21 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", "once_cell", "version_check", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -39,9 +40,9 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arbitrary" -version = "1.3.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" [[package]] name = "arrayvec" @@ -60,13 +61,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.39", ] [[package]] @@ -77,15 +78,15 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "basic-toml" -version = "0.1.1" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e819b667739967cd44d308b8c7b71305d8bb0729ac44a248aa08f33d01950b4" +checksum = "2f2139706359229bfa8f19142ac1155b4b80beafb7a60471ac5dd109d4a19778" dependencies = [ "serde", ] @@ -125,7 +126,7 @@ dependencies = [ "either", "proc-macro2", "quote", - "syn 1.0.107", + "syn 1.0.109", ] [[package]] @@ -151,15 +152,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] @@ -172,46 +173,38 @@ checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "camino" -version = "1.1.2" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" dependencies = [ "serde", ] [[package]] name = "candid" -version = "0.9.6" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88f6eec0ae850e006ef0fe306f362884d370624094ec55a6a26de18b251774be" +checksum = "a2525ab7a58543c132da8c780abe3aa1ba394ddcc1888a4ad2ba4f5100906ebe" dependencies = [ "anyhow", "binread", "byteorder", "candid_derive", - "codespan-reporting", - "convert_case", - "crc32fast", - "data-encoding", "hex", - "lalrpop", - "lalrpop-util", + "ic_principal", "leb128", - "logos", "num-bigint", "num-traits", - "num_enum", "paste", "pretty", "serde", "serde_bytes", - "sha2", "stacker", "thiserror", ] @@ -222,27 +215,46 @@ version = "0.1.2" dependencies = [ "anyhow", "quote", - "syn 1.0.107", + "syn 1.0.109", "wasmtime", ] [[package]] name = "candid_derive" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158403ea38fab5904ae47a5d67eb7047650a91681407f5ccbcbcabc4f4ffb489" +checksum = "970c220da8aa2fa6f7ef5dbbf3ea5b620a59eb3ac107cfb95ae8c6eebdfb7a08" dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.39", +] + +[[package]] +name = "candid_parser" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152b737c1c2681d4ed3359f15016b499f2ddc59aef9fdce0be82f483c11e700" +dependencies = [ + "anyhow", + "candid", + "codespan-reporting", + "convert_case", + "hex", + "lalrpop", + "lalrpop-util", + "logos", + "num-bigint", + "pretty", + "thiserror", ] [[package]] name = "cargo-platform" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +checksum = "e34637b3140142bdf929fb439e8aa4ebad7651ebf7b1080b3930aa16ac1459ff" dependencies = [ "serde", ] @@ -262,11 +274,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -332,9 +345,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -456,16 +469,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -517,9 +520,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "debugid" @@ -579,9 +582,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "ena" @@ -594,9 +597,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", @@ -613,30 +616,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ - "errno-dragonfly", "libc", "windows-sys", ] -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "escargot" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5584ba17d7ab26a8a7284f13e5bd196294dd2f2d79773cff29b9e9edef601a6" +checksum = "768064bd3a0e2bedcba91dc87ace90beea91acc41b6a01a3ca8e9aa8827461bf" dependencies = [ "log", "once_cell", @@ -674,18 +666,18 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -698,9 +690,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -708,15 +700,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -725,38 +717,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.39", ] [[package]] name = "futures-sink" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -785,7 +777,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "debugid", "fxhash", "serde", @@ -794,9 +786,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -804,9 +796,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -820,7 +812,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" dependencies = [ "fallible-iterator", - "indexmap 1.9.2", + "indexmap 1.9.3", "stable_deref_trait", ] @@ -853,9 +845,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "heck" @@ -865,9 +857,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -883,7 +875,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "ic-cdk" -version = "0.11.4" +version = "0.12.0" dependencies = [ "candid", "ic-cdk-macros", @@ -892,13 +884,14 @@ dependencies = [ "serde", "serde_bytes", "slotmap", + "trybuild", ] [[package]] name = "ic-cdk-bindgen" -version = "0.1.1" +version = "0.1.2" dependencies = [ - "candid", + "candid_parser", ] [[package]] @@ -920,21 +913,19 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.8.1" +version = "0.8.2" dependencies = [ "candid", - "ic-cdk", "proc-macro2", "quote", "serde", "serde_tokenstream", - "syn 1.0.107", - "trybuild", + "syn 1.0.109", ] [[package]] name = "ic-cdk-timers" -version = "0.5.1" +version = "0.6.0" dependencies = [ "futures", "ic-cdk", @@ -959,7 +950,7 @@ dependencies = [ [[package]] name = "ic-ledger-types" -version = "0.8.0" +version = "0.9.0" dependencies = [ "candid", "crc32fast", @@ -972,9 +963,9 @@ dependencies = [ [[package]] name = "ic-test-state-machine-client" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cadf6ac4a193a8a45287da67c6c385f118d9266f46d6d98e40fbbd469d3822e" +checksum = "b8e05a81e0cbdf178228d72ace06c60ac7fa99927b49a238f9ccf5ef82eaced6" dependencies = [ "candid", "ciborium", @@ -987,7 +978,23 @@ name = "ic0" version = "0.21.1" dependencies = [ "quote", - "syn 1.0.107", + "syn 1.0.109", +] + +[[package]] +name = "ic_principal" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899a4e8ddada85b91a2fe32b4dc6c0d475ef7bfef3f51cf2aecb26ee4ac4724f" +dependencies = [ + "arbitrary", + "crc32fast", + "data-encoding", + "hex", + "serde", + "serde_bytes", + "sha2", + "thiserror", ] [[package]] @@ -998,9 +1005,9 @@ checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1008,9 +1015,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", @@ -1018,26 +1025,15 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.2", "serde", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys", -] - [[package]] name = "is-terminal" version = "0.4.9" @@ -1045,7 +1041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.4", + "rustix", "windows-sys", ] @@ -1060,15 +1056,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "ittapi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e0d0b7b3b53d92a7e8b80ede3400112a6b8b4c98d1f5b8b16bb787c780582c" +checksum = "25a5c0b993601cad796222ea076565c5d9f337d35592f8622c753724f06d7271" dependencies = [ "anyhow", "ittapi-sys", @@ -1077,18 +1073,18 @@ dependencies = [ [[package]] name = "ittapi-sys" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f8763c96e54e6d6a0dccc2990d8b5e33e3313aaeae6185921a3f4c1614a77c" +checksum = "cb7b5e473765060536a660eed127f758cf1a810c73e49063264959c60d1727d9" dependencies = [ "cc", ] [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" dependencies = [ "libc", ] @@ -1109,7 +1105,7 @@ dependencies = [ "petgraph", "pico-args", "regex", - "regex-syntax 0.7.4", + "regex-syntax 0.7.5", "string_cache", "term", "tiny-keccak", @@ -1139,27 +1135,32 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] -name = "linux-raw-sys" -version = "0.3.8" +name = "libredox" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall", +] [[package]] name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -1167,12 +1168,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "logos" @@ -1194,7 +1192,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.6.29", - "syn 2.0.25", + "syn 2.0.39", ] [[package]] @@ -1217,17 +1215,17 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memfd" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.37.23", + "rustix", ] [[package]] @@ -1245,20 +1243,11 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" -[[package]] -name = "nom8" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" -dependencies = [ - "memchr", -] - [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -1278,44 +1267,13 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.25", -] - [[package]] name = "object" version = "0.31.1" @@ -1324,15 +1282,15 @@ checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "crc32fast", "hashbrown 0.13.2", - "indexmap 1.9.2", + "indexmap 1.9.3", "memchr", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "parking_lot" @@ -1346,37 +1304,37 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall", "smallvec", "windows-targets", ] [[package]] name = "paste" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 1.9.2", + "indexmap 2.1.0", ] [[package]] @@ -1396,9 +1354,9 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1426,30 +1384,20 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "pretty" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "563c9d701c3a31dfffaaf9ce23507ba09cbe0b9125ba176d15e629b0235e9acc" +checksum = "b55c4d17d994b637e2f4daf6e5dc5d660d209d5642377d675d7a1c3ab69fa579" dependencies = [ "arrayvec", "typed-arena", - "unicode-segmentation", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" -dependencies = [ - "once_cell", - "toml_edit", + "unicode-width", ] [[package]] name = "proc-macro2" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -1476,9 +1424,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5907a1b7c277254a8b15170f6e7c97cfa60ee7872a3217663bb81151e48184bb" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1515,9 +1463,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -1525,50 +1473,39 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] [[package]] name = "regalloc2" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b4dcbd3a2ae7fb94b5813fa0e957c6ab51bf5d0a8ee1b69e0c2d0f1e6eb8485" +checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" dependencies = [ "hashbrown 0.13.2", "log", @@ -1579,25 +1516,25 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.7.4", + "regex-syntax 0.8.2", ] [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.8.2", ] [[package]] @@ -1608,9 +1545,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rstest" @@ -1622,7 +1565,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 1.0.107", + "syn 1.0.109", ] [[package]] @@ -1648,72 +1591,58 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys", -] - -[[package]] -name = "rustix" -version = "0.38.4" +version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.3", + "linux-raw-sys", "windows-sys", ] [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.16" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.171" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.9" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ "serde", ] @@ -1730,20 +1659,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.171" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.93" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -1752,20 +1681,20 @@ dependencies = [ [[package]] name = "serde_tokenstream" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "274f512d6748a01e67cbcde5b4307ab2c9d52a98a2b870a980ef0793a351deff" +checksum = "797ba1d80299b264f3aac68ab5d12e5825a561749db4df7cd7c8083900c5d4e9" dependencies = [ "proc-macro2", "serde", - "syn 1.0.107", + "syn 1.0.109", ] [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -1774,15 +1703,15 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -1804,9 +1733,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "sptr" @@ -1848,9 +1777,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -1859,9 +1788,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.25" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -1870,9 +1799,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.11" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" +checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" [[package]] name = "term" @@ -1887,31 +1816,31 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.39", ] [[package]] @@ -1947,28 +1876,11 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_datetime" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" - -[[package]] -name = "toml_edit" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" -dependencies = [ - "indexmap 1.9.2", - "nom8", - "toml_datetime", -] - [[package]] name = "trybuild" -version = "1.0.77" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44da5a6f2164c8e14d3bbc0657d69c5966af9f5f6930d4f600b1f5c4a673413" +checksum = "196a58260a906cedb9bf6d8034b6379d0c11f552416960452f267402ceeddff1" dependencies = [ "basic-toml", "glob", @@ -1987,9 +1899,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicase" @@ -2008,9 +1920,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -2029,9 +1941,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "unicode-xid" @@ -2041,9 +1953,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -2052,9 +1964,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.4.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" [[package]] name = "version_check" @@ -2079,9 +1991,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.32.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba64e81215916eaeb48fee292f29401d69235d62d8b8fd92a7b2844ec5ae5f7" +checksum = "7b09bc5df933a3dabbdb72ae4b6b71be8ae07f58774d5aa41bd20adcd41a235a" dependencies = [ "leb128", ] @@ -2092,7 +2004,7 @@ version = "0.110.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dfcdb72d96f01e6c85b6bf20102e7423bdbaad5c337301bab2bbf253d26413c" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.1.0", "semver", ] @@ -2108,7 +2020,7 @@ dependencies = [ "bumpalo", "cfg-if", "fxprof-processed-profile", - "indexmap 2.0.0", + "indexmap 2.1.0", "libc", "log", "object", @@ -2153,7 +2065,7 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix 0.38.4", + "rustix", "serde", "sha2", "toml", @@ -2170,7 +2082,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.39", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser", @@ -2231,7 +2143,7 @@ dependencies = [ "anyhow", "cranelift-entity", "gimli", - "indexmap 2.0.0", + "indexmap 2.1.0", "log", "object", "serde", @@ -2249,7 +2161,7 @@ checksum = "fc8c8410c03a79073ea06806ccde3da4854c646bd646b3b2707b99b3746c3f70" dependencies = [ "cc", "cfg-if", - "rustix 0.38.4", + "rustix", "wasmtime-asm-macros", "wasmtime-versioned-export-macros", "windows-sys", @@ -2271,7 +2183,7 @@ dependencies = [ "log", "object", "rustc-demangle", - "rustix 0.38.4", + "rustix", "serde", "target-lexicon", "wasmtime-environ", @@ -2289,7 +2201,7 @@ checksum = "aef27ea6c34ef888030d15560037fe7ef27a5609fbbba8e1e3e41dc4245f5bb2" dependencies = [ "object", "once_cell", - "rustix 0.38.4", + "rustix", "wasmtime-versioned-export-macros", ] @@ -2313,7 +2225,7 @@ dependencies = [ "anyhow", "cc", "cfg-if", - "indexmap 2.0.0", + "indexmap 2.1.0", "libc", "log", "mach", @@ -2321,7 +2233,7 @@ dependencies = [ "memoffset", "paste", "rand", - "rustix 0.38.4", + "rustix", "sptr", "wasm-encoder 0.31.1", "wasmtime-asm-macros", @@ -2352,7 +2264,7 @@ checksum = "ca7af9bb3ee875c4907835e607a275d10b04d15623d3aebe01afe8fbd3f85050" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.39", ] [[package]] @@ -2363,27 +2275,27 @@ checksum = "14770d0820f56ba86cdd9987aef97cc3bacbb0394633c37dbfbc61ef29603a71" dependencies = [ "anyhow", "heck", - "indexmap 2.0.0", + "indexmap 2.1.0", "wit-parser", ] [[package]] name = "wast" -version = "64.0.0" +version = "69.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a259b226fd6910225aa7baeba82f9d9933b6d00f2ce1b49b80fa4214328237cc" +checksum = "efa51b5ad1391943d1bfad537e50f28fe938199ee76b115be6bae83802cd5185" dependencies = [ "leb128", "memchr", "unicode-width", - "wasm-encoder 0.32.0", + "wasm-encoder 0.38.0", ] [[package]] name = "wat" -version = "1.0.71" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53253d920ab413fca1c7dc2161d601c79b4fdf631d0ba51dd4343bf9b556c3f6" +checksum = "74a4c2488d058326466e086a43f5d4ea448241a8d0975e3eb0642c0828be1eb3" dependencies = [ "wast", ] @@ -2406,9 +2318,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -2430,9 +2342,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -2445,45 +2357,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "wit-parser" @@ -2493,7 +2405,7 @@ checksum = "541efa2046e544de53a9da1e2f6299e63079840360c9e106f1f8275a97771318" dependencies = [ "anyhow", "id-arena", - "indexmap 2.0.0", + "indexmap 2.1.0", "log", "pulldown-cmark", "semver", @@ -2501,6 +2413,26 @@ dependencies = [ "url", ] +[[package]] +name = "zerocopy" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "zstd" version = "0.11.2+zstd.1.5.2" @@ -2522,11 +2454,10 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +version = "2.0.9+zstd.1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" dependencies = [ "cc", - "libc", "pkg-config", ] diff --git a/Cargo.toml b/Cargo.toml index da46aae85..dbcbf3474 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,11 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.21.1" } -ic-cdk = { path = "src/ic-cdk", version = "0.11.4" } -ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.5.1" } +ic-cdk = { path = "src/ic-cdk", version = "0.12.0" } +ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.6.0" } -candid = "0.9.6" +candid = "0.10" +candid_parser = "0.1.0" futures = "0.3" hex = "0.4" quote = "1" diff --git a/README.md b/README.md index 4a5562967..2ca025e0c 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,8 @@ In Cargo.toml: crate-type = ["cdylib"] [dependencies] -candid = "0.9" # this version is required if you want to define Candid data types -ic-cdk = "0.11" +candid = "0.10" # this version is required if you want to define Candid data types +ic-cdk = "0.12" ``` Then in your rust source code: diff --git a/e2e-tests/canisters/management_caller.rs b/e2e-tests/canisters/management_caller.rs index 5824e99f3..d3a8084c0 100644 --- a/e2e-tests/canisters/management_caller.rs +++ b/e2e-tests/canisters/management_caller.rs @@ -8,9 +8,9 @@ mod main { let arg = CreateCanisterArgument { settings: Some(CanisterSettings { controllers: Some(vec![ic_cdk::id()]), - compute_allocation: Some(0.into()), - memory_allocation: Some(10000.into()), - freezing_threshold: Some(10000.into()), + compute_allocation: Some(0u8.into()), + memory_allocation: Some(10000u16.into()), + freezing_threshold: Some(10000u16.into()), }), }; let canister_id = create_canister(arg, 100_000_000_000u128 / 13) @@ -55,12 +55,12 @@ mod provisional { async fn execute_provisional_methods() { let settings = CanisterSettings { controllers: Some(vec![ic_cdk::caller()]), - compute_allocation: Some(50.into()), - memory_allocation: Some(10000.into()), - freezing_threshold: Some(10000.into()), + compute_allocation: Some(50u8.into()), + memory_allocation: Some(10000u16.into()), + freezing_threshold: Some(10000u16.into()), }; let arg = ProvisionalCreateCanisterWithCyclesArgument { - amount: Some(1_000_000_000.into()), + amount: Some(1_000_000_000u64.into()), settings: Some(settings), }; let canister_id = provisional_create_canister_with_cycles(arg) @@ -71,7 +71,7 @@ mod provisional { let arg = ProvisionalTopUpCanisterArgument { canister_id, - amount: 1_000_000_000.into(), + amount: 1_000_000_000u64.into(), }; provisional_top_up_canister(arg).await.unwrap(); } diff --git a/examples/asset_storage/src/asset_storage_rs/Cargo.toml b/examples/asset_storage/src/asset_storage_rs/Cargo.toml index 1b715d723..38fdb3aa2 100644 --- a/examples/asset_storage/src/asset_storage_rs/Cargo.toml +++ b/examples/asset_storage/src/asset_storage_rs/Cargo.toml @@ -10,5 +10,5 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.9" +candid = "0.10" ic-cdk = { path = "../../../../src/ic-cdk" } diff --git a/examples/chess/src/chess_rs/Cargo.toml b/examples/chess/src/chess_rs/Cargo.toml index d9eba418a..67a29abee 100644 --- a/examples/chess/src/chess_rs/Cargo.toml +++ b/examples/chess/src/chess_rs/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.9.0" +candid = "0.10" ic-cdk = { path = "../../../../src/ic-cdk" } serde = "1.0.111" tanton = "1.0.0" diff --git a/examples/counter/Cargo.toml b/examples/counter/Cargo.toml index eb7dd6932..1b3ee58a8 100644 --- a/examples/counter/Cargo.toml +++ b/examples/counter/Cargo.toml @@ -2,6 +2,6 @@ members = ["src/counter_rs", "src/inter_rs", "src/inter2_rs"] [workspace.dependencies] -candid = "0.9" +candid = "0.10" ic-cdk = { path = "../../src/ic-cdk" } ic-cdk-bindgen = { path = "../../src/ic-cdk-bindgen" } diff --git a/examples/counter/src/counter_rs/lib.rs b/examples/counter/src/counter_rs/lib.rs index 2d0359cd8..ac8c2c8fd 100644 --- a/examples/counter/src/counter_rs/lib.rs +++ b/examples/counter/src/counter_rs/lib.rs @@ -3,7 +3,7 @@ use ic_cdk::{api::call::ManualReply, init, query, update}; use std::cell::{Cell, RefCell}; thread_local! { - static COUNTER: RefCell = RefCell::new(candid::Nat::from(0)); + static COUNTER: RefCell = RefCell::new(candid::Nat::from(0u8)); static OWNER: Cell = Cell::new(Principal::from_slice(&[])); } diff --git a/examples/management_canister/src/caller/Cargo.toml b/examples/management_canister/src/caller/Cargo.toml index 4e57ba562..2da01207d 100644 --- a/examples/management_canister/src/caller/Cargo.toml +++ b/examples/management_canister/src/caller/Cargo.toml @@ -10,6 +10,6 @@ path = "lib.rs" crate-type = ["cdylib"] [dependencies] -candid = "0.9" +candid = "0.10" ic-cdk = { path = "../../../../src/ic-cdk", features = ["transform-closure"] } sha2 = "0.10" diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index edf0209d1..901b0362e 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -44,7 +44,7 @@ mod http_request { .await .unwrap() .0; - assert_eq!(response.status, 200); + assert_eq!(response.status, 200u8); assert_eq!(response.headers.get(0), Some(&header)); } } diff --git a/examples/print/Cargo.toml b/examples/print/Cargo.toml index d0d16f486..05e27f9e5 100644 --- a/examples/print/Cargo.toml +++ b/examples/print/Cargo.toml @@ -3,4 +3,4 @@ members = ["src/print_rs"] [workspace.dependencies] ic-cdk = { path = "../../src/ic-cdk" } -candid = "0.9" +candid = "0.10" diff --git a/examples/profile/Cargo.toml b/examples/profile/Cargo.toml index 6fa009617..1a45abae6 100644 --- a/examples/profile/Cargo.toml +++ b/examples/profile/Cargo.toml @@ -2,7 +2,7 @@ members = ["src/profile_rs", "src/profile_inter_rs"] [workspace.dependencies] -candid = "0.9" +candid = "0.10" ic-cdk = { path = "../../src/ic-cdk" } ic-cdk-bindgen = { path = "../../src/ic-cdk-bindgen" } serde = "1" diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index f03a3b3bb..ad1a801a9 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.9.0] - 2023-11-23 + +### Changed +- Upgrade `ic-cdk` to v0.12 and `candid` to v0.10. + ## [0.8.0] - 2023-09-18 ### Changed diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 74cd797f6..fc23bbff9 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.8.0" +version = "0.9.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-bindgen/CHANGELOG.md b/src/ic-cdk-bindgen/CHANGELOG.md index c600ccc06..7655ddbfc 100644 --- a/src/ic-cdk-bindgen/CHANGELOG.md +++ b/src/ic-cdk-bindgen/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.1.2] - 2023-11-23 + +- Change `candid` dependency to the new `candid_parser` library. + More details here: https://github.com/dfinity/candid/blob/master/Changelog.md#2023-11-16-rust-0100 + ## [0.1.1] - 2023-09-18 - Update `candid` dependency to 0.9.6 which change the Rust bindings. diff --git a/src/ic-cdk-bindgen/Cargo.toml b/src/ic-cdk-bindgen/Cargo.toml index 76e94a59e..e14c27c79 100644 --- a/src/ic-cdk-bindgen/Cargo.toml +++ b/src/ic-cdk-bindgen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-bindgen" -version = "0.1.1" +version = "0.1.2" authors.workspace = true edition.workspace = true license.workspace = true @@ -13,4 +13,4 @@ keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] [dependencies] -candid = { workspace = true, features = ["parser"] } +candid_parser.workspace = true diff --git a/src/ic-cdk-bindgen/src/lib.rs b/src/ic-cdk-bindgen/src/lib.rs index 789b319df..c4fde91fe 100644 --- a/src/ic-cdk-bindgen/src/lib.rs +++ b/src/ic-cdk-bindgen/src/lib.rs @@ -1,4 +1,4 @@ -use candid::{bindings::rust, pretty_check_file, Principal}; +use candid_parser::{bindings::rust, pretty_check_file, Principal}; use std::env; use std::fs; use std::io::Write; @@ -11,6 +11,7 @@ pub struct Config { pub skip_existing_files: bool, pub binding: rust::Config, } + impl Config { pub fn new(canister_name: &str) -> Self { let candid_path_var_name = format!("CANISTER_CANDID_PATH_{}", canister_name); @@ -20,18 +21,19 @@ impl Config { let canister_id = Principal::from_text(env::var(canister_id_var_name).expect("Cannot find canister id")) .unwrap(); + let mut binding = rust::Config::new(); + binding + // User will depend on candid crate directly + .set_candid_crate("candid".to_string()) + .set_canister_id(canister_id) + .set_service_name(canister_name.to_string()) + .set_target(rust::Target::CanisterCall); + Config { canister_name: canister_name.to_string(), candid_path, skip_existing_files: false, - binding: rust::Config { - // User will depend on candid crate directly - candid_crate: "candid".to_string(), - type_attributes: "".to_string(), - canister_id: Some(canister_id), - service_name: canister_name.to_string(), - target: rust::Target::CanisterCall, - }, + binding, } } } diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index 82a803bdf..d260e72b7 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.8.2] - 2023-11-23 + +### Changed + +- Upgrade `candid` to `0.10`. (#448) + ## [0.8.1] - 2023-10-02 ### Fixed diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index d127d4495..44db58b34 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.8.1" # no need to sync with ic-cdk +version = "0.8.2" # no need to sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true @@ -29,7 +29,3 @@ quote.workspace = true serde.workspace = true serde_tokenstream = "0.1.0" syn = { workspace = true, features = ["fold", "full"] } - -[dev-dependencies] -trybuild = "1.0" -ic-cdk.workspace = true diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index 09ddcdbad..000e03e0a 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.6.0] - 2023-11-23 + +### Changed + +- Upgrade `ic-cdk` to v0.12. + ## [0.5.0] - 2023-09-18 ### Changed diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index 9414d0ad0..6a5927271 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.5.1" +version = "0.6.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index aebb0c211..0c3563e40 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.12.0] - 2023-11-23 + +### Changed + +- Upgrade `candid` to `0.10`. (#448) + ## [0.11.4] - 2023-11-20 ### Added diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 02605f4a5..1d4643a90 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.11.4" +version = "0.12.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -22,13 +22,14 @@ include = ["src", "Cargo.toml", "LICENSE", "README.md"] [dependencies] candid.workspace = true ic0.workspace = true -ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.8.0" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.8.2" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true } [dev-dependencies] rstest = "0.12.0" +trybuild = "1.0" [features] transform-closure = ["dep:slotmap"] diff --git a/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_should_have_no_return.rs b/src/ic-cdk/tests/compile_fail/lifecycle_functions_should_have_no_return.rs similarity index 100% rename from src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_should_have_no_return.rs rename to src/ic-cdk/tests/compile_fail/lifecycle_functions_should_have_no_return.rs diff --git a/src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_should_have_no_return.stderr b/src/ic-cdk/tests/compile_fail/lifecycle_functions_should_have_no_return.stderr similarity index 100% rename from src/ic-cdk-macros/tests/compile_fail/lifecycle_functions_should_have_no_return.stderr rename to src/ic-cdk/tests/compile_fail/lifecycle_functions_should_have_no_return.stderr diff --git a/src/ic-cdk-macros/tests/compile_fail/no_generic.rs b/src/ic-cdk/tests/compile_fail/no_generic.rs similarity index 100% rename from src/ic-cdk-macros/tests/compile_fail/no_generic.rs rename to src/ic-cdk/tests/compile_fail/no_generic.rs diff --git a/src/ic-cdk-macros/tests/compile_fail/no_generic.stderr b/src/ic-cdk/tests/compile_fail/no_generic.stderr similarity index 100% rename from src/ic-cdk-macros/tests/compile_fail/no_generic.stderr rename to src/ic-cdk/tests/compile_fail/no_generic.stderr diff --git a/src/ic-cdk-macros/tests/compile_fail/no_guard_function_for_lifecycle.rs b/src/ic-cdk/tests/compile_fail/no_guard_function_for_lifecycle.rs similarity index 100% rename from src/ic-cdk-macros/tests/compile_fail/no_guard_function_for_lifecycle.rs rename to src/ic-cdk/tests/compile_fail/no_guard_function_for_lifecycle.rs diff --git a/src/ic-cdk-macros/tests/compile_fail/no_guard_function_for_lifecycle.stderr b/src/ic-cdk/tests/compile_fail/no_guard_function_for_lifecycle.stderr similarity index 100% rename from src/ic-cdk-macros/tests/compile_fail/no_guard_function_for_lifecycle.stderr rename to src/ic-cdk/tests/compile_fail/no_guard_function_for_lifecycle.stderr diff --git a/src/ic-cdk-macros/tests/compile_fail/no_self.rs b/src/ic-cdk/tests/compile_fail/no_self.rs similarity index 100% rename from src/ic-cdk-macros/tests/compile_fail/no_self.rs rename to src/ic-cdk/tests/compile_fail/no_self.rs diff --git a/src/ic-cdk-macros/tests/compile_fail/no_self.stderr b/src/ic-cdk/tests/compile_fail/no_self.stderr similarity index 100% rename from src/ic-cdk-macros/tests/compile_fail/no_self.stderr rename to src/ic-cdk/tests/compile_fail/no_self.stderr diff --git a/src/ic-cdk-macros/tests/compile_fail/only_function.rs b/src/ic-cdk/tests/compile_fail/only_function.rs similarity index 100% rename from src/ic-cdk-macros/tests/compile_fail/only_function.rs rename to src/ic-cdk/tests/compile_fail/only_function.rs diff --git a/src/ic-cdk-macros/tests/compile_fail/only_function.stderr b/src/ic-cdk/tests/compile_fail/only_function.stderr similarity index 100% rename from src/ic-cdk-macros/tests/compile_fail/only_function.stderr rename to src/ic-cdk/tests/compile_fail/only_function.stderr diff --git a/src/ic-cdk-macros/tests/compile_test.rs b/src/ic-cdk/tests/compile_test.rs similarity index 100% rename from src/ic-cdk-macros/tests/compile_test.rs rename to src/ic-cdk/tests/compile_test.rs diff --git a/src/ic-cdk-macros/tests/pass/blank_methods.rs b/src/ic-cdk/tests/pass/blank_methods.rs similarity index 100% rename from src/ic-cdk-macros/tests/pass/blank_methods.rs rename to src/ic-cdk/tests/pass/blank_methods.rs From 5440fec8136ebec641cf997c9a7670be99af8f5b Mon Sep 17 00:00:00 2001 From: Ulan Degenbaev Date: Thu, 7 Dec 2023 02:09:57 +0100 Subject: [PATCH 185/234] feat: Add `reserved_cycles` and `reserved_cycles_limit` (#449) * feat: Add `reserved_cycles` and `reserved_cycles_limit` This adds the new fields to the API of the management canister: - `reserved_cycles` to `CanisterStatusResponse`. - `reserved_cycles_limit` to `CanisterSettings` and `DefiniteCanisterSettings`. More information: - https://forum.dfinity.org/t/23447 - https://dashboard.internetcomputer.org/proposal/126094 * Add to CHANGELOG and fix errors * changelog details --------- Co-authored-by: Linwei Shang --- e2e-tests/canisters/canister_info.rs | 1 + e2e-tests/canisters/management_caller.rs | 3 +++ src/ic-cdk/CHANGELOG.md | 6 ++++++ src/ic-cdk/src/api/management_canister/main/types.rs | 10 ++++++++++ 4 files changed, 20 insertions(+) diff --git a/e2e-tests/canisters/canister_info.rs b/e2e-tests/canisters/canister_info.rs index 90c19a16a..32700497c 100644 --- a/e2e-tests/canisters/canister_info.rs +++ b/e2e-tests/canisters/canister_info.rs @@ -71,6 +71,7 @@ async fn canister_lifecycle() -> Principal { compute_allocation: None, memory_allocation: None, freezing_threshold: None, + reserved_cycles_limit: None, }, canister_id: canister_id.canister_id, }) diff --git a/e2e-tests/canisters/management_caller.rs b/e2e-tests/canisters/management_caller.rs index d3a8084c0..ecadb4b6b 100644 --- a/e2e-tests/canisters/management_caller.rs +++ b/e2e-tests/canisters/management_caller.rs @@ -11,6 +11,7 @@ mod main { compute_allocation: Some(0u8.into()), memory_allocation: Some(10000u16.into()), freezing_threshold: Some(10000u16.into()), + reserved_cycles_limit: Some(10000u16.into()), }), }; let canister_id = create_canister(arg, 100_000_000_000u128 / 13) @@ -40,6 +41,7 @@ mod main { stop_canister(arg).await.unwrap(); let response = canister_status(arg).await.unwrap().0; assert_eq!(response.status, CanisterStatusType::Stopped); + assert_eq!(response.reserved_cycles.0, 0u128.into()); deposit_cycles(arg, 1_000_000_000_000u128).await.unwrap(); delete_canister(arg).await.unwrap(); let response = raw_rand().await.unwrap().0; @@ -58,6 +60,7 @@ mod provisional { compute_allocation: Some(50u8.into()), memory_allocation: Some(10000u16.into()), freezing_threshold: Some(10000u16.into()), + reserved_cycles_limit: Some(10000u16.into()), }; let arg = ProvisionalCreateCanisterWithCyclesArgument { amount: Some(1_000_000_000u64.into()), diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 0c3563e40..bbc4681c2 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Changed + +- Add "reserved cycles" fields to the management canister API: (#449) + - `reserved_cycles` to `CanisterStatusResponse` + - `reserved_cycles_limit` to `CanisterSettings` and `DefiniteCanisterSettings` + ## [0.12.0] - 2023-11-23 ### Changed diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index 6213b5869..6bec4ddb7 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -19,6 +19,9 @@ pub struct CanisterSettings { pub memory_allocation: Option, /// Must be a number between 0 and 2^64^-1, inclusively, and indicates a length of time in seconds. pub freezing_threshold: Option, + /// Must be a number between 0 and 2^128^-1, inclusively, and indicates the + /// upper limit on cycles in the `reserved_cycles` balance of the canister. + pub reserved_cycles_limit: Option, } /// Argument type of [create_canister](super::create_canister). @@ -162,6 +165,8 @@ pub struct DefiniteCanisterSettings { pub memory_allocation: Nat, /// Freezing threshold. pub freezing_threshold: Nat, + /// Reserved cycles limit. + pub reserved_cycles_limit: Nat, } /// Query statistics, returned by [canister_status](super::canister_status). @@ -194,6 +199,11 @@ pub struct CanisterStatusResponse { pub idle_cycles_burned_per_day: Nat, /// Query statistics pub query_stats: QueryStats, + /// The reserved cycles balance of the canister. + /// These are cycles that are reserved by the resource reservation mechanism + /// on storage allocation. See also the `reserved_cycles_limit` parameter in + /// canister settings. + pub reserved_cycles: Nat, } /// Details about a canister change initiated by a user. From fbacb220f9e8ce913e3cb79cbd8191988a3c8c25 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Wed, 13 Dec 2023 10:41:58 -0800 Subject: [PATCH 186/234] feat: "hidden" attribute to exclude exporting method in export_candid!() (#451) * feat: no_export attribute to exclude exporting method in did file * changelog * test: example & macro compile * rename to hidden * typo --------- Co-authored-by: Linwei Shang --- Cargo.lock | 2 +- examples/counter/.gitignore | 2 ++ examples/counter/dfx.json | 5 +++- examples/counter/src/counter_rs/counter.did | 5 ---- examples/counter/src/counter_rs/lib.rs | 6 +++++ examples/counter/tests/basic.bats | 6 +++++ src/ic-cdk-macros/CHANGELOG.md | 6 +++++ src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-macros/src/export.rs | 27 +++++++++++++-------- src/ic-cdk-macros/src/lib.rs | 24 ++++++++++++++++++ src/ic-cdk/Cargo.toml | 2 +- src/ic-cdk/tests/pass/blank_methods.rs | 6 +++++ 12 files changed, 74 insertions(+), 19 deletions(-) delete mode 100644 examples/counter/src/counter_rs/counter.did diff --git a/Cargo.lock b/Cargo.lock index d21a9fe0f..bc86495f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -913,7 +913,7 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.8.2" +version = "0.8.3" dependencies = [ "candid", "proc-macro2", diff --git a/examples/counter/.gitignore b/examples/counter/.gitignore index 47995179f..958d33e64 100644 --- a/examples/counter/.gitignore +++ b/examples/counter/.gitignore @@ -1,3 +1,5 @@ .dfx/ canisters/ target/ + +src/counter_rs/counter.did diff --git a/examples/counter/dfx.json b/examples/counter/dfx.json index 0622ffc49..02c890da7 100644 --- a/examples/counter/dfx.json +++ b/examples/counter/dfx.json @@ -5,7 +5,10 @@ "type": "custom", "candid": "src/counter_rs/counter.did", "wasm": "target/wasm32-unknown-unknown/release/counter_rs-opt.wasm", - "build": "sh ../build.sh counter counter_rs" + "build": [ + "sh ../build.sh counter counter_rs", + "cp /tmp/a.did src/counter_rs/counter.did" + ] }, "counter_mo": { "type": "motoko", diff --git a/examples/counter/src/counter_rs/counter.did b/examples/counter/src/counter_rs/counter.did deleted file mode 100644 index 9c02a15a7..000000000 --- a/examples/counter/src/counter_rs/counter.did +++ /dev/null @@ -1,5 +0,0 @@ -service : { - "inc": () -> (); - "read": () -> (nat) query; - "write": (nat) -> (); -} diff --git a/examples/counter/src/counter_rs/lib.rs b/examples/counter/src/counter_rs/lib.rs index ac8c2c8fd..e0be90142 100644 --- a/examples/counter/src/counter_rs/lib.rs +++ b/examples/counter/src/counter_rs/lib.rs @@ -28,4 +28,10 @@ fn write(input: candid::Nat) { COUNTER.with(|counter| *counter.borrow_mut() = input); } +#[update(hidden = true)] +fn update_hidden() {} + +#[query(hidden = true)] +fn query_hidden() {} + ic_cdk::export_candid!(); diff --git a/examples/counter/tests/basic.bats b/examples/counter/tests/basic.bats index 83c1f75e3..b64255c16 100644 --- a/examples/counter/tests/basic.bats +++ b/examples/counter/tests/basic.bats @@ -56,3 +56,9 @@ teardown() { run dfx canister call counter_rs read [ "$output" == '(6 : nat)' ] } + +@test "counter_rs generated Candid excludes hidden methods" { + dfx build --check counter_rs + ! grep -q update_hidden src/counter_rs/counter.did + ! grep -q query_hidden src/counter_rs/counter.did +} diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index d260e72b7..4f9ea7b86 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.8.2] - 2023-12-13 + +### Added + +- `#[query(hidden = true)]`/`#[update(hidden = true)]` attribute to exclude exporting certain endpoints in Candid generated by `export_candid!()`. (#451) + ## [0.8.2] - 2023-11-23 ### Changed diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 44db58b34..ac360399a 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.8.2" # no need to sync with ic-cdk +version = "0.8.3" # no need to sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index f6b2440e5..868a457ec 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -14,6 +14,8 @@ struct ExportAttributes { pub manual_reply: bool, #[serde(default)] pub composite: bool, + #[serde(default)] + pub hidden: bool, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -198,18 +200,23 @@ fn dfn_macro( quote! {} }; - let candid_method_attr = match method { - MethodType::Query if attrs.composite => { - quote! { #[::candid::candid_method(composite_query, rename = #function_name)] } - } - MethodType::Query => quote! { #[::candid::candid_method(query, rename = #function_name)] }, - MethodType::Update => { - quote! { #[::candid::candid_method(update, rename = #function_name)] } + let candid_method_attr = if attrs.hidden { + quote! {} + } else { + match method { + MethodType::Query if attrs.composite => { + quote! { #[::candid::candid_method(composite_query, rename = #function_name)] } + } + MethodType::Query => { + quote! { #[::candid::candid_method(query, rename = #function_name)] } + } + MethodType::Update => { + quote! { #[::candid::candid_method(update, rename = #function_name)] } + } + MethodType::Init => quote! { #[::candid::candid_method(init)] }, + _ => quote! {}, } - MethodType::Init => quote! { #[::candid::candid_method(init)] }, - _ => quote! {}, }; - let item = quote! { #candid_method_attr #item diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index 56e04ea4a..a4a25d58c 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -110,6 +110,18 @@ pub fn export_candid(input: TokenStream) -> TokenStream { /// } /// ``` /// +/// If you want to hide this method in the Candid generated by [export_candid], +/// you will need to set `hidden` to `true`. The entry point still exists in the canister. +/// +/// ```rust +/// # use ic_cdk::query; +/// #[query(hidden = true)] +/// fn query_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// /// You can specify a guard function to be executed before the query function. /// When the guard function returns an error, the query function will not proceed. /// @@ -186,6 +198,18 @@ pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { /// } /// ``` /// +/// If you want to hide this method in the Candid generated by [export_candid], +/// you will need to set `hidden` to `true`. The entry point still exists in the canister. +/// +/// ```rust +/// # use ic_cdk::update; +/// #[update(hidden = true)] +/// fn update_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// /// You can specify a guard function to be executed before the update function. /// When the guard function returns an error, the update function will not proceed. /// diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 1d4643a90..42bc64d90 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -22,7 +22,7 @@ include = ["src", "Cargo.toml", "LICENSE", "README.md"] [dependencies] candid.workspace = true ic0.workspace = true -ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.8.2" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.8.3" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true } diff --git a/src/ic-cdk/tests/pass/blank_methods.rs b/src/ic-cdk/tests/pass/blank_methods.rs index 9b9e502fd..bd3922901 100644 --- a/src/ic-cdk/tests/pass/blank_methods.rs +++ b/src/ic-cdk/tests/pass/blank_methods.rs @@ -12,9 +12,15 @@ fn post_upgrade() {} #[update] fn update() {} +#[update(hidden = true)] +fn update_hidden() {} + #[query] fn query() {} +#[query(hidden = true)] +fn query_hidden() {} + #[query(composite = true)] fn composite_query() {} From c01fc1741eb3fec2df0bb4e5c5ff54fa027a6091 Mon Sep 17 00:00:00 2001 From: Stefan Kaestle Date: Thu, 11 Jan 2024 09:32:22 +0100 Subject: [PATCH 187/234] fix: query stats: make members public (#453) --- src/ic-cdk/src/api/management_canister/main/types.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index 6bec4ddb7..a76547769 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -174,10 +174,14 @@ pub struct DefiniteCanisterSettings { CandidType, Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, )] pub struct QueryStats { - num_calls_total: candid::Nat, - num_instructions_total: candid::Nat, - request_payload_bytes_total: candid::Nat, - response_payload_bytes_total: candid::Nat, + /// Total number of query calls. + pub num_calls_total: candid::Nat, + /// Total number of instructions executed by query calls. + pub num_instructions_total: candid::Nat, + /// Total number of payload bytes use for query call requests. + pub request_payload_bytes_total: candid::Nat, + /// Total number of payload bytes use for query call responses. + pub response_payload_bytes_total: candid::Nat, } /// Argument type of [canister_status](super::canister_status). From 1da310b58c3bcfa8f946da1d14bd49ee7c11a801 Mon Sep 17 00:00:00 2001 From: Levi <31335633+levifeldman@users.noreply.github.com> Date: Fri, 12 Jan 2024 16:49:12 -0500 Subject: [PATCH 188/234] feat: Serde Serialize and Deserialize traits for the RbTree in the ic-certified-map crate. (#399) * This change adds the serde Serialize and Deserialize traits to the RbTree. * Manual implementation of Serialize and Deserialize for the RbTree. * replace 'static lifetime bounds with a custom lifetime 't. * Added bincode serialization in the serde test. * CandidType for the RbTree. * update CHANGELOG with CandidType. --- library/ic-certified-map/CHANGELOG.md | 3 + library/ic-certified-map/Cargo.toml | 3 +- library/ic-certified-map/src/rbtree.rs | 166 +++++++++++++++----- library/ic-certified-map/src/rbtree/test.rs | 23 +++ 4 files changed, 154 insertions(+), 41 deletions(-) diff --git a/library/ic-certified-map/CHANGELOG.md b/library/ic-certified-map/CHANGELOG.md index e47783d12..fab88d089 100644 --- a/library/ic-certified-map/CHANGELOG.md +++ b/library/ic-certified-map/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added +- Implement CandidType, Serialize, and Deserialize for the RbTree. + ## [0.4.0] - 2023-07-13 ### Changed diff --git a/library/ic-certified-map/Cargo.toml b/library/ic-certified-map/Cargo.toml index c72a6e3bf..331b29c0b 100644 --- a/library/ic-certified-map/Cargo.toml +++ b/library/ic-certified-map/Cargo.toml @@ -22,9 +22,10 @@ include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"] serde.workspace = true serde_bytes.workspace = true sha2.workspace = true +candid.workspace = true [dev-dependencies] hex.workspace = true serde_cbor = "0.11" ic-cdk.workspace = true -candid.workspace = true +bincode = "1.3.3" diff --git a/library/ic-certified-map/src/rbtree.rs b/library/ic-certified-map/src/rbtree.rs index 6878c6efb..cccbd9668 100644 --- a/library/ic-certified-map/src/rbtree.rs +++ b/library/ic-certified-map/src/rbtree.rs @@ -55,7 +55,7 @@ impl AsHashTree for Hash { } } -impl, V: AsHashTree + 'static> AsHashTree for RbTree { +impl<'t, K: 't + AsRef<[u8]>, V: AsHashTree + 't> AsHashTree for RbTree { fn root_hash(&self) -> Hash { match self.root.as_ref() { None => Empty.reconstruct(), @@ -102,7 +102,7 @@ struct Node { subtree_hash: Hash, } -impl, V: AsHashTree + 'static> Node { +impl<'t, K: 't + AsRef<[u8]>, V: AsHashTree + 't> Node { fn new(key: K, value: V) -> Box> { let value_hash = value.root_hash(); let data_hash = labeled_hash(key.as_ref(), &value_hash); @@ -274,47 +274,47 @@ pub struct RbTree { root: NodeRef, } -impl PartialEq for RbTree +impl<'t, K, V> PartialEq for RbTree where - K: 'static + AsRef<[u8]> + PartialEq, - V: 'static + AsHashTree + PartialEq, + K: 't + AsRef<[u8]> + PartialEq, + V: 't + AsHashTree + PartialEq, { fn eq(&self, other: &Self) -> bool { self.iter().eq(other.iter()) } } -impl Eq for RbTree +impl<'t, K, V> Eq for RbTree where - K: 'static + AsRef<[u8]> + Eq, - V: 'static + AsHashTree + Eq, + K: 't + AsRef<[u8]> + Eq, + V: 't + AsHashTree + Eq, { } -impl PartialOrd for RbTree +impl<'t, K, V> PartialOrd for RbTree where - K: 'static + AsRef<[u8]> + PartialOrd, - V: 'static + AsHashTree + PartialOrd, + K: 't + AsRef<[u8]> + PartialOrd, + V: 't + AsHashTree + PartialOrd, { fn partial_cmp(&self, other: &Self) -> Option { self.iter().partial_cmp(other.iter()) } } -impl Ord for RbTree +impl<'t, K, V> Ord for RbTree where - K: 'static + AsRef<[u8]> + Ord, - V: 'static + AsHashTree + Ord, + K: 't + AsRef<[u8]> + Ord, + V: 't + AsHashTree + Ord, { fn cmp(&self, other: &Self) -> Ordering { self.iter().cmp(other.iter()) } } -impl std::iter::FromIterator<(K, V)> for RbTree +impl<'t, K, V> std::iter::FromIterator<(K, V)> for RbTree where - K: 'static + AsRef<[u8]>, - V: 'static + AsHashTree, + K: 't + AsRef<[u8]>, + V: 't + AsHashTree, { fn from_iter(iter: T) -> Self where @@ -328,10 +328,10 @@ where } } -impl std::fmt::Debug for RbTree +impl<'t, K, V> std::fmt::Debug for RbTree where - K: 'static + AsRef<[u8]> + std::fmt::Debug, - V: 'static + AsHashTree + std::fmt::Debug, + K: 't + AsRef<[u8]> + std::fmt::Debug, + V: 't + AsHashTree + std::fmt::Debug, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "[")?; @@ -359,7 +359,7 @@ impl RbTree { } } -impl, V: AsHashTree + 'static> RbTree { +impl<'t, K: 't + AsRef<[u8]>, V: AsHashTree + 't> RbTree { /// Looks up the key in the map and returns the associated value, if there is one. pub fn get(&self, key: &[u8]) -> Option<&V> { let mut root = self.root.as_ref(); @@ -375,7 +375,7 @@ impl, V: AsHashTree + 'static> RbTree { /// Updates the value corresponding to the specified key. pub fn modify(&mut self, key: &[u8], f: impl FnOnce(&mut V)) { - fn go, V: AsHashTree + 'static>( + fn go<'t, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( h: &mut NodeRef, k: &[u8], f: impl FnOnce(&mut V), @@ -506,7 +506,7 @@ impl, V: AsHashTree + 'static> RbTree { lo: KeyBound<'a>, f: fn(&'a Node) -> HashTree<'a>, ) -> HashTree<'a> { - fn go<'a, K: 'static + AsRef<[u8]>, V: AsHashTree + 'static>( + fn go<'a, 't, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( n: &'a NodeRef, lo: KeyBound<'a>, f: fn(&'a Node) -> HashTree<'a>, @@ -543,7 +543,7 @@ impl, V: AsHashTree + 'static> RbTree { hi: KeyBound<'a>, f: fn(&'a Node) -> HashTree<'a>, ) -> HashTree<'a> { - fn go<'a, K: 'static + AsRef<[u8]>, V: AsHashTree + 'static>( + fn go<'a, 't, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( n: &'a NodeRef, hi: KeyBound<'a>, f: fn(&'a Node) -> HashTree<'a>, @@ -587,7 +587,7 @@ impl, V: AsHashTree + 'static> RbTree { lo.as_ref(), hi.as_ref() ); - fn go<'a, K: 'static + AsRef<[u8]>, V: AsHashTree + 'static>( + fn go<'a, 't, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( n: &'a NodeRef, lo: KeyBound<'a>, hi: KeyBound<'a>, @@ -645,7 +645,7 @@ impl, V: AsHashTree + 'static> RbTree { } fn lower_bound(&self, key: &[u8]) -> Option> { - fn go<'a, K: 'static + AsRef<[u8]>, V>( + fn go<'a, 't, K: 't + AsRef<[u8]>, V>( n: &'a NodeRef, key: &[u8], ) -> Option> { @@ -662,7 +662,7 @@ impl, V: AsHashTree + 'static> RbTree { } fn upper_bound(&self, key: &[u8]) -> Option> { - fn go<'a, K: 'static + AsRef<[u8]>, V>( + fn go<'a, 't, K: 't + AsRef<[u8]>, V>( n: &'a NodeRef, key: &[u8], ) -> Option> { @@ -685,7 +685,7 @@ impl, V: AsHashTree + 'static> RbTree { } &x[0..p.len()] == p } - fn go<'a, K: 'static + AsRef<[u8]>, V>( + fn go<'a, 't, K: 't + AsRef<[u8]>, V>( n: &'a NodeRef, prefix: &[u8], ) -> Option> { @@ -706,7 +706,7 @@ impl, V: AsHashTree + 'static> RbTree { key: &[u8], f: impl FnOnce(&'a V) -> HashTree<'a>, ) -> Option> { - fn go<'a, K: 'static + AsRef<[u8]>, V: AsHashTree + 'static>( + fn go<'a, 't, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( n: &'a NodeRef, key: &[u8], f: impl FnOnce(&'a V) -> HashTree<'a>, @@ -740,7 +740,7 @@ impl, V: AsHashTree + 'static> RbTree { /// Inserts a key-value entry into the map. pub fn insert(&mut self, key: K, value: V) { - fn go, V: AsHashTree + 'static>( + fn go<'t, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( h: NodeRef, k: K, v: V, @@ -778,7 +778,7 @@ impl, V: AsHashTree + 'static> RbTree { /// Removes the specified key from the map. pub fn delete(&mut self, key: &[u8]) { - fn move_red_left, V: AsHashTree + 'static>( + fn move_red_left<'t, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( mut h: Box>, ) -> Box> { flip_colors(&mut h); @@ -790,7 +790,7 @@ impl, V: AsHashTree + 'static> RbTree { h } - fn move_red_right, V: AsHashTree + 'static>( + fn move_red_right<'t, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( mut h: Box>, ) -> Box> { flip_colors(&mut h); @@ -802,7 +802,7 @@ impl, V: AsHashTree + 'static> RbTree { } #[inline] - fn min, V: AsHashTree + 'static>( + fn min<'t, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( mut h: &mut Box>, ) -> &mut Box> { while h.left.is_some() { @@ -811,7 +811,7 @@ impl, V: AsHashTree + 'static> RbTree { h } - fn delete_min, V: AsHashTree + 'static>( + fn delete_min<'t, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( mut h: Box>, ) -> NodeRef { if h.left.is_none() { @@ -827,7 +827,7 @@ impl, V: AsHashTree + 'static> RbTree { Some(balance(h)) } - fn go, V: AsHashTree + 'static>( + fn go<'t, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( mut h: Box>, key: &[u8], ) -> NodeRef { @@ -888,6 +888,94 @@ impl, V: AsHashTree + 'static> RbTree { } } +use candid::CandidType; + +impl<'t, K, V> CandidType for RbTree +where + K: CandidType + AsRef<[u8]> + 't, + V: CandidType + AsHashTree + 't, +{ + fn _ty() -> candid::types::internal::Type { + as CandidType>::_ty() + } + fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> { + let collect_as_vec = self.iter().collect::>(); + as CandidType>::idl_serialize(&collect_as_vec, serializer) + } +} + +use serde::{ + de::{Deserialize, Deserializer, MapAccess, Visitor}, + ser::{Serialize, SerializeMap, Serializer}, +}; +use std::marker::PhantomData; + +impl<'t, K, V> Serialize for RbTree +where + K: Serialize + AsRef<[u8]> + 't, + V: Serialize + AsHashTree + 't, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(self.iter().count()))?; + for (k, v) in self.iter() { + map.serialize_entry(k, v)?; + } + map.end() + } +} + +// The PhantomData keeps the compiler from complaining about unused generic type parameters. +struct RbTreeSerdeVisitor { + marker: PhantomData RbTree>, +} + +impl RbTreeSerdeVisitor { + fn new() -> Self { + RbTreeSerdeVisitor { + marker: PhantomData, + } + } +} + +impl<'de, 't, K, V> Visitor<'de> for RbTreeSerdeVisitor +where + K: Deserialize<'de> + AsRef<[u8]> + 't, + V: Deserialize<'de> + AsHashTree + 't, +{ + type Value = RbTree; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a map") + } + + fn visit_map(self, mut access: M) -> Result + where + M: MapAccess<'de>, + { + let mut t = RbTree::::new(); + while let Some((key, value)) = access.next_entry()? { + t.insert(key, value); + } + Ok(t) + } +} + +impl<'de, 't, K, V> Deserialize<'de> for RbTree +where + K: Deserialize<'de> + AsRef<[u8]> + 't, + V: Deserialize<'de> + AsHashTree + 't, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(RbTreeSerdeVisitor::new()) + } +} + fn three_way_fork<'a>(l: HashTree<'a>, m: HashTree<'a>, r: HashTree<'a>) -> HashTree<'a> { match (l, m, r) { (Empty, m, Empty) => m, @@ -906,9 +994,7 @@ fn is_red(x: &NodeRef) -> bool { x.as_ref().map(|h| h.color == Color::Red).unwrap_or(false) } -fn balance + 'static, V: AsHashTree + 'static>( - mut h: Box>, -) -> Box> { +fn balance<'t, K: AsRef<[u8]> + 't, V: AsHashTree + 't>(mut h: Box>) -> Box> { if is_red(&h.right) && !is_red(&h.left) { h = rotate_left(h); } @@ -922,7 +1008,7 @@ fn balance + 'static, V: AsHashTree + 'static>( } /// Make a left-leaning link lean to the right. -fn rotate_right, V: AsHashTree + 'static>( +fn rotate_right<'t, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( mut h: Box>, ) -> Box> { debug_assert!(is_red(&h.left)); @@ -939,7 +1025,7 @@ fn rotate_right, V: AsHashTree + 'static>( x } -fn rotate_left, V: AsHashTree + 'static>( +fn rotate_left<'t, K: 't + AsRef<[u8]>, V: AsHashTree + 't>( mut h: Box>, ) -> Box> { debug_assert!(is_red(&h.right)); diff --git a/library/ic-certified-map/src/rbtree/test.rs b/library/ic-certified-map/src/rbtree/test.rs index 206906757..40fa6a13f 100644 --- a/library/ic-certified-map/src/rbtree/test.rs +++ b/library/ic-certified-map/src/rbtree/test.rs @@ -375,3 +375,26 @@ fn test_ordering() { assert_eq!(t1.cmp(&t3), Greater); assert_eq!(t1.cmp(&t4), Less); } + +#[test] +fn test_serde_serialize_and_deserialize() { + type Tree<'a> = RbTree<&'a str, Hash>; + let t1: Tree<'_> = Tree::from_iter([("hi", [1; 32]), ("hello", [2; 32]), ("world", [3; 32])]); + + // cbor test + let mut b: Vec = Vec::new(); + serde_cbor::to_writer(&mut b, &t1).unwrap(); + let t2: Tree<'_> = serde_cbor::from_slice(&b[..]).unwrap(); + assert_eq!(t1, t2); + + // bincode test + use bincode::Options; + let b = bincode::options().serialize(&t1).unwrap(); + let t3: Tree<'_> = bincode::options().deserialize(&b).unwrap(); + assert_eq!(t1, t3); + + // candid test + let b = candid::encode_one(&t1).unwrap(); + let t4: Tree<'_> = candid::decode_one(&b).unwrap(); + assert_eq!(t1, t4); +} From edcbe3af0ac6031facc86d5ea40eeb2def66327e Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 12 Jan 2024 17:13:52 -0500 Subject: [PATCH 189/234] docs: more informative README and call* methods (#454) * docs: ic-cdk README * docs: README for macros * docs: call* methods * chore: bump version and changelog * fix: grammar and format * fix: a leftover lock change from other PR --- Cargo.lock | 6 +- Cargo.toml | 2 +- README.md | 9 +-- src/ic-cdk-macros/CHANGELOG.md | 8 ++- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-macros/README.md | 31 ++++++-- src/ic-cdk-macros/src/lib.rs | 27 +------ src/ic-cdk/CHANGELOG.md | 7 ++ src/ic-cdk/Cargo.toml | 5 +- src/ic-cdk/README.md | 79 +++++++++++++++++++-- src/ic-cdk/src/api/call.rs | 126 +++++++++++++++++++++++++++++---- src/ic-cdk/src/lib.rs | 10 ++- 12 files changed, 247 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc86495f2..bc0817a93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -875,8 +875,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "ic-cdk" -version = "0.12.0" +version = "0.12.1" dependencies = [ + "anyhow", "candid", "ic-cdk-macros", "ic0", @@ -913,7 +914,7 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.8.3" +version = "0.8.4" dependencies = [ "candid", "proc-macro2", @@ -939,6 +940,7 @@ dependencies = [ name = "ic-certified-map" version = "0.4.0" dependencies = [ + "bincode", "candid", "hex", "ic-cdk", diff --git a/Cargo.toml b/Cargo.toml index dbcbf3474..f7f2c2a5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.21.1" } -ic-cdk = { path = "src/ic-cdk", version = "0.12.0" } +ic-cdk = { path = "src/ic-cdk", version = "0.12.1" } ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.6.0" } candid = "0.10" diff --git a/README.md b/README.md index 2ca025e0c..cff587ef6 100644 --- a/README.md +++ b/README.md @@ -52,16 +52,17 @@ In Cargo.toml: crate-type = ["cdylib"] [dependencies] -candid = "0.10" # this version is required if you want to define Candid data types ic-cdk = "0.12" +# Only necessary if you want to define Candid data types +candid = "0.10" ``` -Then in your rust source code: +Then in Rust source code: ```rust #[ic_cdk::query] -fn print() { - ic_cdk::print("Hello World from DFINITY!"); +fn hello() -> String{ + "world".to_string() } ``` diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index 4f9ea7b86..f13441383 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,7 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -## [0.8.2] - 2023-12-13 +## [0.8.4] - 2024-01-12 + +### Fixed + +- The README file is now more informative and used as the front page of the doc site. + +## [0.8.3] - 2023-12-13 ### Added diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index ac360399a..82915a14f 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.8.3" # no need to sync with ic-cdk +version = "0.8.4" # no need to sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-macros/README.md b/src/ic-cdk-macros/README.md index 95c912264..c7dd633dc 100644 --- a/src/ic-cdk-macros/README.md +++ b/src/ic-cdk-macros/README.md @@ -1,11 +1,32 @@ -# ic-cdk-macros - -**Internet Computer Canister Development Kit** - [![Documentation](https://docs.rs/ic-cdk-macros/badge.svg)](https://docs.rs/ic-cdk-macros/) [![Crates.io](https://img.shields.io/crates/v/ic-cdk-macros.svg)](https://crates.io/crates/ic-cdk-macros) [![License](https://img.shields.io/crates/l/ic-cdk-macros.svg)](https://github.com/dfinity/cdk-rs/blob/main/src/ic-cdk-macros/LICENSE) [![Downloads](https://img.shields.io/crates/d/ic-cdk-macros.svg)](https://crates.io/crates/ic-cdk-macros) [![CI](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml) -This crate provides attribute macros, with which you can annotate regular rust functions to be public interfaces of a canister. +# ic-cdk-macros + +This crate provides a set of macros to facilitate canister development. + +The macros fall into two categories: + +* To register functions as canister entry points +* To export Candid definitions + +## Register functions as canister entry points + +These macros are directly related to the [Internet Computer Specification](https://internetcomputer.org/docs/current/references/ic-interface-spec#entry-points). + +* [`init`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.init.html) +* [`pre_upgrade`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.pre_upgrade.html) +* [`post_upgrade`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.post_upgrade.html) +* [`inspect_message`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.inspect_message.html) +* [`heartbeat`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.heartbeat.html) +* [`update`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.update.html) +* [`query`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.query.html) + +## Export Candid definitions + +* [`export_candid`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/macro.export_candid.html) + +Check [Generating Candid files for Rust canisters](https://internetcomputer.org/docs/current/developer-docs/backend/candid/generating-candid/) for more details. diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index a4a25d58c..0aa73b91f 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -1,25 +1,4 @@ -//! This crate provide a set of attribute macros to facilitate canister development. -//! -//! The macros fall into two categories: -//! * To register functions as canister entry points -//! * To export candid definitions -//! -//! ## Register functions as canister entry points -//! -//! These macros are directly related to the [Internet Computer Specification](https://smartcontracts.org/docs/interface-spec/index.html#_entry_points). -//! -//! * [`init`](attr.init.html) -//! * [`pre_upgrade`](attr.pre_upgrade.html) -//! * [`post_upgrade`](attr.post_upgrade.html) -//! * [`inspect_message`](attr.inspect_message.html) -//! * [`heartbeat`](attr.heartbeat.html) -//! * [`update`](attr.update.html) -//! * [`query`](attr.query.html) -//! -//! ## Export candid definitions -//! -//! * [`export_candid`](attr.export_candid.html) - +#![doc = include_str!("../README.md")] #![warn( elided_lifetimes_in_paths, missing_debug_implementations, @@ -110,7 +89,7 @@ pub fn export_candid(input: TokenStream) -> TokenStream { /// } /// ``` /// -/// If you want to hide this method in the Candid generated by [export_candid], +/// If you want to hide this method in the Candid generated by [export_candid!], /// you will need to set `hidden` to `true`. The entry point still exists in the canister. /// /// ```rust @@ -198,7 +177,7 @@ pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { /// } /// ``` /// -/// If you want to hide this method in the Candid generated by [export_candid], +/// If you want to hide this method in the Candid generated by [export_candid!], /// you will need to set `hidden` to `true`. The entry point still exists in the canister. /// /// ```rust diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index bbc4681c2..d1f4b6954 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,12 +6,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.12.1] - 2024-01-12 + ### Changed - Add "reserved cycles" fields to the management canister API: (#449) - `reserved_cycles` to `CanisterStatusResponse` - `reserved_cycles_limit` to `CanisterSettings` and `DefiniteCanisterSettings` +### Fixed + +- The README file is now more informative and used as the front page of the doc site. +- The `call*` methods are documented with examples and notes. + ## [0.12.0] - 2023-11-23 ### Changed diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 42bc64d90..22d7ae18a 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.12.0" +version = "0.12.1" authors.workspace = true edition.workspace = true license.workspace = true @@ -22,12 +22,13 @@ include = ["src", "Cargo.toml", "LICENSE", "README.md"] [dependencies] candid.workspace = true ic0.workspace = true -ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.8.3" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.8.4" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true } [dev-dependencies] +anyhow = "1" rstest = "0.12.0" trybuild = "1.0" diff --git a/src/ic-cdk/README.md b/src/ic-cdk/README.md index e2687ee9d..d3ec7ea20 100644 --- a/src/ic-cdk/README.md +++ b/src/ic-cdk/README.md @@ -1,9 +1,80 @@ -# ic-cdk - -**Internet Computer Canister Development Kit** - [![Documentation](https://docs.rs/ic-cdk/badge.svg)](https://docs.rs/ic-cdk/) [![Crates.io](https://img.shields.io/crates/v/ic-cdk.svg)](https://crates.io/crates/ic-cdk) [![License](https://img.shields.io/crates/l/ic-cdk.svg)](https://github.com/dfinity/cdk-rs/blob/main/src/ic-cdk/LICENSE) [![Downloads](https://img.shields.io/crates/d/ic-cdk.svg)](https://crates.io/crates/ic-cdk) [![CI](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/dfinity/cdk-rs/actions/workflows/ci.yml) + +# ic-cdk + +Canister Developer Kit for the Internet Computer. + +## Background + +On the Internet Computer, smart contracts come in the form of canisters which are WebAssembly modules. + +Canisters expose entry points which can be called both by other canisters and by parties external to the IC. + +This library aims to provide a Rust-ergonomic abstraction to implement Canister entry points. + +## Using `ic-cdk` + +In Cargo.toml: + +```toml +[lib] +crate-type = ["cdylib"] + +[dependencies] +ic-cdk = "0.12" +# Only necessary if you want to define Candid data types +candid = "0.10" +``` + +Then in Rust source code: + +```rust +#[ic_cdk::query] +fn hello() -> String { + "world".to_string() +} +``` + +This will register a **query** entry point named `hello`. + +## Macros + +This library re-exports macros defined in `ic-cdk-macros` crate. + +The macros fall into two categories: + +* To register functions as canister entry points +* To export Candid definitions + +### Register functions as canister entry points + +These macros are directly related to the [Internet Computer Specification](https://internetcomputer.org/docs/current/references/ic-interface-spec#entry-points). + +* [`init`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.init.html) +* [`pre_upgrade`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.pre_upgrade.html) +* [`post_upgrade`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.post_upgrade.html) +* [`inspect_message`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.inspect_message.html) +* [`heartbeat`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.heartbeat.html) +* [`update`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.update.html) +* [`query`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.query.html) + +### Export Candid definitions + +* [`export_candid`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/macro.export_candid.html) + +Check [Generating Candid files for Rust canisters](https://internetcomputer.org/docs/current/developer-docs/backend/candid/generating-candid/) for more details. + +## More examples + +* [Basic examples](https://github.com/dfinity/cdk-rs/tree/main/examples): Demonstrate usage of `ic-cdk` API. +* [Comprehensive examples](https://github.com/dfinity/examples/tree/master/rust): Illustrate how to build useful Rust canisters. + +## Manage Data Structure in Stable Memory + +Using the `ic_cdk::storage::{stable_save, stable_restore}` API is easy but it doesn't scale well. + +[`ic-stable-structures`](https://crates.io/crates/ic-stable-structures) is recommended when you are dealing with multiple data structures with larger datasets. diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index c335e459f..c43a30d2e 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -280,7 +280,21 @@ pub fn notify_raw( } } -/// Similar to `call`, but without serialization. +/// Performs an asynchronous call to another canister and pay cycles at the same time. +/// +/// Treats arguments and returns as raw bytes. No data serialization and deserialization is performed. +/// +/// # Example +/// +/// It can be called: +/// +/// ```rust +/// # use ic_cdk::api::call::call_raw; +/// # fn callee_canister() -> candid::Principal { unimplemented!() } +/// async fn call_add_user() -> Vec{ +/// call_raw(callee_canister(), "add_user", b"abcd", 1_000_000u64).await.unwrap() +/// } +/// ``` pub fn call_raw<'a, T: AsRef<[u8]> + Send + Sync + 'a>( id: Principal, method: &str, @@ -290,7 +304,20 @@ pub fn call_raw<'a, T: AsRef<[u8]> + Send + Sync + 'a>( call_raw_internal(id, method, args_raw, payment.into()) } -/// Similar to `call128`, but without serialization. +/// Performs an asynchronous call to another canister and pay cycles (in `u128`) at the same time. +/// +/// Treats arguments and returns as raw bytes. No data serialization and deserialization is performed. +/// # Example +/// +/// It can be called: +/// +/// ```rust +/// # use ic_cdk::api::call::call_raw128; +/// # fn callee_canister() -> candid::Principal { unimplemented!() } +/// async fn call_add_user() -> Vec{ +/// call_raw128(callee_canister(), "add_user", b"abcd", 1_000_000u128).await.unwrap() +/// } +/// ``` pub fn call_raw128<'a, T: AsRef<[u8]> + Send + Sync + 'a>( id: Principal, method: &str, @@ -328,14 +355,35 @@ fn decoder_error_to_reject(err: candid::error::Error) -> (RejectionCode, Stri ) } -/// Performs an asynchronous call to another canister using the [System API](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-call). +/// Performs an asynchronous call to another canister. +/// +/// # Example +/// +/// Assuming that the callee canister has following interface: +/// +/// ```text +/// service : { +/// add_user: (name: text) -> (nat64); +/// } +/// ``` +/// +/// It can be called: +/// +/// ```rust +/// # use ic_cdk::api::call::call; +/// # fn callee_canister() -> candid::Principal { unimplemented!() } +/// async fn call_add_user() -> u64 { +/// let (user_id,) = call(callee_canister(), "add_user", ("Alice".to_string(),)).await.unwrap(); +/// user_id +/// } +/// ``` /// -/// If the reply payload is not a valid encoding of the expected type `T`, -/// the call results in [RejectionCode::CanisterError] error. +/// # Note /// -/// Note that the asynchronous call must be awaited -/// in order for the inter-canister call to be made -/// using the [System API](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-call). +/// * Both argument and return types are tuples even if it has only one value, e.g `(user_id,)`, `("Alice".to_string(),)`. +/// * The type annotation on return type is required. Or the return type can be inferred from the context. +/// * The asynchronous call must be awaited in order for the inter-canister call to be made. +/// * If the reply payload is not a valid encoding of the expected type `T`, the call results in [RejectionCode::CanisterError] error. pub fn call ArgumentDecoder<'a>>( id: Principal, method: &str, @@ -351,9 +399,33 @@ pub fn call ArgumentDecoder<'a>>( /// Performs an asynchronous call to another canister and pay cycles at the same time. /// -/// Note that the asynchronous call must be awaited -/// in order for the inter-canister call to be made -/// using the [System API](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-call). +/// # Example +/// +/// Assuming that the callee canister has following interface: +/// +/// ```text +/// service : { +/// add_user: (name: text) -> (nat64); +/// } +/// ``` +/// +/// It can be called: +/// +/// ```rust +/// # use ic_cdk::api::call::call_with_payment; +/// # fn callee_canister() -> candid::Principal { unimplemented!() } +/// async fn call_add_user() -> u64 { +/// let (user_id,) = call_with_payment(callee_canister(), "add_user", ("Alice".to_string(),), 1_000_000u64).await.unwrap(); +/// user_id +/// } +/// ``` +/// +/// # Note +/// +/// * Both argument and return types are tuples even if it has only one value, e.g `(user_id,)`, `("Alice".to_string(),)`. +/// * The type annotation on return type is required. Or the return type can be inferred from the context. +/// * The asynchronous call must be awaited in order for the inter-canister call to be made. +/// * If the reply payload is not a valid encoding of the expected type `T`, the call results in [RejectionCode::CanisterError] error. pub fn call_with_payment ArgumentDecoder<'a>>( id: Principal, method: &str, @@ -368,11 +440,35 @@ pub fn call_with_payment ArgumentDecoder<'a>>( } } -/// Performs an asynchronous call to another canister and pay cycles at the same time. +/// Performs an asynchronous call to another canister and pay cycles (in `u128`) at the same time. +/// +/// # Example +/// +/// Assuming that the callee canister has following interface: +/// +/// ```text +/// service : { +/// add_user: (name: text) -> (nat64); +/// } +/// ``` +/// +/// It can be called: +/// +/// ```rust +/// # use ic_cdk::api::call::call_with_payment128; +/// # fn callee_canister() -> candid::Principal { unimplemented!() } +/// async fn call_add_user() -> u64 { +/// let (user_id,) = call_with_payment128(callee_canister(), "add_user", ("Alice".to_string(),), 1_000_000u128).await.unwrap(); +/// user_id +/// } +/// ``` +/// +/// # Note /// -/// Note that the asynchronous call must be awaited -/// in order for the inter-canister call to be made -/// using the [System API](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-call). +/// * Both argument and return types are tuples even if it has only one value, e.g `(user_id,)`, `("Alice".to_string(),)`. +/// * The type annotation on return type is required. Or the return type can be inferred from the context. +/// * The asynchronous call must be awaited in order for the inter-canister call to be made. +/// * If the reply payload is not a valid encoding of the expected type `T`, the call results in [RejectionCode::CanisterError] error. pub fn call_with_payment128 ArgumentDecoder<'a>>( id: Principal, method: &str, diff --git a/src/ic-cdk/src/lib.rs b/src/ic-cdk/src/lib.rs index b15390382..20492aeff 100644 --- a/src/ic-cdk/src/lib.rs +++ b/src/ic-cdk/src/lib.rs @@ -1,3 +1,4 @@ +#![doc = include_str!("../README.md")] #![warn( elided_lifetimes_in_paths, missing_debug_implementations, @@ -8,12 +9,6 @@ )] #![cfg_attr(docsrs, feature(doc_cfg))] -//! This crate provides building blocks for developing Internet Computer canisters. -//! -//! You can check the [Internet Computer Specification]( -//! https://smartcontracts.org/docs/interface-spec/index.html#system-api-imports) -//! for a full list of the system API functions. - #[cfg(target_feature = "atomics")] compile_error!("This version of the CDK does not support multithreading."); @@ -27,8 +22,11 @@ pub mod storage; use std::sync::atomic::{AtomicBool, Ordering}; +#[doc(inline)] pub use api::call::call; +#[doc(inline)] pub use api::call::notify; +#[doc(inline)] pub use api::{caller, id, print, trap}; static DONE: AtomicBool = AtomicBool::new(false); From c4daa31461139d29675242adf4a1ea7159586ac0 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Thu, 18 Jan 2024 13:38:01 -0800 Subject: [PATCH 190/234] feat: `is_recovering_from_trap` (#456) --- src/ic-cdk/CHANGELOG.md | 4 ++++ src/ic-cdk/src/api/call.rs | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index d1f4b6954..6c7416b1c 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Added + +- Add `is_recovering_from_trap` function for implementing trap cleanup logic + ## [0.12.1] - 2024-01-12 ### Changed diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index c43a30d2e..a58ca7daa 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -741,3 +741,19 @@ where Err(S::Error::custom("`Empty` cannot be serialized")) } } + +/// Tells you whether the current async fn is being canceled due to a trap/panic. +/// +/// If a function traps/panics, then the canister state is rewound to the beginning of the function. +/// However, due to the way async works, the beginning of the function as the IC understands it is actually +/// the most recent `await` from an inter-canister-call. This means that part of the function will have executed, +/// and part of it won't. +/// +/// When this happens the CDK will cancel the task, causing destructors to be run. If you need any functions to be run +/// no matter what happens, they should happen in a destructor; the [`scopeguard`](https://docs.rs/scopeguard) crate +/// provides a convenient wrapper for this. In a destructor, `is_recovering_from_trap` serves the same purpose as +/// [`is_panicking`](std::thread::is_panicking) - it tells you whether the destructor is executing *because* of a trap, +/// as opposed to just because the scope was exited, so you could e.g. implement mutex poisoning. +pub fn is_recovering_from_trap() -> bool { + crate::futures::CLEANUP.load(Ordering::Relaxed) +} From 67cd41656fd10c903df87188d032cba584472ff9 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:32:52 -0800 Subject: [PATCH 191/234] Raise MSRV to 1.70.0 (#457) --- Cargo.toml | 2 +- e2e-tests/Cargo.toml | 1 + rust-toolchain.toml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f7f2c2a5a..39a198e65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/dfinity/cdk-rs" # MSRV # Avoid updating this field unless we use new Rust features # Sync with rust-toolchain.toml -rust-version = "1.66.0" +rust-version = "1.70.0" license = "Apache-2.0" [profile.canister-release] diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index c82de0d62..39e8319ba 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" description = "End-to-end tests for the Rust Canister Development Kit" license = "Apache-2.0" repository = "https://github.com/dfinity/cdk-rs" +publish = false [dependencies] candid.workspace = true diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 4af0f9705..22ff7da10 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.66.0" # sync with rust-version in root Cargo.toml +channel = "1.70.0" # sync with rust-version in root Cargo.toml targets = ["wasm32-unknown-unknown"] components = ["rustfmt", "clippy"] From 852f7b07c2bfb57ca0c339d75f15b71c6300e36c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Jan 2024 20:45:43 -0500 Subject: [PATCH 192/234] chore(deps): bump zerocopy from 0.7.26 to 0.7.32 (#458) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc0817a93..4410e8437 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2417,18 +2417,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.26" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.26" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", From e630e8378460fea5906207b1937d48c76299548d Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 27 Feb 2024 14:01:31 -0500 Subject: [PATCH 193/234] fix(bindgen): look for standardized environment variables (#467) * feat: resolve env vars * test: e2e using profile example * chore: clean up dfx.json * chore: bump ver & changelog * chore: dfx v0.13.1 * fix: profile bats * try the workaround * workaround * fmt --- Cargo.lock | 2 +- examples/profile/dfx.json | 16 +---- .../profile/src/profile_inter_rs/build.rs | 2 + examples/profile/tests/basic.bats | 50 ++++++++++----- src/ic-cdk-bindgen/CHANGELOG.md | 6 ++ src/ic-cdk-bindgen/Cargo.toml | 2 +- src/ic-cdk-bindgen/src/lib.rs | 62 ++++++++++++++++--- 7 files changed, 102 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4410e8437..16deea55e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -890,7 +890,7 @@ dependencies = [ [[package]] name = "ic-cdk-bindgen" -version = "0.1.2" +version = "0.1.3" dependencies = [ "candid_parser", ] diff --git a/examples/profile/dfx.json b/examples/profile/dfx.json index b8c5e8a61..a64297603 100644 --- a/examples/profile/dfx.json +++ b/examples/profile/dfx.json @@ -1,30 +1,20 @@ { "version": 1, "canisters": { - "profile_inter_rs": { + "profile-inter-rs": { "type": "custom", "candid": "src/profile_inter_rs/profile.did", "wasm": "target/wasm32-unknown-unknown/release/profile_inter_rs-opt.wasm", "build": "sh ../build.sh profile profile_inter_rs", "dependencies": [ - "profile_rs" + "profile-rs" ] }, - "profile_rs": { + "profile-rs": { "type": "custom", "candid": "src/profile_rs/profile.did", "wasm": "target/wasm32-unknown-unknown/release/profile_rs-opt.wasm", "build": "sh ../build.sh profile profile_rs" } - }, - "defaults": { - "build": { - "output": "canisters/" - }, - "start": { - "address": "127.0.0.1", - "port": 8000, - "serve_root": "canisters/eeoo/assets" - } } } diff --git a/examples/profile/src/profile_inter_rs/build.rs b/examples/profile/src/profile_inter_rs/build.rs index 520412881..a2a375747 100644 --- a/examples/profile/src/profile_inter_rs/build.rs +++ b/examples/profile/src/profile_inter_rs/build.rs @@ -2,6 +2,8 @@ use ic_cdk_bindgen::{Builder, Config}; use std::path::PathBuf; fn main() { + // A workaround to force always rerun build.rs + println!("cargo:rerun-if-changed=NULL"); let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").expect("Cannot find manifest dir")); let profile_rs = Config::new("profile_rs"); diff --git a/examples/profile/tests/basic.bats b/examples/profile/tests/basic.bats index 6b016151f..9979ed807 100644 --- a/examples/profile/tests/basic.bats +++ b/examples/profile/tests/basic.bats @@ -1,8 +1,9 @@ +load ../../bats/bats-support/load.bash +load ../../bats/bats-assert/load.bash + # Executed before each test. setup() { cd examples/profile - # Make sure the directory is clean. - dfx start --clean --background } # executed after each test @@ -11,21 +12,38 @@ teardown() { } @test "Can get, update, search (profile_rs)" { + dfx start --clean --background dfx deploy - run dfx canister call profile_rs getSelf - [ "$output" == '(record { name = ""; description = ""; keywords = vec {} })' ] - dfx canister call profile_rs update 'record {"name"= "abc"; "description"="123"; "keywords"= vec {} }' - run dfx canister call profile_rs get abc - [ "$output" == '(record { name = "abc"; description = "123"; keywords = vec {} })' ] - run dfx canister call profile_rs search ab - [ "$output" == '(opt record { name = "abc"; description = "123"; keywords = vec {} })' ] + run dfx canister call profile-rs getSelf + assert_success + assert_output '(record { name = ""; description = ""; keywords = vec {} })' + run dfx canister call profile-rs update 'record {"name"= "abc"; "description"="123"; "keywords"= vec {} }' + assert_success + run dfx canister call profile-rs get abc + assert_success + assert_output '(record { name = "abc"; description = "123"; keywords = vec {} })' + run dfx canister call profile-rs search ab + assert_success + assert_output '(opt record { name = "abc"; description = "123"; keywords = vec {} })' - run dfx canister call profile_inter_rs getSelf - [ "$output" == '(record { name = ""; description = ""; keywords = vec {} })' ] - dfx canister call profile_inter_rs update 'record {"name"= "def"; "description"="456"; "keywords"= vec {} }' - run dfx canister call profile_inter_rs get def - [ "$output" == '(record { name = "def"; description = "456"; keywords = vec {} })' ] - run dfx canister call profile_inter_rs search de - [ "$output" == '(opt record { name = "def"; description = "456"; keywords = vec {} })' ] + run dfx canister call profile-inter-rs getSelf + assert_success + assert_output '(record { name = ""; description = ""; keywords = vec {} })' + run dfx canister call profile-inter-rs update 'record {"name"= "def"; "description"="456"; "keywords"= vec {} }' + assert_success + run dfx canister call profile-inter-rs get def + assert_success + assert_output '(record { name = "def"; description = "456"; keywords = vec {} })' + run dfx canister call profile-inter-rs search de + assert_success + assert_output '(opt record { name = "def"; description = "456"; keywords = vec {} })' } + +@test "ic-cdk-bindgen warns about deprecated env vars when running with dfx v0.13.1" { + dfxvm install 0.13.1 + run dfx +0.13.1 build --check + assert_success + assert_regex "$output" "The environment variable CANISTER_CANDID_PATH_profile_rs is deprecated. Please set CANISTER_CANDID_PATH_PROFILE_RS instead. Upgrading dfx may fix this issue." + assert_regex "$output" "The environment variable CANISTER_ID_profile_rs is deprecated. Please set CANISTER_ID_PROFILE_RS instead. Upgrading dfx may fix this issue." +} \ No newline at end of file diff --git a/src/ic-cdk-bindgen/CHANGELOG.md b/src/ic-cdk-bindgen/CHANGELOG.md index 7655ddbfc..31b9ef646 100644 --- a/src/ic-cdk-bindgen/CHANGELOG.md +++ b/src/ic-cdk-bindgen/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.1.3] - 2024-02-27 + +- Resolve CANISTER_CANDID_PATH and CANISTER_ID from standardized environment variables (uppercase canister names). + - The support for legacy (non-uppercase) env vars is kept. + - It will be removed in next major release (v0.2). + ## [0.1.2] - 2023-11-23 - Change `candid` dependency to the new `candid_parser` library. diff --git a/src/ic-cdk-bindgen/Cargo.toml b/src/ic-cdk-bindgen/Cargo.toml index e14c27c79..e3f252ebc 100644 --- a/src/ic-cdk-bindgen/Cargo.toml +++ b/src/ic-cdk-bindgen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-bindgen" -version = "0.1.2" +version = "0.1.3" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-bindgen/src/lib.rs b/src/ic-cdk-bindgen/src/lib.rs index c4fde91fe..4773b4f47 100644 --- a/src/ic-cdk-bindgen/src/lib.rs +++ b/src/ic-cdk-bindgen/src/lib.rs @@ -14,13 +14,7 @@ pub struct Config { impl Config { pub fn new(canister_name: &str) -> Self { - let candid_path_var_name = format!("CANISTER_CANDID_PATH_{}", canister_name); - let candid_path = - PathBuf::from(env::var(candid_path_var_name).expect("Cannot find candid path")); - let canister_id_var_name = format!("CANISTER_ID_{}", canister_name); - let canister_id = - Principal::from_text(env::var(canister_id_var_name).expect("Cannot find canister id")) - .unwrap(); + let (candid_path, canister_id) = resolve_candid_path_and_canister_id(canister_name); let mut binding = rust::Config::new(); binding // User will depend on candid crate directly @@ -38,6 +32,60 @@ impl Config { } } +/// Resolve the candid path and canister id from environment variables. +/// +/// The name and format of the environment variables are standardized: +/// https://github.com/dfinity/sdk/blob/master/docs/cli-reference/dfx-envars.md#canister_id_canistername +/// +/// We previously used environment variables like`CANISTER_CANDID_PATH_` without to_uppercase. +/// That is deprecated. To keep backward compatibility, we also check for the old format. +/// Just in case the user run `ic-cdk-bindgen` outside `dfx`. +/// If the old format is found, we print a warning to the user. +/// dfx v0.13.0 only provides the old format, which can be used to check the warning logic. +/// TODO: remove the support for the old format, in the next major release (v0.2) of `ic-cdk-bindgen`. +fn resolve_candid_path_and_canister_id(canister_name: &str) -> (PathBuf, Principal) { + fn warning_deprecated_env(deprecated_name: &str, new_name: &str) { + println!("cargo:warning=The environment variable {} is deprecated. Please set {} instead. Upgrading dfx may fix this issue.", deprecated_name, new_name); + } + + let canister_name = canister_name.replace('-', "_"); + let canister_name_upper = canister_name.to_uppercase(); + + let candid_path_var_name = format!("CANISTER_CANDID_PATH_{}", canister_name_upper); + let candid_path_var_name_legacy = format!("CANISTER_CANDID_PATH_{}", canister_name); + + let candid_path_str = if let Ok(candid_path_str) = env::var(&candid_path_var_name) { + candid_path_str + } else if let Ok(candid_path_str) = env::var(&candid_path_var_name_legacy) { + warning_deprecated_env(&candid_path_var_name_legacy, &candid_path_var_name); + candid_path_str + } else { + panic!( + "Cannot find environment variable: {}", + &candid_path_var_name + ); + }; + let candid_path = PathBuf::from(candid_path_str); + + let canister_id_var_name = format!("CANISTER_ID_{}", canister_name_upper); + let canister_id_var_name_legacy = format!("CANISTER_ID_{}", canister_name); + let canister_id_str = if let Ok(canister_id_str) = env::var(&canister_id_var_name) { + canister_id_str + } else if let Ok(canister_id_str) = env::var(&canister_id_var_name_legacy) { + warning_deprecated_env(&canister_id_var_name_legacy, &canister_id_var_name); + canister_id_str + } else { + panic!( + "Cannot find environment variable: {}", + &canister_id_var_name + ); + }; + let canister_id = Principal::from_text(&canister_id_str) + .unwrap_or_else(|_| panic!("Invalid principal: {}", &canister_id_str)); + + (candid_path, canister_id) +} + #[derive(Default)] pub struct Builder { configs: Vec, From f6c18209c9a1e5aaca5b80cb04990d7d01f111a4 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 27 Feb 2024 20:21:27 -0500 Subject: [PATCH 194/234] chore(ci): examples run with latest dfx (#468) * chore: upgrade CI dependencies & use latest in setup-dfx * chore: correct comment * fix: add mising export_candid! --- .github/workflows/ci.yml | 16 ++++++++-------- .github/workflows/examples.yml | 15 ++++++--------- examples/counter/src/inter2_rs/lib.rs | 2 ++ examples/counter/src/inter_rs/lib.rs | 2 ++ examples/profile/src/profile_inter_rs/lib.rs | 2 ++ examples/rust-toolchain.toml | 2 +- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ce363738..362314586 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,9 +18,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cargo/bin/ @@ -43,9 +43,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cargo/bin/ @@ -69,9 +69,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cargo/bin/ @@ -92,9 +92,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cargo/bin/ diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 64f1e787a..bb9dce1b4 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -13,7 +13,6 @@ concurrency: cancel-in-progress: true env: - dfx-version: 0.14.1 ic-wasm-version: 0.4.0 jobs: @@ -21,10 +20,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cargo/bin/ @@ -40,7 +39,7 @@ jobs: - name: Build candid-extractor run: cargo build -p candid-extractor --release - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: candid-extractor path: target/release/candid-extractor @@ -56,12 +55,12 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: "recursive" - name: Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cargo/bin/ @@ -82,7 +81,7 @@ jobs: mv ic-wasm-linux64 /usr/local/bin/ic-wasm - name: Download candid-extractor - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: candid-extractor @@ -93,8 +92,6 @@ jobs: - name: Install DFX uses: dfinity/setup-dfx@main - with: - dfx-version: "${{ env.dfx-version }}" - name: Install bitcoin if: ${{ matrix.project-name == 'management_canister' }} diff --git a/examples/counter/src/inter2_rs/lib.rs b/examples/counter/src/inter2_rs/lib.rs index 2781e825a..195d36f2d 100644 --- a/examples/counter/src/inter2_rs/lib.rs +++ b/examples/counter/src/inter2_rs/lib.rs @@ -17,3 +17,5 @@ async fn inc() { async fn write(input: candid::Nat) { inter_mo.write(input).await.unwrap() } + +ic_cdk::export_candid!(); diff --git a/examples/counter/src/inter_rs/lib.rs b/examples/counter/src/inter_rs/lib.rs index b36d64159..4657db6c7 100644 --- a/examples/counter/src/inter_rs/lib.rs +++ b/examples/counter/src/inter_rs/lib.rs @@ -17,3 +17,5 @@ async fn inc() { async fn write(input: candid::Nat) { counter_mo.write(input).await.unwrap() } + +ic_cdk::export_candid!(); diff --git a/examples/profile/src/profile_inter_rs/lib.rs b/examples/profile/src/profile_inter_rs/lib.rs index 04d748b66..90db9834f 100644 --- a/examples/profile/src/profile_inter_rs/lib.rs +++ b/examples/profile/src/profile_inter_rs/lib.rs @@ -22,3 +22,5 @@ async fn update(profile: Profile) { async fn search(text: String) -> Option { profile_rs.search(text).await.unwrap().0 } + +ic_cdk::export_candid!(); diff --git a/examples/rust-toolchain.toml b/examples/rust-toolchain.toml index ccf20527a..8fbec9af3 100644 --- a/examples/rust-toolchain.toml +++ b/examples/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "stable" # sync with rust-version in root Cargo.toml +channel = "stable" # intentionally not pinned to a specific version targets = ["wasm32-unknown-unknown"] components = ["rustfmt", "clippy"] From bbd63393f40c5af4abbfbcc4592c39735a168e8f Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Thu, 29 Feb 2024 21:38:14 -0800 Subject: [PATCH 195/234] feat!: config canister endpoint decoding quota (#465) * feat: config canister endpoint decoding quota * add call_with_config * fix * fix * changelog * fix * fix * update changelog --- Cargo.lock | 12 +- Cargo.toml | 6 +- examples/counter/src/counter_rs/lib.rs | 2 +- src/ic-cdk-macros/src/export.rs | 91 +++++++++++-- src/ic-cdk-timers/src/lib.rs | 7 +- src/ic-cdk/CHANGELOG.md | 10 ++ src/ic-cdk/src/api/call.rs | 128 +++++++++++++++++- .../management_canister/http_request/mod.rs | 4 +- 8 files changed, 234 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16deea55e..0193d5251 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,9 +188,9 @@ dependencies = [ [[package]] name = "candid" -version = "0.10.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2525ab7a58543c132da8c780abe3aa1ba394ddcc1888a4ad2ba4f5100906ebe" +checksum = "7fcd70c7bed52cb20e38dd933c19c0c9abf0302b60db3fa3186e27ec53edf6ad" dependencies = [ "anyhow", "binread", @@ -221,9 +221,9 @@ dependencies = [ [[package]] name = "candid_derive" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "970c220da8aa2fa6f7ef5dbbf3ea5b620a59eb3ac107cfb95ae8c6eebdfb7a08" +checksum = "3de398570c386726e7a59d9887b68763c481477f9a043fb998a2e09d428df1a9" dependencies = [ "lazy_static", "proc-macro2", @@ -233,9 +233,9 @@ dependencies = [ [[package]] name = "candid_parser" -version = "0.1.0" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152b737c1c2681d4ed3359f15016b499f2ddc59aef9fdce0be82f483c11e700" +checksum = "48a3da76f989cd350b7342c64c6c6008341bb6186f6832ef04e56dc50ba0fd76" dependencies = [ "anyhow", "candid", diff --git a/Cargo.toml b/Cargo.toml index 39a198e65..c1606f8ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = ["src/*", "library/*", "e2e-tests"] +resolver = "2" [workspace.package] authors = ["DFINITY Stiftung "] @@ -23,8 +24,8 @@ ic0 = { path = "src/ic0", version = "0.21.1" } ic-cdk = { path = "src/ic-cdk", version = "0.12.1" } ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.6.0" } -candid = "0.10" -candid_parser = "0.1.0" +candid = "0.10.4" +candid_parser = "0.1.4" futures = "0.3" hex = "0.4" quote = "1" @@ -33,3 +34,4 @@ serde_bytes = "0.11" sha2 = "0.10" slotmap = "1" syn = "1" + diff --git a/examples/counter/src/counter_rs/lib.rs b/examples/counter/src/counter_rs/lib.rs index e0be90142..0368e7dad 100644 --- a/examples/counter/src/counter_rs/lib.rs +++ b/examples/counter/src/counter_rs/lib.rs @@ -12,7 +12,7 @@ fn init() { OWNER.with(|owner| owner.set(ic_cdk::api::caller())); } -#[update] +#[update(debug = true, decoding_quota = 50, skipping_quota = 0)] fn inc() { ic_cdk::println!("{:?}", OWNER.with(|owner| owner.get())); COUNTER.with(|counter| *counter.borrow_mut() += 1u64); diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index 868a457ec..a90e1991c 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -16,6 +16,12 @@ struct ExportAttributes { pub composite: bool, #[serde(default)] pub hidden: bool, + #[serde(default)] + pub decoding_quota: Option, + #[serde(default = "default_skipping_quota")] + pub skipping_quota: Option, + #[serde(default)] + pub debug: bool, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -56,6 +62,10 @@ impl std::fmt::Display for MethodType { } } +fn default_skipping_quota() -> Option { + Some(10_000) +} + fn get_args(method: MethodType, signature: &Signature) -> Result)>, Error> { // We only need the tuple of arguments, not their types. Magic of type inference. let mut args = vec![]; @@ -176,7 +186,29 @@ fn dfn_macro( let arg_decode = if method.is_lifecycle() && arg_count == 0 { quote! {} } else { - quote! { let ( #( #arg_tuple, )* ) = ic_cdk::api::call::arg_data(); } + let decoding_quota = if let Some(n) = attrs.decoding_quota { + quote! { Some(#n) } + } else { + quote! { None } + }; + let skipping_quota = if let Some(n) = attrs.skipping_quota { + quote! { Some(#n) } + } else { + quote! { None } + }; + let debug = if attrs.debug { + quote! { true } + } else { + quote! { false } + }; + let config = quote! { + ic_cdk::api::call::ArgDecoderConfig { + decoding_quota: #decoding_quota, + skipping_quota: #skipping_quota, + debug: #debug, + } + }; + quote! { let ( #( #arg_tuple, )* ) = ic_cdk::api::call::arg_data(#config); } }; let guard = if let Some(guard_name) = attrs.guard { @@ -298,7 +330,13 @@ mod test { fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { - let () = ic_cdk::api::call::arg_data(); + let () = ic_cdk::api::call::arg_data( + ic_cdk::api::call::ArgDecoderConfig { + decoding_quota: None, + skipping_quota: Some(10000usize), + debug: false, + } + ); let result = query(); ic_cdk::api::call::reply(()) }); @@ -314,7 +352,6 @@ mod test { _ => panic!("not a function"), }; } - #[test] fn ic_query_return_one_value() { let generated = ic_query( @@ -335,7 +372,13 @@ mod test { fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { - let () = ic_cdk::api::call::arg_data(); + let () = ic_cdk::api::call::arg_data( + ic_cdk::api::call::ArgDecoderConfig { + decoding_quota: None, + skipping_quota: Some(10000usize), + debug: false, + } + ); let result = query(); ic_cdk::api::call::reply((result,)) }); @@ -372,7 +415,13 @@ mod test { fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { - let () = ic_cdk::api::call::arg_data(); + let () = ic_cdk::api::call::arg_data( + ic_cdk::api::call::ArgDecoderConfig { + decoding_quota: None, + skipping_quota: Some(10000usize), + debug: false, + } + ); let result = query(); ic_cdk::api::call::reply(result) }); @@ -409,7 +458,13 @@ mod test { fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { - let (a, ) = ic_cdk::api::call::arg_data(); + let (a, ) = ic_cdk::api::call::arg_data( + ic_cdk::api::call::ArgDecoderConfig { + decoding_quota: None, + skipping_quota: Some(10000usize), + debug: false, + } + ); let result = query(a); ic_cdk::api::call::reply(()) }); @@ -446,7 +501,13 @@ mod test { fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { - let (a, b, ) = ic_cdk::api::call::arg_data(); + let (a, b, ) = ic_cdk::api::call::arg_data( + ic_cdk::api::call::ArgDecoderConfig { + decoding_quota: None, + skipping_quota: Some(10000usize), + debug: false, + } + ); let result = query(a, b); ic_cdk::api::call::reply(()) }); @@ -483,7 +544,13 @@ mod test { fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { - let (a, b, ) = ic_cdk::api::call::arg_data(); + let (a, b, ) = ic_cdk::api::call::arg_data( + ic_cdk::api::call::ArgDecoderConfig { + decoding_quota: None, + skipping_quota: Some(10000usize), + debug: false, + } + ); let result = query(a, b); ic_cdk::api::call::reply((result,)) }); @@ -520,7 +587,13 @@ mod test { fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { - let () = ic_cdk::api::call::arg_data(); + let () = ic_cdk::api::call::arg_data( + ic_cdk::api::call::ArgDecoderConfig { + decoding_quota: None, + skipping_quota: Some(10000usize), + debug: false, + } + ); let result = query(); ic_cdk::api::call::reply(()) }); diff --git a/src/ic-cdk-timers/src/lib.rs b/src/ic-cdk-timers/src/lib.rs index a25ec0336..863ae8a16 100644 --- a/src/ic-cdk-timers/src/lib.rs +++ b/src/ic-cdk-timers/src/lib.rs @@ -265,7 +265,12 @@ extern "C" fn timer_executor() { if ic_cdk::api::caller() != ic_cdk::api::id() { ic_cdk::trap("This function is internal to ic-cdk and should not be called externally."); } - let (task_id,) = ic_cdk::api::call::arg_data(); + let config = ic_cdk::api::call::ArgDecoderConfig { + decoding_quota: Some(10_000), + skipping_quota: Some(100), + debug: false, + }; + let (task_id,) = ic_cdk::api::call::arg_data(config); let task_id = TimerId(KeyData::from_ffi(task_id)); // We can't be holding `TASKS` when we call the function, because it may want to schedule more tasks. // Instead, we swap the task out in order to call it, and then either swap it back in, or remove it. diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 6c7416b1c..7922ef334 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -9,6 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add `is_recovering_from_trap` function for implementing trap cleanup logic +- Allow setting decoding quota for canister endpoints and inter-canister calls. + * When defining canister endpoints, we add the following attributes: `#[update(decoding_quota = 10000, skipping_quota = 100, debug = true)]` + - `skipping_quota` limits the amount of work allowed for skipping unneeded data on the wire. If this attributes is not present, we set a default quota of `10_000`. This affects ALL existing canisters, and is mainly used to improve canister throughput. See [docs on the Candid library](https://docs.rs/candid/latest/candid/de/struct.DecoderConfig.html#method.set_skipping_quota) to understand the skipping cost. + - `decoding_quota` limits the total amount of work the deserializer can perform. See [docs on the Candid library](https://docs.rs/candid/latest/candid/de/struct.DecoderConfig.html#method.set_decoding_quota) to understand the cost model. + - `debug = true` prints the instruction count and the decoding/skipping cost to the replica log, after a successful deserialization. The decoding/skipping cost is logged only when you have already set a quota in the attributes. The debug mode is useful to determine the right quotas above. Developers can send a few large payloads to the debugging endpoint and know the actual decoding cost. + * When making inter-canister calls, we have a new function `call_with_config` to config the same decoding quotas described above. It's strongly recommended to use `call_with_config` when calling third-party untrusted canisters. + +### Changed + +- `ic_cdk::api::call::arg_data` takes `ArgDecoderConfig` as argument. ## [0.12.1] - 2024-01-12 diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index a58ca7daa..1fe5e8f90 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -1,7 +1,9 @@ //! APIs to make and manage calls in the canister. use crate::api::trap; -use candid::utils::{ArgumentDecoder, ArgumentEncoder}; -use candid::{decode_args, encode_args, write_args, CandidType, Deserialize, Principal}; +use candid::utils::{decode_args_with_config_debug, ArgumentDecoder, ArgumentEncoder}; +use candid::{ + decode_args, encode_args, write_args, CandidType, DecoderConfig, Deserialize, Principal, +}; use serde::ser::Error; use std::future::Future; use std::marker::PhantomData; @@ -483,6 +485,80 @@ pub fn call_with_payment128 ArgumentDecoder<'a>>( } } +/// Performs an asynchronous call to another canister and pay cycles (in `u128`). +/// It also allows setting a quota for decoding the return values. +/// The decoding quota is strongly recommended when calling third-party or untrusted canisters. +/// +/// # Example +/// +/// Assuming that the callee canister has following interface: +/// +/// ```text +/// service : { +/// add_user: (name: text) -> (nat64); +/// } +/// ``` +/// +/// It can be called: +/// +/// ```rust +/// # use ic_cdk::api::call::{call_with_config, ArgDecoderConfig}; +/// # fn callee_canister() -> candid::Principal { unimplemented!() } +/// async fn call_add_user() -> u64 { +/// let config = ArgDecoderConfig { +/// // The function only returns a nat64, to accomodate future upgrades, we set a larger decoding_quota. +/// decoding_quota: Some(10_000), +/// // To accomodate future upgrades, reserve some skipping_quota. +/// skipping_quota: Some(100), +/// // Enable debug mode to print decoding instructions and cost to the replica log. +/// debug: true, +/// }; +/// let (user_id,) = call_with_config(callee_canister(), "add_user", ("Alice".to_string(),), 1_000_000u128, &config).await.unwrap(); +/// user_id +/// } +/// ``` +pub fn call_with_config<'b, T: ArgumentEncoder, R: for<'a> ArgumentDecoder<'a>>( + id: Principal, + method: &'b str, + args: T, + cycles: u128, + arg_config: &'b ArgDecoderConfig, +) -> impl Future> + Send + Sync + 'b { + let args_raw = encode_args(args).expect("Failed to encode arguments."); + let fut = call_raw128(id, method, args_raw, cycles); + async move { + let bytes = fut.await?; + let config = arg_config.to_candid_config(); + let pre_cycles = if arg_config.debug { + Some(crate::api::performance_counter(0)) + } else { + None + }; + match decode_args_with_config_debug(&bytes, &config) { + Err(e) => Err(decoder_error_to_reject::(e)), + Ok((r, cost)) => { + if arg_config.debug { + print_decoding_debug_info(&format!("{method} return"), &cost, pre_cycles); + } + Ok(r) + } + } + } +} + +fn print_decoding_debug_info(title: &str, cost: &DecoderConfig, pre_cycles: Option) { + use crate::api::{performance_counter, print}; + let pre_cycles = pre_cycles.unwrap_or(0); + let instrs = performance_counter(0) - pre_cycles; + print(format!("[Debug] {title} decoding instructions: {instrs}")); + if let Some(n) = cost.decoding_quota { + print(format!("[Debug] {title} decoding cost: {n}")); + } + if let Some(n) = cost.skipping_quota { + print(format!("[Debug] {title} skipping cost: {n}")); + } +} + /// Returns a result that maps over the call /// /// It will be Ok(T) if the call succeeded (with T being the arg_data), @@ -642,14 +718,56 @@ pub fn reply_raw(buf: &[u8]) { unsafe { ic0::msg_reply() }; } +#[derive(Debug)] +/// Config to control the behavior of decoding canister endpoint arguments. +pub struct ArgDecoderConfig { + /// Limit the total amount of work the deserializer can perform. See [docs on the Candid library](https://docs.rs/candid/latest/candid/de/struct.DecoderConfig.html#method.set_decoding_quota) to understand the cost model. + pub decoding_quota: Option, + /// Limit the total amount of work for skipping unneeded data on the wire. See [docs on the Candid library](https://docs.rs/candid/latest/candid/de/struct.DecoderConfig.html#method.set_skipping_quota) to understand the skipping cost. + pub skipping_quota: Option, + /// When set to true, print instruction count and the decoding/skipping cost to the replica log. + pub debug: bool, +} +impl ArgDecoderConfig { + fn to_candid_config(&self) -> DecoderConfig { + let mut config = DecoderConfig::new(); + if let Some(n) = self.decoding_quota { + config.set_decoding_quota(n); + } + if let Some(n) = self.skipping_quota { + config.set_skipping_quota(n); + } + if self.debug { + config.set_full_error_message(true); + } + config + } +} +impl Default for ArgDecoderConfig { + fn default() -> Self { + Self { + decoding_quota: None, + skipping_quota: Some(10_000), + debug: false, + } + } +} + /// Returns the argument data in the current call. Traps if the data cannot be /// decoded. -pub fn arg_data ArgumentDecoder<'a>>() -> R { +pub fn arg_data ArgumentDecoder<'a>>(arg_config: ArgDecoderConfig) -> R { let bytes = arg_data_raw(); - match decode_args(&bytes) { + let config = arg_config.to_candid_config(); + let res = decode_args_with_config_debug(&bytes, &config); + match res { Err(e) => trap(&format!("failed to decode call arguments: {:?}", e)), - Ok(r) => r, + Ok((r, cost)) => { + if arg_config.debug { + print_decoding_debug_info("Argument", &cost, None); + } + r + } } } diff --git a/src/ic-cdk/src/api/management_canister/http_request/mod.rs b/src/ic-cdk/src/api/management_canister/http_request/mod.rs index aebd4776f..48e214d2e 100644 --- a/src/ic-cdk/src/api/management_canister/http_request/mod.rs +++ b/src/ic-cdk/src/api/management_canister/http_request/mod.rs @@ -39,14 +39,14 @@ thread_local! { #[export_name = "canister_query http_transform"] extern "C" fn http_transform() { use crate::api::{ - call::{arg_data, reply}, + call::{arg_data, reply, ArgDecoderConfig}, caller, }; if caller() != Principal::management_canister() { crate::trap("This function is internal to ic-cdk and should not be called externally."); } crate::setup(); - let (args,): (TransformArgs,) = arg_data(); + let (args,): (TransformArgs,) = arg_data(ArgDecoderConfig::default()); let int = u64::from_be_bytes(args.context[..].try_into().unwrap()); let key = DefaultKey::from(KeyData::from_ffi(int)); let func = TRANSFORMS.with(|transforms| transforms.borrow_mut().remove(key)); From 406e8aa49add55d65582ae4a8a83830e0bc2ee29 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 1 Mar 2024 13:35:05 -0500 Subject: [PATCH 196/234] chore: release ic-cdk v0.13.0 (#469) * chore: release ic-cdk v0.13.0 * chore: ic-ledger-types v0.10.0 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- library/ic-ledger-types/CHANGELOG.md | 5 +++++ library/ic-ledger-types/Cargo.toml | 2 +- src/ic-cdk-macros/CHANGELOG.md | 6 ++++++ src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 8 +++++--- src/ic-cdk/Cargo.toml | 4 ++-- 8 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0193d5251..46f8c6e31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -875,7 +875,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "ic-cdk" -version = "0.12.1" +version = "0.13.0" dependencies = [ "anyhow", "candid", @@ -914,7 +914,7 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.8.4" +version = "0.8.5" dependencies = [ "candid", "proc-macro2", @@ -952,7 +952,7 @@ dependencies = [ [[package]] name = "ic-ledger-types" -version = "0.9.0" +version = "0.10.0" dependencies = [ "candid", "crc32fast", diff --git a/Cargo.toml b/Cargo.toml index c1606f8ae..045f69d84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.21.1" } -ic-cdk = { path = "src/ic-cdk", version = "0.12.1" } +ic-cdk = { path = "src/ic-cdk", version = "0.13.0" } ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.6.0" } candid = "0.10.4" diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index ad1a801a9..997458b98 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.10.0] - 2024-03-01 + +### Changed +- Upgrade `ic-cdk` to v0.13. + ## [0.9.0] - 2023-11-23 ### Changed diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index fc23bbff9..fe599cef6 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.9.0" +version = "0.10.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index f13441383..32dfb498f 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.8.5] - 2024-03-01 + +### Added + +- Allow setting decoding quota for canister endpoints and inter-canister calls. (#465) + ## [0.8.4] - 2024-01-12 ### Fixed diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 82915a14f..43b026601 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.8.4" # no need to sync with ic-cdk +version = "0.8.5" # no need to sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 7922ef334..181cd7d8d 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,10 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.13.0] - 2024-03-01 + ### Added -- Add `is_recovering_from_trap` function for implementing trap cleanup logic -- Allow setting decoding quota for canister endpoints and inter-canister calls. +- Add `is_recovering_from_trap` function for implementing trap cleanup logic. (#456) +- Allow setting decoding quota for canister endpoints and inter-canister calls. (#465) * When defining canister endpoints, we add the following attributes: `#[update(decoding_quota = 10000, skipping_quota = 100, debug = true)]` - `skipping_quota` limits the amount of work allowed for skipping unneeded data on the wire. If this attributes is not present, we set a default quota of `10_000`. This affects ALL existing canisters, and is mainly used to improve canister throughput. See [docs on the Candid library](https://docs.rs/candid/latest/candid/de/struct.DecoderConfig.html#method.set_skipping_quota) to understand the skipping cost. - `decoding_quota` limits the total amount of work the deserializer can perform. See [docs on the Candid library](https://docs.rs/candid/latest/candid/de/struct.DecoderConfig.html#method.set_decoding_quota) to understand the cost model. @@ -18,7 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- `ic_cdk::api::call::arg_data` takes `ArgDecoderConfig` as argument. +- `ic_cdk::api::call::arg_data` takes `ArgDecoderConfig` as argument. (#465) ## [0.12.1] - 2024-01-12 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 22d7ae18a..5d93124f1 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.12.1" +version = "0.13.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -22,7 +22,7 @@ include = ["src", "Cargo.toml", "LICENSE", "README.md"] [dependencies] candid.workspace = true ic0.workspace = true -ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.8.4" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.8.5" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true } From ad36d902228aa77ec88677988c9925865f963778 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 1 Mar 2024 14:46:53 -0500 Subject: [PATCH 197/234] chore: release ic-cdk v0.13.1 and ic-cdk-macros v0.9.0 (#470) * chore: release ic-cdk v0.13.1 and ic-cdk-macros v0.9.0 * pin ic-cdk-macros to a specific version --- Cargo.lock | 4 ++-- src/ic-cdk-macros/CHANGELOG.md | 8 +++++++- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 8 +++++++- src/ic-cdk/Cargo.toml | 9 +++++++-- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46f8c6e31..a50f6f946 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -875,7 +875,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "ic-cdk" -version = "0.13.0" +version = "0.13.1" dependencies = [ "anyhow", "candid", @@ -914,7 +914,7 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.8.5" +version = "0.9.0" dependencies = [ "candid", "proc-macro2", diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index 32dfb498f..14fd1a1d7 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,7 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -## [0.8.5] - 2024-03-01 +## [0.9.0] - 2024-03-01 + +### Fixed + +- The change in yanked version v0.8.5 contains breaking change. + +## [0.8.5] - 2024-03-01 (yanked) ### Added diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 43b026601..d56ac4d0d 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.8.5" # no need to sync with ic-cdk +version = "0.9.0" # no need to sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 181cd7d8d..d6923d5ea 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,7 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -## [0.13.0] - 2024-03-01 +## [0.13.1] - 2024-03-01 + +### Changed + +- Upgrade `ic-cdk-macros` to v0.9.0. + +## [0.13.0] - 2024-03-01 (yanked) ### Added diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 5d93124f1..0e73a24ec 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.13.0" +version = "0.13.1" authors.workspace = true edition.workspace = true license.workspace = true @@ -22,7 +22,12 @@ include = ["src", "Cargo.toml", "LICENSE", "README.md"] [dependencies] candid.workspace = true ic0.workspace = true -ic-cdk-macros = { path = "../ic-cdk-macros", version = "0.8.5" } +# Pin ic-cdk-macros to a specific version. +# This actually create a 1-to-1 mapping between ic-cdk and ic-cdk-macros. +# Dependents won't accidentaly upgrading ic-cdk-macros only but not ic-cdk. +# ic-cdk-macros is a hidden dependency, re-exported by ic-cdk. +# It should not be included by users direcly. +ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.9.0" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true } From 08cbe397fcbaf62dd1edbec218492f967e80dd00 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 1 Mar 2024 17:16:16 -0500 Subject: [PATCH 198/234] chore: release ic-cdk-timers v0.7.0 (#471) --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/ic-cdk-timers/CHANGELOG.md | 6 ++++++ src/ic-cdk-timers/Cargo.toml | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a50f6f946..f28a9ec9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -926,7 +926,7 @@ dependencies = [ [[package]] name = "ic-cdk-timers" -version = "0.6.0" +version = "0.7.0" dependencies = [ "futures", "ic-cdk", diff --git a/Cargo.toml b/Cargo.toml index 045f69d84..ba126f4f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.21.1" } ic-cdk = { path = "src/ic-cdk", version = "0.13.0" } -ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.6.0" } +ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.7.0" } candid = "0.10.4" candid_parser = "0.1.4" diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index 000e03e0a..5ec74beec 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.7.0] - 2024-03-01 + +### Changed + +- Upgrade `ic-cdk` to v0.13. + ## [0.6.0] - 2023-11-23 ### Changed diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index 6a5927271..aa241dd9e 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.6.0" +version = "0.7.0" authors.workspace = true edition.workspace = true license.workspace = true From ab458c44d9d405c4329ef470eab66fac33c2e151 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 14 Mar 2024 14:45:43 -0400 Subject: [PATCH 199/234] chore: examples overhaul (#473) * make assertions * pin btc-canister * gitignore * comment * asset_storage * fix management * chess * counter * print * simplify profile * edition 2021 & resolver 2 --- examples/asset_storage/Cargo.toml | 5 +- .../src/asset_storage_rs/Cargo.toml | 2 +- examples/asset_storage/tests/basic.bats | 88 +++++++++---------- examples/chess/Cargo.toml | 5 +- examples/chess/src/chess_rs/Cargo.toml | 6 +- examples/chess/tests/basic.bats | 10 ++- examples/counter/Cargo.toml | 1 + examples/counter/src/counter_rs/Cargo.toml | 2 +- examples/counter/src/inter2_rs/Cargo.toml | 2 +- examples/counter/src/inter_rs/Cargo.toml | 2 +- examples/counter/tests/basic.bats | 31 ++++--- examples/management_canister/.gitignore | 1 + examples/management_canister/Cargo.toml | 5 +- examples/management_canister/tests/basic.bats | 22 +++-- examples/print/Cargo.toml | 1 + examples/print/src/print_rs/Cargo.toml | 2 +- examples/print/tests/basic.bats | 5 +- examples/profile/Cargo.toml | 1 + .../profile/src/profile_inter_rs/Cargo.toml | 2 +- examples/profile/src/profile_rs/Cargo.toml | 2 +- examples/profile/tests/basic.bats | 13 ++- 21 files changed, 114 insertions(+), 94 deletions(-) create mode 100644 examples/management_canister/.gitignore diff --git a/examples/asset_storage/Cargo.toml b/examples/asset_storage/Cargo.toml index 995b8a2fa..f9b923407 100644 --- a/examples/asset_storage/Cargo.toml +++ b/examples/asset_storage/Cargo.toml @@ -1,7 +1,6 @@ [workspace] -members = [ - "src/asset_storage_rs", -] +members = ["src/asset_storage_rs"] +resolver = "2" [profile.release] lto = true diff --git a/examples/asset_storage/src/asset_storage_rs/Cargo.toml b/examples/asset_storage/src/asset_storage_rs/Cargo.toml index 38fdb3aa2..ef7509a19 100644 --- a/examples/asset_storage/src/asset_storage_rs/Cargo.toml +++ b/examples/asset_storage/src/asset_storage_rs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "asset_storage_rs" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/asset_storage/tests/basic.bats b/examples/asset_storage/tests/basic.bats index 72c64f553..c26ad4129 100644 --- a/examples/asset_storage/tests/basic.bats +++ b/examples/asset_storage/tests/basic.bats @@ -1,70 +1,66 @@ +load ../../bats/bats-assert/load.bash + # Executed before each test. setup() { cd examples/asset_storage # Make sure the directory is clean. - dfx start --clean --background + dfx start --clean --background - run dfx identity new alice --disable-encryption - run dfx identity new bob --disable-encryption - run dfx identity new charlie --disable-encryption + x=$(mktemp -d -t cdk-XXXXXXXX) + export DFX_CONFIG_ROOT="$x" + dfx identity new alice --storage-mode=plaintext + dfx identity new bob --storage-mode=plaintext + dfx identity new charlie --storage-mode=plaintext } # executed after each test teardown() { dfx stop + rm -rf "$DFX_CONFIG_ROOT" } @test "Can store and restore assets" { - dfx deploy - dfx canister call asset_storage store '("asset_name", vec { 1; 2; 3; })' - dfx canister call asset_storage retrieve '("asset_name")' - run dfx canister call asset_storage retrieve '("unknown")' - # As of dfx 0.8.1, above command results in following error message: - # > The Replica returned an error: code 5, message: "IC0502: Canister rwlgt-iiaaa-aaaaa-aaaaa-cai trapped: unreachable" - [ "$status" != 0 ] -} - -@test "Will fails on invalid identities" { - dfx identity use alice - dfx deploy - dfx canister call asset_storage store '("asset_name", vec { 1; 2; 3; })' - dfx canister call asset_storage retrieve '("asset_name")' - - dfx canister call asset_storage add_user "(principal \"$(dfx --identity charlie identity get-principal)\")" - - dfx identity use bob - dfx canister call asset_storage retrieve '("asset_name")' + dfx --identity alice deploy + run dfx --identity alice canister call asset_storage store '("asset_name", vec { 1; 2; 3; })' + assert_success + run dfx --identity alice canister call asset_storage retrieve '("asset_name")' + assert_success # Test that an unknown asset fails. - run dfx canister call asset_storage retrieve '("unknown")' - [ "$status" != 0 ] + run dfx --identity alice canister call asset_storage retrieve '("unknown")' + assert_failure +} - # Test that cannot upload assets as bob. - run dfx canister call asset_storage store '("asset_name", vec { 1; })' - [ "$status" != 0 ] +@test "Unauthorized identity cannot store" { + dfx --identity alice deploy + dfx --identity alice canister call asset_storage store '("asset_name", vec { 1; 2; 3; })' + dfx --identity alice canister call asset_storage retrieve '("asset_name")' - # Test we can upload assets as charlie. - dfx identity use charlie - run dfx canister call asset_storage store '("asset_name_2", vec { 1; 2; 3; })' - [ "$status" == 0 ] -} + # add charlie + run dfx --identity alice canister call asset_storage add_user "(principal \"$(dfx --identity charlie identity get-principal)\")" + assert_success -@test "Can upgrade and keep ACLs" { - dfx identity use alice - dfx deploy + # bob cannot upload assets + run dfx --identity bob canister call asset_storage store '("asset_name", vec { 1; })' + assert_failure - dfx canister call asset_storage store '("asset_name", vec { 1; 2; 3; })' - dfx identity use bob - run dfx canister call asset_storage retrieve '("unknown")' - [ "$status" != 0 ] + # charlie can upload assets + run dfx --identity charlie canister call asset_storage store '("asset_name_2", vec { 1; 2; 3; })' + assert_success +} - dfx identity use alice - dfx canister call asset_storage add_user "(principal \"$(dfx --identity charlie identity get-principal)\")" +@test "Can upgrade and keep the access control list" { + dfx --identity alice deploy + dfx --identity alice canister call asset_storage store '("asset_name", vec { 1; 2; 3; })' + dfx --identity alice canister call asset_storage add_user "(principal \"$(dfx --identity charlie identity get-principal)\")" - dfx build dfx canister install --all --mode=upgrade - dfx identity use charlie - run dfx canister call asset_storage store '("asset_name_2", vec { 1; 2; 3; })' - [ "$status" == 0 ] + # bob still cannot upload assets + run dfx --identity bob canister call asset_storage store '("asset_name", vec { 1; })' + assert_failure + + # charlie still can upload assets + run dfx --identity charlie canister call asset_storage store '("asset_name_2", vec { 1; 2; 3; })' + assert_success } diff --git a/examples/chess/Cargo.toml b/examples/chess/Cargo.toml index e97684672..c1a34a5b4 100644 --- a/examples/chess/Cargo.toml +++ b/examples/chess/Cargo.toml @@ -1,7 +1,6 @@ [workspace] -members = [ - "src/chess_rs", -] +members = ["src/chess_rs"] +resolver = "2" [profile.release] lto = true diff --git a/examples/chess/src/chess_rs/Cargo.toml b/examples/chess/src/chess_rs/Cargo.toml index 67a29abee..7bcf08b43 100644 --- a/examples/chess/src/chess_rs/Cargo.toml +++ b/examples/chess/src/chess_rs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "chess_rs" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -14,4 +14,6 @@ candid = "0.10" ic-cdk = { path = "../../../../src/ic-cdk" } serde = "1.0.111" tanton = "1.0.0" -getrandom = { version = "0.2", features = ["custom"] } # tanton requires this to compile on wasm target +getrandom = { version = "0.2", features = [ + "custom", +] } # tanton requires this to compile on wasm target diff --git a/examples/chess/tests/basic.bats b/examples/chess/tests/basic.bats index 36706ff2b..a9ee3acfd 100644 --- a/examples/chess/tests/basic.bats +++ b/examples/chess/tests/basic.bats @@ -1,3 +1,5 @@ +load ../../bats/bats-assert/load.bash + # Executed before each test. setup() { cd examples/chess @@ -13,11 +15,11 @@ teardown() { @test "Can play chess against AI" { dfx deploy run dfx canister call chess_rs new '("test", true)' - [ "$output" == "()" ] + assert_output '()' run dfx canister call chess_rs move '("test", "e2e4")' - [ "$output" == "(true)" ] + assert_output '(true)' run dfx canister call chess_rs move '("test", "d2d3")' - [ "$output" == "(true)" ] + assert_output '(true)' run dfx canister call chess_rs getFen '("test")' - [ "$output" == '(opt "rnb1kbnr/pp1ppppp/1qp5/8/4P3/3P4/PPP2PPP/RNBQKBNR w KQkq - 1 3")' ] + assert_output '(opt "rnb1kbnr/pp1ppppp/1qp5/8/4P3/3P4/PPP2PPP/RNBQKBNR w KQkq - 1 3")' } diff --git a/examples/counter/Cargo.toml b/examples/counter/Cargo.toml index 1b3ee58a8..46f1a57ca 100644 --- a/examples/counter/Cargo.toml +++ b/examples/counter/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = ["src/counter_rs", "src/inter_rs", "src/inter2_rs"] +resolver = "2" [workspace.dependencies] candid = "0.10" diff --git a/examples/counter/src/counter_rs/Cargo.toml b/examples/counter/src/counter_rs/Cargo.toml index bb514ed8a..9e79d3c98 100644 --- a/examples/counter/src/counter_rs/Cargo.toml +++ b/examples/counter/src/counter_rs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "counter_rs" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/counter/src/inter2_rs/Cargo.toml b/examples/counter/src/inter2_rs/Cargo.toml index b6f68b4e6..db86938ff 100644 --- a/examples/counter/src/inter2_rs/Cargo.toml +++ b/examples/counter/src/inter2_rs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "inter2_rs" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/counter/src/inter_rs/Cargo.toml b/examples/counter/src/inter_rs/Cargo.toml index 6c90a1f5a..6be96c0f6 100644 --- a/examples/counter/src/inter_rs/Cargo.toml +++ b/examples/counter/src/inter_rs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "inter_rs" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/counter/tests/basic.bats b/examples/counter/tests/basic.bats index b64255c16..eff4af782 100644 --- a/examples/counter/tests/basic.bats +++ b/examples/counter/tests/basic.bats @@ -1,3 +1,5 @@ +load ../../bats/bats-assert/load.bash + # Executed before each test. setup() { cd examples/counter @@ -13,52 +15,55 @@ teardown() { @test "Can counter (counter_rs)" { dfx deploy run dfx canister call counter_rs read - [ "$output" == '(0 : nat)' ] + assert_output '(0 : nat)' dfx canister call counter_rs inc run dfx canister call counter_rs read - [ "$output" == '(1 : nat)' ] + assert_output '(1 : nat)' run dfx canister call counter_rs write '(5)' dfx canister call counter_rs inc run dfx canister call counter_rs read - [ "$output" == '(6 : nat)' ] + assert_output '(6 : nat)' } @test "Can counter (inter_rs)" { dfx deploy run dfx canister call inter_rs read - [ "$output" == '(0 : nat)' ] + assert_output '(0 : nat)' dfx canister call inter_rs inc run dfx canister call inter_rs read - [ "$output" == '(1 : nat)' ] + assert_output '(1 : nat)' run dfx canister call inter_rs write '(5)' dfx canister call inter_rs inc run dfx canister call inter_rs read - [ "$output" == '(6 : nat)' ] + assert_output '(6 : nat)' } @test "Can counter (inter2_rs)" { dfx deploy run dfx canister call counter_rs read - [ "$output" == '(0 : nat)' ] + assert_output '(0 : nat)' run dfx canister call inter2_rs read - [ "$output" == '(0 : nat)' ] + assert_output '(0 : nat)' dfx canister call inter2_rs inc run dfx canister call inter2_rs read - [ "$output" == '(1 : nat)' ] + assert_output '(1 : nat)' run dfx canister call inter2_rs write '(5)' dfx canister call inter2_rs inc run dfx canister call inter2_rs read - [ "$output" == '(6 : nat)' ] + assert_output '(6 : nat)' # Check that counter_rs has 6 too. run dfx canister call counter_rs read - [ "$output" == '(6 : nat)' ] + assert_output '(6 : nat)' } @test "counter_rs generated Candid excludes hidden methods" { dfx build --check counter_rs - ! grep -q update_hidden src/counter_rs/counter.did - ! grep -q query_hidden src/counter_rs/counter.did + run grep -q update_hidden src/counter_rs/counter.did + assert_failure + + run grep -q query_hidden src/counter_rs/counter.did + assert_failure } diff --git a/examples/management_canister/.gitignore b/examples/management_canister/.gitignore new file mode 100644 index 000000000..789b75c9c --- /dev/null +++ b/examples/management_canister/.gitignore @@ -0,0 +1 @@ +ic-btc-canister.wasm.gz diff --git a/examples/management_canister/Cargo.toml b/examples/management_canister/Cargo.toml index c3cc6137b..012852de8 100644 --- a/examples/management_canister/Cargo.toml +++ b/examples/management_canister/Cargo.toml @@ -1,4 +1,3 @@ [workspace] -members = [ - "src/caller", -] +members = ["src/caller"] +resolver = "2" diff --git a/examples/management_canister/tests/basic.bats b/examples/management_canister/tests/basic.bats index aa9fdf7ec..c7ae752b2 100644 --- a/examples/management_canister/tests/basic.bats +++ b/examples/management_canister/tests/basic.bats @@ -1,3 +1,5 @@ +load ../../bats/bats-assert/load.bash + # Executed before each test. setup() { cd examples/management_canister @@ -9,21 +11,31 @@ teardown() { } @test "http_request example succeed" { - dfx start --clean --background --enable-canister-http + dfx start --clean --background # canister-http default on dfx deploy - dfx canister call caller http_request_example + run dfx canister call caller http_request_example + assert_success } @test "ecdsa methods succeed" { dfx start --clean --background dfx deploy - dfx canister call caller execute_ecdsa_methods + run dfx canister call caller execute_ecdsa_methods + assert_success } @test "bitcoin methods succeed" { bitcoind -regtest -daemonwait - dfx start --clean --background --enable-bitcoin + + # The bitcoin canister bundled with dfx 0.18.0 doesn't work with application replica + # As a temporary remedy, we download a previous release. + # TODO: remove when dfx fix, SDKTG-296 + wget -O ic-btc-canister.wasm.gz https://github.com/dfinity/bitcoin-canister/releases/download/release%2F2023-10-13/ic-btc-canister.wasm.gz + DFX_BITCOIN_WASM=ic-btc-canister.wasm.gz dfx start --clean --background --enable-bitcoin + dfx deploy - dfx canister call caller execute_bitcoin_methods + run dfx canister call caller execute_bitcoin_methods + assert_success + bitcoin-cli -regtest stop } diff --git a/examples/print/Cargo.toml b/examples/print/Cargo.toml index 05e27f9e5..08e5fe590 100644 --- a/examples/print/Cargo.toml +++ b/examples/print/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = ["src/print_rs"] +resolver = "2" [workspace.dependencies] ic-cdk = { path = "../../src/ic-cdk" } diff --git a/examples/print/src/print_rs/Cargo.toml b/examples/print/src/print_rs/Cargo.toml index 17fa426d5..365149732 100644 --- a/examples/print/src/print_rs/Cargo.toml +++ b/examples/print/src/print_rs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "print_rs" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/print/tests/basic.bats b/examples/print/tests/basic.bats index db5028e4b..959f86313 100644 --- a/examples/print/tests/basic.bats +++ b/examples/print/tests/basic.bats @@ -1,3 +1,5 @@ +load ../../bats/bats-assert/load.bash + # Executed before each test. setup() { cd examples/print @@ -13,5 +15,6 @@ teardown() { @test "Can print" { dfx deploy - dfx canister call print print + run dfx canister call print print + assert_success } diff --git a/examples/profile/Cargo.toml b/examples/profile/Cargo.toml index 1a45abae6..f860ac065 100644 --- a/examples/profile/Cargo.toml +++ b/examples/profile/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = ["src/profile_rs", "src/profile_inter_rs"] +resolver = "2" [workspace.dependencies] candid = "0.10" diff --git a/examples/profile/src/profile_inter_rs/Cargo.toml b/examples/profile/src/profile_inter_rs/Cargo.toml index ed40ee0f5..bb44f33a3 100644 --- a/examples/profile/src/profile_inter_rs/Cargo.toml +++ b/examples/profile/src/profile_inter_rs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "profile_inter_rs" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/profile/src/profile_rs/Cargo.toml b/examples/profile/src/profile_rs/Cargo.toml index 701f1bfa7..bbd1f0447 100644 --- a/examples/profile/src/profile_rs/Cargo.toml +++ b/examples/profile/src/profile_rs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "profile_rs" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/profile/tests/basic.bats b/examples/profile/tests/basic.bats index 9979ed807..e2edbfe22 100644 --- a/examples/profile/tests/basic.bats +++ b/examples/profile/tests/basic.bats @@ -1,4 +1,3 @@ -load ../../bats/bats-support/load.bash load ../../bats/bats-assert/load.bash # Executed before each test. @@ -16,27 +15,27 @@ teardown() { dfx deploy run dfx canister call profile-rs getSelf - assert_success assert_output '(record { name = ""; description = ""; keywords = vec {} })' + run dfx canister call profile-rs update 'record {"name"= "abc"; "description"="123"; "keywords"= vec {} }' assert_success + run dfx canister call profile-rs get abc - assert_success assert_output '(record { name = "abc"; description = "123"; keywords = vec {} })' + run dfx canister call profile-rs search ab - assert_success assert_output '(opt record { name = "abc"; description = "123"; keywords = vec {} })' run dfx canister call profile-inter-rs getSelf - assert_success assert_output '(record { name = ""; description = ""; keywords = vec {} })' + run dfx canister call profile-inter-rs update 'record {"name"= "def"; "description"="456"; "keywords"= vec {} }' assert_success + run dfx canister call profile-inter-rs get def - assert_success assert_output '(record { name = "def"; description = "456"; keywords = vec {} })' + run dfx canister call profile-inter-rs search de - assert_success assert_output '(opt record { name = "def"; description = "456"; keywords = vec {} })' } From a47fd6d1a838d43afc30cd7fcaccc556498c68a2 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 29 Mar 2024 13:28:59 -0400 Subject: [PATCH 200/234] feat: provide safe wrapper of global_timer_set in ic-cdk (#475) * feat: provide safe wrapper of global_timer_set in ic-cdk * changelog * e2e test --- e2e-tests/canisters/timers.rs | 5 +++++ e2e-tests/tests/e2e.rs | 33 +++++++++++++++++++++++++++++++++ src/ic-cdk/CHANGELOG.md | 4 ++++ src/ic-cdk/src/api/mod.rs | 17 +++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/e2e-tests/canisters/timers.rs b/e2e-tests/canisters/timers.rs index ec277fa8f..03433aaa8 100644 --- a/e2e-tests/canisters/timers.rs +++ b/e2e-tests/canisters/timers.rs @@ -92,4 +92,9 @@ fn add_event(event: &'static str) { EVENTS.with(|events| events.borrow_mut().push(event)); } +#[update] +fn set_global_timer(timestamp: u64) -> u64 { + ic_cdk::api::set_global_timer(timestamp) +} + fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 6957dfcee..650849f19 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -269,6 +269,39 @@ fn advance_seconds(env: &StateMachine, seconds: u32) { } } +#[test] +fn test_set_global_timers() { + // Must be more than the queue limit (500) + let env = env(); + let system_time = std::time::SystemTime::now(); + + env.set_time(system_time); + + let wasm = cargo_build_canister("timers"); + let canister_id = env.create_canister(None); + env.install_canister(canister_id, wasm, vec![], None); + + call_candid::<_, ()>(&env, canister_id, "schedule_long", ()) + .expect("Failed to call schedule_long"); + let ts0 = system_time + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_nanos() as u64 + + 9_000_000_000; // the long event is scheduled 9 seconds from ts0 + advance_seconds(&env, 5); + + // set the timer to 5 seconds from ts0 + let ts1 = ts0 + 5_000_000_000; + let (previous,) = call_candid::<(u64,), (u64,)>(&env, canister_id, "set_global_timer", (ts1,)) + .expect("Failed to call set_global_timer"); + assert_eq!(previous, ts0); + + // deactivate the timer + let (previous,) = call_candid::<(u64,), (u64,)>(&env, canister_id, "set_global_timer", (0,)) + .expect("Failed to call set_global_timer"); + assert_eq!(previous, ts1); +} + #[test] fn test_canister_info() { let env = env(); diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index d6923d5ea..ef04c40b6 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Added + +- Provide safe wrapper of global_timer_set in ic-cdk. (#475) + ## [0.13.1] - 2024-03-01 ### Changed diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index 98d13ca16..5a2d5fcf2 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -176,3 +176,20 @@ pub fn cycles_burn(amount: u128) -> u128 { } dst } + +/// Sets global timer. +/// +/// The canister can set a global timer to make the system +/// schedule a call to the exported canister_global_timer +/// Wasm method after the specified time. +/// The time must be provided as nanoseconds since 1970-01-01. +/// +/// The function returns the previous value of the timer. +/// If no timer is set before invoking the function, then the function returns zero. +/// +/// Passing zero as an argument to the function deactivates the timer and thus +/// prevents the system from scheduling calls to the canister's canister_global_timer Wasm method. +pub fn set_global_timer(timestamp: u64) -> u64 { + // SAFETY: ic0.global_timer_set is always safe to call. + unsafe { ic0::global_timer_set(timestamp as i64) as u64 } +} From db3b0ef81e891bd25f4e7088ae8845214631c49c Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 2 Apr 2024 12:52:25 -0400 Subject: [PATCH 201/234] chore(ci): remove temporary fix for bitcoin integration canister (#474) * try beta * remove with beta * remove outdated comment --- examples/management_canister/tests/basic.bats | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/management_canister/tests/basic.bats b/examples/management_canister/tests/basic.bats index c7ae752b2..8c51a7fa8 100644 --- a/examples/management_canister/tests/basic.bats +++ b/examples/management_canister/tests/basic.bats @@ -27,11 +27,7 @@ teardown() { @test "bitcoin methods succeed" { bitcoind -regtest -daemonwait - # The bitcoin canister bundled with dfx 0.18.0 doesn't work with application replica - # As a temporary remedy, we download a previous release. - # TODO: remove when dfx fix, SDKTG-296 - wget -O ic-btc-canister.wasm.gz https://github.com/dfinity/bitcoin-canister/releases/download/release%2F2023-10-13/ic-btc-canister.wasm.gz - DFX_BITCOIN_WASM=ic-btc-canister.wasm.gz dfx start --clean --background --enable-bitcoin + dfx start --clean --background --enable-bitcoin dfx deploy run dfx canister call caller execute_bitcoin_methods From 2d3f76e95af956d5fdfbfbe16955eea92815a7d3 Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Mon, 8 Apr 2024 16:44:31 +0100 Subject: [PATCH 202/234] feat: add management canister methods for interacting with the chunk store (#461) * feat: add management canister methods for interacting with the chunk store * Update CHANGELOG * fmt * IC spec change * Serialize with `serde_bytes` * fix: names * test: e2e chunk * chore: upgrade state-machine binary * chore: cargo fmt & clippy * fix: clippy * fix: make the tests pass * conform final spec --------- Co-authored-by: Linwei Shang --- e2e-tests/Cargo.toml | 4 + e2e-tests/canisters/canister_info.rs | 2 +- e2e-tests/canisters/chunk.rs | 64 +++++++ e2e-tests/tests/e2e.rs | 85 ++++++++- scripts/download_state_machine_binary.sh | 2 +- src/ic-cdk/CHANGELOG.md | 1 + .../src/api/management_canister/main/mod.rs | 41 +++++ .../src/api/management_canister/main/types.rs | 161 ++++++++++++++++-- 8 files changed, 339 insertions(+), 21 deletions(-) create mode 100644 e2e-tests/canisters/chunk.rs diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 39e8319ba..a5fe20ec5 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -47,6 +47,10 @@ path = "canisters/canister_info.rs" name = "management_caller" path = "canisters/management_caller.rs" +[[bin]] +name = "chunk" +path = "canisters/chunk.rs" + [dev-dependencies] hex.workspace = true ic-test-state-machine-client = "3" diff --git a/e2e-tests/canisters/canister_info.rs b/e2e-tests/canisters/canister_info.rs index 32700497c..b04d38a34 100644 --- a/e2e-tests/canisters/canister_info.rs +++ b/e2e-tests/canisters/canister_info.rs @@ -54,7 +54,7 @@ async fn canister_lifecycle() -> Principal { .await .unwrap(); install_code(InstallCodeArgument { - mode: Upgrade, + mode: Upgrade(None), arg: vec![], wasm_module: vec![0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00], canister_id: canister_id.canister_id, diff --git a/e2e-tests/canisters/chunk.rs b/e2e-tests/canisters/chunk.rs new file mode 100644 index 000000000..ad46f7d3f --- /dev/null +++ b/e2e-tests/canisters/chunk.rs @@ -0,0 +1,64 @@ +use candid::Principal; +use ic_cdk::api::management_canister::main::{ + clear_chunk_store, create_canister, install_chunked_code, stored_chunks, upload_chunk, + CanisterInstallMode, ChunkHash, ClearChunkStoreArgument, CreateCanisterArgument, + InstallChunkedCodeArgument, StoredChunksArgument, UploadChunkArgument, +}; +use ic_cdk::update; + +#[update] +async fn call_create_canister() -> Principal { + let arg = CreateCanisterArgument::default(); + + create_canister(arg, 100_000_000_000u128) + .await + .unwrap() + .0 + .canister_id +} + +#[update] +async fn call_upload_chunk(canister_id: Principal, chunk: Vec) -> Vec { + let arg = UploadChunkArgument { + canister_id, + chunk: chunk.to_vec(), + }; + + upload_chunk(arg).await.unwrap().0.hash +} + +#[update] +async fn call_stored_chunks(canister_id: Principal) -> Vec> { + let arg = StoredChunksArgument { canister_id }; + let hashes = stored_chunks(arg).await.unwrap().0; + hashes.into_iter().map(|v| v.hash).collect() +} + +#[update] +async fn call_clear_chunk_store(canister_id: Principal) { + let arg = ClearChunkStoreArgument { canister_id }; + clear_chunk_store(arg).await.unwrap(); +} + +#[update] +async fn call_install_chunked_code( + canister_id: Principal, + chunk_hashes_list: Vec>, + wasm_module_hash: Vec, +) { + let chunk_hashes_list = chunk_hashes_list + .iter() + .map(|v| ChunkHash { hash: v.clone() }) + .collect(); + let arg = InstallChunkedCodeArgument { + mode: CanisterInstallMode::Install, + target_canister: canister_id, + store_canister: None, + chunk_hashes_list, + wasm_module_hash, + arg: vec![], + }; + install_chunked_code(arg).await.unwrap(); +} + +fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 650849f19..bf9541df6 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -1,10 +1,11 @@ use std::time::Duration; +use std::time::SystemTime; use candid::{Encode, Principal}; use ic_cdk::api::management_canister::main::{ CanisterChange, CanisterChangeDetails, CanisterChangeOrigin, CanisterIdRecord, - CanisterInfoResponse, - CanisterInstallMode::{Install, Reinstall, Upgrade}, + CanisterInfoResponse, CanisterInstallMode, + CodeDeploymentMode::{Install, Reinstall, Upgrade}, CodeDeploymentRecord, ControllersChangeRecord, CreationRecord, FromCanisterRecord, FromUserRecord, InstallCodeArgument, }; @@ -13,7 +14,7 @@ use ic_test_state_machine_client::{ call_candid, call_candid_as, query_candid, CallError, ErrorCode, StateMachine, WasmResult, }; use serde_bytes::ByteBuf; -use std::time::SystemTime; +use sha2::Digest; pub static STATE_MACHINE_BINARY: &str = "../ic-test-state-machine"; @@ -329,7 +330,7 @@ fn test_canister_info() { Principal::anonymous(), "install_code", (InstallCodeArgument { - mode: Install, + mode: CanisterInstallMode::Install, arg: vec![], wasm_module: vec![0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00], canister_id: new_canister.0, @@ -518,3 +519,79 @@ fn call_management() { let () = call_candid(&env, canister_id, "execute_provisional_methods", ()) .expect("Error calling execute_provisional_methods"); } + +#[test] +fn test_chunk() { + let env = env(); + let wasm = cargo_build_canister("chunk"); + let canister_id = env.create_canister(None); + env.add_cycles(canister_id, 100_000_000_000_000); + env.install_canister(canister_id, wasm, vec![], None); + let (target_canister_id,): (Principal,) = + call_candid(&env, canister_id, "call_create_canister", ()) + .expect("Error calling call_create_canister"); + + let wasm_module = b"\x00asm\x01\x00\x00\x00".to_vec(); + let wasm_module_hash = sha2::Sha256::digest(&wasm_module).to_vec(); + let chunk1 = wasm_module[..4].to_vec(); + let chunk2 = wasm_module[4..].to_vec(); + let hash1_expected = sha2::Sha256::digest(&chunk1).to_vec(); + let hash2_expected = sha2::Sha256::digest(&chunk2).to_vec(); + + let (hash1_return,): (Vec,) = call_candid( + &env, + canister_id, + "call_upload_chunk", + (target_canister_id, chunk1.clone()), + ) + .expect("Error calling call_upload_chunk"); + assert_eq!(&hash1_return, &hash1_expected); + + let () = call_candid( + &env, + canister_id, + "call_clear_chunk_store", + (target_canister_id,), + ) + .expect("Error calling call_clear_chunk_store"); + + let (_hash1_return,): (Vec,) = call_candid( + &env, + canister_id, + "call_upload_chunk", + (target_canister_id, chunk1), + ) + .expect("Error calling call_upload_chunk"); + let (_hash2_return,): (Vec,) = call_candid( + &env, + canister_id, + "call_upload_chunk", + (target_canister_id, chunk2), + ) + .expect("Error calling call_upload_chunk"); + + let (hashes,): (Vec>,) = call_candid( + &env, + canister_id, + "call_stored_chunks", + (target_canister_id,), + ) + .expect("Error calling call_stored_chunks"); + // the hashes returned are not guaranteed to be in order + assert_eq!(hashes.len(), 2); + assert!(hashes.contains(&hash1_expected)); + assert!(hashes.contains(&hash2_expected)); + + let () = call_candid( + &env, + canister_id, + "call_install_chunked_code", + ( + target_canister_id, + // the order of the hashes matters + vec![hash1_expected, hash2_expected], + wasm_module_hash, + ), + ) + .expect("Error calling call_install_chunked_code"); +} diff --git a/scripts/download_state_machine_binary.sh b/scripts/download_state_machine_binary.sh index 7f9aae609..1f75ff622 100755 --- a/scripts/download_state_machine_binary.sh +++ b/scripts/download_state_machine_binary.sh @@ -10,7 +10,7 @@ uname_sys=$(uname -s | tr '[:upper:]' '[:lower:]') echo "uname_sys: $uname_sys" # Check https://gitlab.com/dfinity-lab/public/ic/-/commits/master # Find the most recent commit with a green check mark (the artifacts were built successfully) -commit_sha="f3216c1d7d83a366b4af0cf24708f84819880246" +commit_sha="ba6d8b136549f0acf8a2eafddab031156d53accd" curl -sLO "https://download.dfinity.systems/ic/$commit_sha/binaries/x86_64-$uname_sys/ic-test-state-machine.gz" gzip -d ic-test-state-machine.gz diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index ef04c40b6..5bc6aa81e 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Management canister methods for interacting with the chunk store. (#461) - Provide safe wrapper of global_timer_set in ic-cdk. (#475) ## [0.13.1] - 2024-03-01 diff --git a/src/ic-cdk/src/api/management_canister/main/mod.rs b/src/ic-cdk/src/api/management_canister/main/mod.rs index 02a83d028..d1cd9de3e 100644 --- a/src/ic-cdk/src/api/management_canister/main/mod.rs +++ b/src/ic-cdk/src/api/management_canister/main/mod.rs @@ -52,6 +52,26 @@ pub async fn update_settings(arg: UpdateSettingsArgument) -> CallResult<()> { .await } +/// See [IC method `upload_chunk`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-upload_chunk). +pub async fn upload_chunk(arg: UploadChunkArgument) -> CallResult<(ChunkHash,)> { + call(Principal::management_canister(), "upload_chunk", (arg,)).await +} + +/// See [IC method `clear_chunk_store`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-clear_chunk_store). +pub async fn clear_chunk_store(arg: ClearChunkStoreArgument) -> CallResult<()> { + call( + Principal::management_canister(), + "clear_chunk_store", + (arg,), + ) + .await +} + +/// See [IC method `stored_chunks`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-stored_chunks). +pub async fn stored_chunks(arg: StoredChunksArgument) -> CallResult<(Vec,)> { + call(Principal::management_canister(), "stored_chunks", (arg,)).await +} + /// Install code into a canister. /// /// See [IC method `install_code`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-install_code). @@ -71,6 +91,27 @@ pub async fn install_code(arg: InstallCodeArgument) -> CallResult<()> { .await } +/// Install code into a canister where the code has previously been uploaded in chunks. +/// +/// See [IC method `install_chunked_code`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-install_chunked_code). +pub async fn install_chunked_code(arg: InstallChunkedCodeArgument) -> CallResult<()> { + let extended_arg = InstallChunkedCodeArgumentExtended { + mode: arg.mode, + target_canister: arg.target_canister, + store_canister: arg.store_canister, + chunk_hashes_list: arg.chunk_hashes_list, + wasm_module_hash: arg.wasm_module_hash, + arg: arg.arg, + sender_canister_version: Some(canister_version()), + }; + call( + Principal::management_canister(), + "install_chunked_code", + (extended_arg,), + ) + .await +} + /// Remove a canister's code and state, making the canister empty again. /// /// See [IC method `uninstall_code`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-uninstall_code). diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index a76547769..5499c5087 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -48,7 +48,7 @@ pub(crate) struct CreateCanisterArgumentExtended { CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, )] pub struct UpdateSettingsArgument { - /// Principle of the canister. + /// Principal of the canister. pub canister_id: CanisterId, /// See [CanisterSettings]. pub settings: CanisterSettings, @@ -58,7 +58,7 @@ pub struct UpdateSettingsArgument { CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, )] pub(crate) struct UpdateSettingsArgumentExtended { - /// Principle of the canister. + /// Principal of the canister. pub canister_id: CanisterId, /// See [CanisterSettings]. pub settings: CanisterSettings, @@ -66,23 +66,94 @@ pub(crate) struct UpdateSettingsArgumentExtended { pub sender_canister_version: Option, } +/// Argument type of [update_chunk](super::update_chunk). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct UploadChunkArgument { + /// The canister whose chunk store the chunk will be uploaded to + pub canister_id: CanisterId, + /// The chunk bytes (max size 1MB) + #[serde(with = "serde_bytes")] + pub chunk: Vec, +} + +/// Return type of [upload_chunk](super::upload_chunk) and [stored_chunks](super::stored_chunks). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct ChunkHash { + /// The hash of an uploaded chunk + #[serde(with = "serde_bytes")] + pub hash: Vec, +} + +/// Argument type of [clear_chunk_store](super::clear_chunk_store). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct ClearChunkStoreArgument { + /// The canister whose chunk store will be cleared + pub canister_id: CanisterId, +} + +/// Argument type of [stored_chunks](super::stored_chunks). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct StoredChunksArgument { + /// The canister whose chunk store will be queried + pub canister_id: CanisterId, +} + /// The mode with which a canister is installed. +/// +/// This second version of the mode allows someone to specify the +/// optional `SkipPreUpgrade` parameter in case of an upgrade #[derive( - CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, + CandidType, + Serialize, + Deserialize, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Clone, + Copy, + Default, )] -// #[serde(rename_all = "lowercase")] pub enum CanisterInstallMode { /// A fresh install of a new canister. #[serde(rename = "install")] + #[default] Install, /// Reinstalling a canister that was already installed. #[serde(rename = "reinstall")] Reinstall, /// Upgrade an existing canister. #[serde(rename = "upgrade")] - Upgrade, + Upgrade(Option), } +/// If set to true, the pre_upgrade step will be skipped during the canister upgrade +#[derive( + CandidType, + Serialize, + Deserialize, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Clone, + Copy, + Default, +)] +pub struct SkipPreUpgrade(pub Option); + /// WASM module. pub type WasmModule = Vec; @@ -93,7 +164,7 @@ pub type WasmModule = Vec; pub struct InstallCodeArgument { /// See [CanisterInstallMode]. pub mode: CanisterInstallMode, - /// Principle of the canister. + /// Principal of the canister. pub canister_id: CanisterId, /// Code to be installed. pub wasm_module: WasmModule, @@ -107,7 +178,7 @@ pub struct InstallCodeArgument { pub(crate) struct InstallCodeArgumentExtended { /// See [CanisterInstallMode]. pub mode: CanisterInstallMode, - /// Principle of the canister. + /// Principal of the canister. pub canister_id: CanisterId, /// Code to be installed. pub wasm_module: WasmModule, @@ -117,12 +188,55 @@ pub(crate) struct InstallCodeArgumentExtended { pub sender_canister_version: Option, } +/// Argument type of [install_chunked_code](super::install_chunked_code). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct InstallChunkedCodeArgument { + /// See [CanisterInstallMode]. + pub mode: CanisterInstallMode, + /// Principal of the canister being installed + pub target_canister: CanisterId, + /// The canister in whose chunk storage the chunks are stored (defaults to target_canister if not specified) + pub store_canister: Option, + /// The list of chunks that make up the canister wasm + pub chunk_hashes_list: Vec, + /// The sha256 hash of the wasm + #[serde(with = "serde_bytes")] + pub wasm_module_hash: Vec, + /// The argument to be passed to `canister_init` or `canister_post_upgrade` + #[serde(with = "serde_bytes")] + pub arg: Vec, +} + +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub(crate) struct InstallChunkedCodeArgumentExtended { + /// See [CanisterInstallMode]. + pub mode: CanisterInstallMode, + /// Principal of the canister being installed + pub target_canister: CanisterId, + /// The canister in whose chunk storage the chunks are stored (defaults to target_canister if not specified) + pub store_canister: Option, + /// The list of chunks that make up the canister wasm + pub chunk_hashes_list: Vec, + /// The sha256 hash of the wasm + #[serde(with = "serde_bytes")] + pub wasm_module_hash: Vec, + /// The argument to be passed to `canister_init` or `canister_post_upgrade`. + #[serde(with = "serde_bytes")] + pub arg: Vec, + /// sender_canister_version must be set to ic_cdk::api::canister_version() + pub sender_canister_version: Option, +} + /// A wrapper of canister id. #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, )] pub struct CanisterIdRecord { - /// Principle of the canister. + /// Principal of the canister. pub canister_id: CanisterId, } @@ -130,7 +244,7 @@ pub struct CanisterIdRecord { CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, )] pub(crate) struct CanisterIdRecordExtended { - /// Principle of the canister. + /// Principal of the canister. pub canister_id: CanisterId, /// sender_canister_version must be set to ic_cdk::api::canister_version() pub sender_canister_version: Option, @@ -184,7 +298,7 @@ pub struct QueryStats { pub response_payload_bytes_total: candid::Nat, } -/// Argument type of [canister_status](super::canister_status). +/// Return type of [canister_status](super::canister_status). #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, )] @@ -215,7 +329,7 @@ pub struct CanisterStatusResponse { CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, )] pub struct FromUserRecord { - /// Principle of the user. + /// Principal of the user. pub user_id: Principal, } @@ -224,7 +338,7 @@ pub struct FromUserRecord { CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, )] pub struct FromCanisterRecord { - /// Principle of the originator. + /// Principal of the originator. pub canister_id: Principal, /// Canister version of the originator when the originator initiated the change. /// This is null if the original does not include its canister version @@ -254,13 +368,30 @@ pub struct CreationRecord { pub controllers: Vec, } +/// The mode with which a canister is installed. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, +)] +// #[serde(rename_all = "lowercase")] +pub enum CodeDeploymentMode { + /// A fresh install of a new canister. + #[serde(rename = "install")] + Install, + /// Reinstalling a canister that was already installed. + #[serde(rename = "reinstall")] + Reinstall, + /// Upgrade an existing canister. + #[serde(rename = "upgrade")] + Upgrade, +} + /// Details about a canister code deployment. #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, )] pub struct CodeDeploymentRecord { - /// See [CanisterInstallMode]. - pub mode: CanisterInstallMode, + /// See [CodeDeploymentMode]. + pub mode: CodeDeploymentMode, /// A SHA256 hash of the new module installed on the canister. pub module_hash: Vec, } @@ -313,7 +444,7 @@ pub struct CanisterChange { CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, )] pub struct CanisterInfoRequest { - /// Principle of the canister. + /// Principal of the canister. pub canister_id: Principal, /// Number of most recent changes requested to be retrieved from canister history. /// No changes are retrieved if this field is null. From a7650a281036515d53a9fc7f1c141f5a25793c32 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 8 Apr 2024 13:04:38 -0400 Subject: [PATCH 203/234] chore: release ic-cdk v0.13.2 (#478) --- Cargo.lock | 4 ++-- Cargo.toml | 3 +-- src/ic-cdk-macros/CHANGELOG.md | 6 ++++++ src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 2 ++ src/ic-cdk/Cargo.toml | 4 ++-- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f28a9ec9e..6f2b1b3fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -875,7 +875,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "ic-cdk" -version = "0.13.1" +version = "0.13.2" dependencies = [ "anyhow", "candid", @@ -914,7 +914,7 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.9.0" +version = "0.13.2" dependencies = [ "candid", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index ba126f4f0..8c240e513 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.21.1" } -ic-cdk = { path = "src/ic-cdk", version = "0.13.0" } +ic-cdk = { path = "src/ic-cdk", version = "0.13.2"} ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.7.0" } candid = "0.10.4" @@ -34,4 +34,3 @@ serde_bytes = "0.11" sha2 = "0.10" slotmap = "1" syn = "1" - diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index 14fd1a1d7..1393753d8 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.13.2] - 2024-04-08 + +### Changed + +- `ic-cdk-macros` will have the same version as the `ic-cdk`. + ## [0.9.0] - 2024-03-01 ### Fixed diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index d56ac4d0d..5b233489b 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.9.0" # no need to sync with ic-cdk +version = "0.13.2" # sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 5bc6aa81e..0532d2f13 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.13.2] - 2024-04-08 + ### Added - Management canister methods for interacting with the chunk store. (#461) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 0e73a24ec..1993d34a3 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.13.1" +version = "0.13.2" # sync with ic-cdk-macros authors.workspace = true edition.workspace = true license.workspace = true @@ -27,7 +27,7 @@ ic0.workspace = true # Dependents won't accidentaly upgrading ic-cdk-macros only but not ic-cdk. # ic-cdk-macros is a hidden dependency, re-exported by ic-cdk. # It should not be included by users direcly. -ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.9.0" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.13.2" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true } From 681008a386f7d508256031e64c1da43e371743bd Mon Sep 17 00:00:00 2001 From: Severin Siffert Date: Wed, 10 Apr 2024 17:37:26 +0200 Subject: [PATCH 204/234] feat: Re-generate bindings if canister id or candid path change (#479) --- src/ic-cdk-bindgen/CHANGELOG.md | 2 ++ src/ic-cdk-bindgen/src/lib.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/ic-cdk-bindgen/CHANGELOG.md b/src/ic-cdk-bindgen/CHANGELOG.md index 31b9ef646..4ea9e69e3 100644 --- a/src/ic-cdk-bindgen/CHANGELOG.md +++ b/src/ic-cdk-bindgen/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +- Re-generate bindings if the canister ids changed (e.g. when switching networks) or when the path to the candid file of a dependency changed. + ## [0.1.3] - 2024-02-27 - Resolve CANISTER_CANDID_PATH and CANISTER_ID from standardized environment variables (uppercase canister names). diff --git a/src/ic-cdk-bindgen/src/lib.rs b/src/ic-cdk-bindgen/src/lib.rs index 4773b4f47..265351ecc 100644 --- a/src/ic-cdk-bindgen/src/lib.rs +++ b/src/ic-cdk-bindgen/src/lib.rs @@ -53,6 +53,8 @@ fn resolve_candid_path_and_canister_id(canister_name: &str) -> (PathBuf, Princip let candid_path_var_name = format!("CANISTER_CANDID_PATH_{}", canister_name_upper); let candid_path_var_name_legacy = format!("CANISTER_CANDID_PATH_{}", canister_name); + println!("cargo:rerun-if-env-changed={candid_path_var_name}"); + println!("cargo:rerun-if-env-changed={candid_path_var_name_legacy}"); let candid_path_str = if let Ok(candid_path_str) = env::var(&candid_path_var_name) { candid_path_str @@ -69,6 +71,8 @@ fn resolve_candid_path_and_canister_id(canister_name: &str) -> (PathBuf, Princip let canister_id_var_name = format!("CANISTER_ID_{}", canister_name_upper); let canister_id_var_name_legacy = format!("CANISTER_ID_{}", canister_name); + println!("cargo:rerun-if-env-changed={canister_id_var_name}"); + println!("cargo:rerun-if-env-changed={canister_id_var_name_legacy}"); let canister_id_str = if let Ok(canister_id_str) = env::var(&canister_id_var_name) { canister_id_str } else if let Ok(canister_id_str) = env::var(&canister_id_var_name_legacy) { From dc582aec71a630029cf9defd5263c256b7159c6c Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 12 Apr 2024 14:45:19 -0400 Subject: [PATCH 205/234] refactor!: move Rust code generation logic from candid_parser. (#480) * refactor!(bindgen): move Rust codegen logic from candid_parser * changelog * revert unnecessary changes --- Cargo.lock | 3 + src/ic-cdk-bindgen/CHANGELOG.md | 24 +- src/ic-cdk-bindgen/Cargo.toml | 3 + src/ic-cdk-bindgen/src/code_generator.rs | 667 +++++++++++++++++++++++ src/ic-cdk-bindgen/src/lib.rs | 13 +- 5 files changed, 700 insertions(+), 10 deletions(-) create mode 100644 src/ic-cdk-bindgen/src/code_generator.rs diff --git a/Cargo.lock b/Cargo.lock index 6f2b1b3fe..3a71713f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -892,7 +892,10 @@ dependencies = [ name = "ic-cdk-bindgen" version = "0.1.3" dependencies = [ + "candid", "candid_parser", + "convert_case", + "pretty", ] [[package]] diff --git a/src/ic-cdk-bindgen/CHANGELOG.md b/src/ic-cdk-bindgen/CHANGELOG.md index 4ea9e69e3..6c1c2941a 100644 --- a/src/ic-cdk-bindgen/CHANGELOG.md +++ b/src/ic-cdk-bindgen/CHANGELOG.md @@ -6,23 +6,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -- Re-generate bindings if the canister ids changed (e.g. when switching networks) or when the path to the candid file of a dependency changed. +### Changed + +- Refactor!: move Rust code generation logic from candid_parser. (#480) + +### Fixed + +- Re-generate bindings if the canister ids changed (e.g. when switching networks) or when the path to the candid file of a dependency changed. (#479) ## [0.1.3] - 2024-02-27 -- Resolve CANISTER_CANDID_PATH and CANISTER_ID from standardized environment variables (uppercase canister names). +### Added + +- Resolve CANISTER_CANDID_PATH and CANISTER_ID from standardized environment variables (uppercase canister names). (#467) - The support for legacy (non-uppercase) env vars is kept. - It will be removed in next major release (v0.2). ## [0.1.2] - 2023-11-23 -- Change `candid` dependency to the new `candid_parser` library. +### Changed + +- Change `candid` dependency to the new `candid_parser` library. (#448) More details here: https://github.com/dfinity/candid/blob/master/Changelog.md#2023-11-16-rust-0100 ## [0.1.1] - 2023-09-18 -- Update `candid` dependency to 0.9.6 which change the Rust bindings. +### Changed + +- Update `candid` dependency to 0.9.6 which change the Rust bindings. (#424) ## [0.1.0] - 2023-07-13 -- First release. +### Added + +- First release. (#416) diff --git a/src/ic-cdk-bindgen/Cargo.toml b/src/ic-cdk-bindgen/Cargo.toml index e3f252ebc..27d34828f 100644 --- a/src/ic-cdk-bindgen/Cargo.toml +++ b/src/ic-cdk-bindgen/Cargo.toml @@ -13,4 +13,7 @@ keywords = ["internet-computer", "types", "dfinity", "canister", "cdk"] include = ["src", "Cargo.toml", "LICENSE", "README.md"] [dependencies] +candid.workspace = true candid_parser.workspace = true +convert_case = "0.6" +pretty = "0.12" diff --git a/src/ic-cdk-bindgen/src/code_generator.rs b/src/ic-cdk-bindgen/src/code_generator.rs new file mode 100644 index 000000000..57cecc142 --- /dev/null +++ b/src/ic-cdk-bindgen/src/code_generator.rs @@ -0,0 +1,667 @@ +use candid::pretty::utils::*; +use candid::types::{Field, Function, Label, SharedLabel, Type, TypeEnv, TypeInner}; +use candid_parser::bindings::analysis::{chase_actor, infer_rec}; +use convert_case::{Case, Casing}; +use pretty::RcDoc; +use std::collections::BTreeSet; + +#[derive(Clone)] +pub enum Target { + CanisterCall, + Agent, + CanisterStub, +} + +#[derive(Clone)] +pub struct Config { + candid_crate: String, + type_attributes: String, + canister_id: Option, + service_name: String, + target: Target, +} +impl Config { + pub fn new() -> Self { + Config { + candid_crate: "candid".to_string(), + type_attributes: "".to_string(), + canister_id: None, + service_name: "service".to_string(), + target: Target::CanisterCall, + } + } + pub fn set_candid_crate(&mut self, name: String) -> &mut Self { + self.candid_crate = name; + self + } + /// Applies to all types for now + pub fn set_type_attributes(&mut self, attr: String) -> &mut Self { + self.type_attributes = attr; + self + } + /// Only generates SERVICE struct if canister_id is not provided + pub fn set_canister_id(&mut self, id: candid::Principal) -> &mut Self { + self.canister_id = Some(id); + self + } + /// Service name when canister id is provided + pub fn set_service_name(&mut self, name: String) -> &mut Self { + self.service_name = name; + self + } + pub fn set_target(&mut self, name: Target) -> &mut Self { + self.target = name; + self + } +} +impl Default for Config { + fn default() -> Self { + Self::new() + } +} + +type RecPoints<'a> = BTreeSet<&'a str>; +// The definition of tuple is language specific. +pub(crate) fn is_tuple(fs: &[Field]) -> bool { + if fs.is_empty() { + return false; + } + !fs.iter() + .enumerate() + .any(|(i, field)| field.id.get_id() != (i as u32)) +} +static KEYWORDS: [&str; 51] = [ + "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for", + "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", + "self", "Self", "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where", + "while", "async", "await", "dyn", "abstract", "become", "box", "do", "final", "macro", + "override", "priv", "typeof", "unsized", "virtual", "yield", "try", +]; +fn ident_(id: &str, case: Option) -> (RcDoc, bool) { + if id.is_empty() + || id.starts_with(|c: char| !c.is_ascii_alphabetic() && c != '_') + || id.chars().any(|c| !c.is_ascii_alphanumeric() && c != '_') + { + return (RcDoc::text(format!("_{}_", candid::idl_hash(id))), true); + } + let (is_rename, id) = if let Some(case) = case { + let new_id = id.to_case(case); + (new_id != id, new_id) + } else { + (false, id.to_owned()) + }; + if ["crate", "self", "super", "Self", "Result", "Principal"].contains(&id.as_str()) { + (RcDoc::text(format!("{id}_")), true) + } else if KEYWORDS.contains(&id.as_str()) { + (RcDoc::text(format!("r#{id}")), is_rename) + } else { + (RcDoc::text(id), is_rename) + } +} +fn ident(id: &str, case: Option) -> RcDoc { + ident_(id, case).0 +} + +fn pp_ty<'a>(ty: &'a Type, recs: &RecPoints) -> RcDoc<'a> { + use TypeInner::*; + match ty.as_ref() { + Null => str("()"), + Bool => str("bool"), + Nat => str("candid::Nat"), + Int => str("candid::Int"), + Nat8 => str("u8"), + Nat16 => str("u16"), + Nat32 => str("u32"), + Nat64 => str("u64"), + Int8 => str("i8"), + Int16 => str("i16"), + Int32 => str("i32"), + Int64 => str("i64"), + Float32 => str("f32"), + Float64 => str("f64"), + Text => str("String"), + Reserved => str("candid::Reserved"), + Empty => str("candid::Empty"), + Var(ref id) => { + let name = ident(id, Some(Case::Pascal)); + if recs.contains(id.as_str()) { + str("Box<").append(name).append(">") + } else { + name + } + } + Principal => str("Principal"), + Opt(ref t) => str("Option").append(enclose("<", pp_ty(t, recs), ">")), + // It's a bit tricky to use `deserialize_with = "serde_bytes"`. It's not working for `type t = blob` + Vec(ref t) if matches!(t.as_ref(), Nat8) => str("serde_bytes::ByteBuf"), + Vec(ref t) => str("Vec").append(enclose("<", pp_ty(t, recs), ">")), + Record(ref fs) => pp_record_fields(fs, recs, ""), + Variant(_) => unreachable!(), // not possible after rewriting + Func(_) => unreachable!(), // not possible after rewriting + Service(_) => unreachable!(), // not possible after rewriting + Class(_, _) => unreachable!(), + Knot(_) | Unknown | Future => unreachable!(), + } +} + +fn pp_label<'a>(id: &'a SharedLabel, is_variant: bool, vis: &'a str) -> RcDoc<'a> { + let vis = if vis.is_empty() { + RcDoc::nil() + } else { + kwd(vis) + }; + match &**id { + Label::Named(id) => { + let case = if is_variant { Some(Case::Pascal) } else { None }; + let (doc, is_rename) = ident_(id, case); + if is_rename { + str("#[serde(rename=\"") + .append(id.escape_debug().to_string()) + .append("\")]") + .append(RcDoc::line()) + .append(vis) + .append(doc) + } else { + vis.append(doc) + } + } + Label::Id(n) | Label::Unnamed(n) => vis.append("_").append(RcDoc::as_string(n)).append("_"), + } +} + +fn pp_record_field<'a>(field: &'a Field, recs: &RecPoints, vis: &'a str) -> RcDoc<'a> { + pp_label(&field.id, false, vis) + .append(kwd(":")) + .append(pp_ty(&field.ty, recs)) +} + +fn pp_record_fields<'a>(fs: &'a [Field], recs: &RecPoints, vis: &'a str) -> RcDoc<'a> { + if is_tuple(fs) { + let vis = if vis.is_empty() { + RcDoc::nil() + } else { + kwd(vis) + }; + let tuple = RcDoc::concat( + fs.iter() + .map(|f| vis.clone().append(pp_ty(&f.ty, recs)).append(",")), + ); + enclose("(", tuple, ")") + } else { + let fields = concat(fs.iter().map(|f| pp_record_field(f, recs, vis)), ","); + enclose_space("{", fields, "}") + } +} + +fn pp_variant_field<'a>(field: &'a Field, recs: &RecPoints) -> RcDoc<'a> { + match field.ty.as_ref() { + TypeInner::Null => pp_label(&field.id, true, ""), + TypeInner::Record(fs) => { + pp_label(&field.id, true, "").append(pp_record_fields(fs, recs, "")) + } + _ => pp_label(&field.id, true, "").append(enclose("(", pp_ty(&field.ty, recs), ")")), + } +} + +fn pp_variant_fields<'a>(fs: &'a [Field], recs: &RecPoints) -> RcDoc<'a> { + let fields = concat(fs.iter().map(|f| pp_variant_field(f, recs)), ","); + enclose_space("{", fields, "}") +} + +fn pp_defs<'a>( + config: &'a Config, + env: &'a TypeEnv, + def_list: &'a [&'a str], + recs: &'a RecPoints, +) -> RcDoc<'a> { + let derive = if config.type_attributes.is_empty() { + "#[derive(CandidType, Deserialize)]" + } else { + &config.type_attributes + }; + lines(def_list.iter().map(|id| { + let ty = env.find_type(id).unwrap(); + let name = ident(id, Some(Case::Pascal)).append(" "); + let vis = "pub "; + match ty.as_ref() { + TypeInner::Record(fs) => { + let separator = if is_tuple(fs) { + RcDoc::text(";") + } else { + RcDoc::nil() + }; + str(derive) + .append(RcDoc::line()) + .append(vis) + .append("struct ") + .append(name) + .append(pp_record_fields(fs, recs, "pub")) + .append(separator) + .append(RcDoc::hardline()) + } + TypeInner::Variant(fs) => str(derive) + .append(RcDoc::line()) + .append(vis) + .append("enum ") + .append(name) + .append(pp_variant_fields(fs, recs)) + .append(RcDoc::hardline()), + TypeInner::Func(func) => str("candid::define_function!(") + .append(vis) + .append(name) + .append(": ") + .append(pp_ty_func(func)) + .append(");"), + TypeInner::Service(serv) => str("candid::define_service!(") + .append(vis) + .append(name) + .append(": ") + .append(pp_ty_service(serv)) + .append(");"), + _ => { + if recs.contains(id) { + str(derive) + .append(RcDoc::line()) + .append(vis) + .append("struct ") + .append(ident(id, Some(Case::Pascal))) + .append(enclose("(", pp_ty(ty, recs), ")")) + .append(";") + .append(RcDoc::hardline()) + } else { + str(vis) + .append(kwd("type")) + .append(name) + .append("= ") + .append(pp_ty(ty, recs)) + .append(";") + } + } + } + })) +} + +fn pp_args(args: &[Type]) -> RcDoc { + let empty = RecPoints::default(); + let doc = concat(args.iter().map(|t| pp_ty(t, &empty)), ","); + enclose("(", doc, ")") +} +fn pp_ty_func(f: &Function) -> RcDoc { + let args = pp_args(&f.args); + let rets = pp_args(&f.rets); + let modes = candid::pretty::candid::pp_modes(&f.modes); + args.append(" ->") + .append(RcDoc::space()) + .append(rets.append(modes)) + .nest(INDENT_SPACE) +} +fn pp_ty_service(serv: &[(String, Type)]) -> RcDoc { + let doc = concat( + serv.iter().map(|(id, func)| { + let func_doc = match func.as_ref() { + TypeInner::Func(ref f) => enclose("candid::func!(", pp_ty_func(f), ")"), + TypeInner::Var(_) => pp_ty(func, &RecPoints::default()).append("::ty()"), + _ => unreachable!(), + }; + RcDoc::text("\"") + .append(id) + .append(kwd("\" :")) + .append(func_doc) + }), + ";", + ); + enclose_space("{", doc, "}") +} + +fn pp_function<'a>(config: &Config, id: &'a str, func: &'a Function) -> RcDoc<'a> { + let name = ident(id, Some(Case::Snake)); + let empty = BTreeSet::new(); + let arg_prefix = str(match config.target { + Target::CanisterCall => "&self", + Target::Agent => "&self", + Target::CanisterStub => unimplemented!(), + }); + let args = concat( + std::iter::once(arg_prefix).chain( + func.args + .iter() + .enumerate() + .map(|(i, ty)| RcDoc::as_string(format!("arg{i}: ")).append(pp_ty(ty, &empty))), + ), + ",", + ); + let rets = match config.target { + Target::CanisterCall => enclose( + "(", + RcDoc::concat(func.rets.iter().map(|ty| pp_ty(ty, &empty).append(","))), + ")", + ), + Target::Agent => match func.rets.len() { + 0 => str("()"), + 1 => pp_ty(&func.rets[0], &empty), + _ => enclose( + "(", + RcDoc::intersperse( + func.rets.iter().map(|ty| pp_ty(ty, &empty)), + RcDoc::text(", "), + ), + ")", + ), + }, + Target::CanisterStub => unimplemented!(), + }; + let sig = kwd("pub async fn") + .append(name) + .append(enclose("(", args, ")")) + .append(kwd(" ->")) + .append(enclose("Result<", rets, "> ")); + let method = id.escape_debug().to_string(); + let body = match config.target { + Target::CanisterCall => { + let args = RcDoc::concat((0..func.args.len()).map(|i| RcDoc::text(format!("arg{i},")))); + str("ic_cdk::call(self.0, \"") + .append(method) + .append("\", ") + .append(enclose("(", args, ")")) + .append(").await") + } + Target::Agent => { + let is_query = func.is_query(); + let builder_method = if is_query { "query" } else { "update" }; + let call = if is_query { "call" } else { "call_and_wait" }; + let args = RcDoc::intersperse( + (0..func.args.len()).map(|i| RcDoc::text(format!("&arg{i}"))), + RcDoc::text(", "), + ); + let blob = str("Encode!").append(enclose("(", args, ")?;")); + let rets = RcDoc::concat( + func.rets + .iter() + .map(|ty| str(", ").append(pp_ty(ty, &empty))), + ); + str("let args = ").append(blob).append(RcDoc::hardline()) + .append(format!("let bytes = self.1.{builder_method}(&self.0, \"{method}\").with_arg(args).{call}().await?;")) + .append(RcDoc::hardline()) + .append("Ok(Decode!(&bytes").append(rets).append(")?)") + } + Target::CanisterStub => unimplemented!(), + }; + sig.append(enclose_space("{", body, "}")) +} + +fn pp_actor<'a>(config: &'a Config, env: &'a TypeEnv, actor: &'a Type) -> RcDoc<'a> { + // TODO trace to service before we figure out what canister means in Rust + let serv = env.as_service(actor).unwrap(); + let body = RcDoc::intersperse( + serv.iter().map(|(id, func)| { + let func = env.as_func(func).unwrap(); + pp_function(config, id, func) + }), + RcDoc::hardline(), + ); + let struct_name = config.service_name.to_case(Case::Pascal); + let service_def = match config.target { + Target::CanisterCall => format!("pub struct {}(pub Principal);", struct_name), + Target::Agent => format!( + "pub struct {}<'a>(pub Principal, pub &'a ic_agent::Agent);", + struct_name + ), + Target::CanisterStub => unimplemented!(), + }; + let service_impl = match config.target { + Target::CanisterCall => format!("impl {} ", struct_name), + Target::Agent => format!("impl<'a> {}<'a> ", struct_name), + Target::CanisterStub => unimplemented!(), + }; + let res = RcDoc::text(service_def) + .append(RcDoc::hardline()) + .append(service_impl) + .append(enclose_space("{", body, "}")) + .append(RcDoc::hardline()); + if let Some(cid) = config.canister_id { + let slice = cid + .as_slice() + .iter() + .map(|b| b.to_string()) + .collect::>() + .join(", "); + let id = RcDoc::text(format!( + "pub const CANISTER_ID : Principal = Principal::from_slice(&[{}]); // {}", + slice, cid + )); + let instance = match config.target { + Target::CanisterCall => format!( + "pub const {} : {} = {}(CANISTER_ID);", + config.service_name, struct_name, struct_name + ), + Target::Agent => "".to_string(), + Target::CanisterStub => unimplemented!(), + }; + res.append(id).append(RcDoc::hardline()).append(instance) + } else { + res + } +} + +pub fn compile(config: &Config, env: &TypeEnv, actor: &Option) -> String { + let header = format!( + r#"// This is an experimental feature to generate Rust binding from Candid. +// You may want to manually adjust some of the types. +#![allow(dead_code, unused_imports)] +use {}::{{self, CandidType, Deserialize, Principal, Encode, Decode}}; +"#, + config.candid_crate + ); + let header = header + + match &config.target { + Target::CanisterCall => "use ic_cdk::api::call::CallResult as Result;\n", + Target::Agent => "type Result = std::result::Result;\n", + Target::CanisterStub => "", + }; + let (env, actor) = nominalize_all(env, actor); + let def_list: Vec<_> = if let Some(actor) = &actor { + chase_actor(&env, actor).unwrap() + } else { + env.0.iter().map(|pair| pair.0.as_ref()).collect() + }; + let recs = infer_rec(&env, &def_list).unwrap(); + let defs = pp_defs(config, &env, &def_list, &recs); + let doc = match &actor { + None => defs, + Some(actor) => { + let actor = pp_actor(config, &env, actor); + defs.append(actor) + } + }; + let doc = RcDoc::text(header).append(RcDoc::line()).append(doc); + doc.pretty(LINE_WIDTH).to_string() +} + +pub enum TypePath { + Id(String), + Opt, + Vec, + RecordField(String), + VariantField(String), + Func(String), + Init, +} +fn path_to_var(path: &[TypePath]) -> String { + let name: Vec<&str> = path + .iter() + .map(|node| match node { + TypePath::Id(id) => id.as_str(), + TypePath::RecordField(f) | TypePath::VariantField(f) => f.as_str(), + TypePath::Opt => "inner", + TypePath::Vec => "item", + TypePath::Func(id) => id.as_str(), + TypePath::Init => "init", + }) + .collect(); + name.join("_").to_case(Case::Pascal) +} +// Convert structural typing to nominal typing to fit Rust's type system +fn nominalize(env: &mut TypeEnv, path: &mut Vec, t: &Type) -> Type { + match t.as_ref() { + TypeInner::Opt(ty) => { + path.push(TypePath::Opt); + let ty = nominalize(env, path, ty); + path.pop(); + TypeInner::Opt(ty) + } + TypeInner::Vec(ty) => { + path.push(TypePath::Vec); + let ty = nominalize(env, path, ty); + path.pop(); + TypeInner::Vec(ty) + } + TypeInner::Record(fs) => { + if matches!( + path.last(), + None | Some(TypePath::VariantField(_)) | Some(TypePath::Id(_)) + ) || is_tuple(fs) + { + let fs: Vec<_> = fs + .iter() + .map(|Field { id, ty }| { + path.push(TypePath::RecordField(id.to_string())); + let ty = nominalize(env, path, ty); + path.pop(); + Field { id: id.clone(), ty } + }) + .collect(); + TypeInner::Record(fs) + } else { + let new_var = path_to_var(path); + let ty = nominalize( + env, + &mut vec![TypePath::Id(new_var.clone())], + &TypeInner::Record(fs.to_vec()).into(), + ); + env.0.insert(new_var.clone(), ty); + TypeInner::Var(new_var) + } + } + TypeInner::Variant(fs) => match path.last() { + None | Some(TypePath::Id(_)) => { + let fs: Vec<_> = fs + .iter() + .map(|Field { id, ty }| { + path.push(TypePath::VariantField(id.to_string())); + let ty = nominalize(env, path, ty); + path.pop(); + Field { id: id.clone(), ty } + }) + .collect(); + TypeInner::Variant(fs) + } + Some(_) => { + let new_var = path_to_var(path); + let ty = nominalize( + env, + &mut vec![TypePath::Id(new_var.clone())], + &TypeInner::Variant(fs.to_vec()).into(), + ); + env.0.insert(new_var.clone(), ty); + TypeInner::Var(new_var) + } + }, + TypeInner::Func(func) => match path.last() { + None | Some(TypePath::Id(_)) => { + let func = func.clone(); + TypeInner::Func(Function { + modes: func.modes, + args: func + .args + .into_iter() + .enumerate() + .map(|(i, ty)| { + let i = if i == 0 { + "".to_string() + } else { + i.to_string() + }; + path.push(TypePath::Func(format!("arg{i}"))); + let ty = nominalize(env, path, &ty); + path.pop(); + ty + }) + .collect(), + rets: func + .rets + .into_iter() + .enumerate() + .map(|(i, ty)| { + let i = if i == 0 { + "".to_string() + } else { + i.to_string() + }; + path.push(TypePath::Func(format!("ret{i}"))); + let ty = nominalize(env, path, &ty); + path.pop(); + ty + }) + .collect(), + }) + } + Some(_) => { + let new_var = path_to_var(path); + let ty = nominalize( + env, + &mut vec![TypePath::Id(new_var.clone())], + &TypeInner::Func(func.clone()).into(), + ); + env.0.insert(new_var.clone(), ty); + TypeInner::Var(new_var) + } + }, + TypeInner::Service(serv) => match path.last() { + None | Some(TypePath::Id(_)) => TypeInner::Service( + serv.iter() + .map(|(meth, ty)| { + path.push(TypePath::Id(meth.to_string())); + let ty = nominalize(env, path, ty); + path.pop(); + (meth.clone(), ty) + }) + .collect(), + ), + Some(_) => { + let new_var = path_to_var(path); + let ty = nominalize( + env, + &mut vec![TypePath::Id(new_var.clone())], + &TypeInner::Service(serv.clone()).into(), + ); + env.0.insert(new_var.clone(), ty); + TypeInner::Var(new_var) + } + }, + TypeInner::Class(args, ty) => TypeInner::Class( + args.iter() + .map(|ty| { + path.push(TypePath::Init); + let ty = nominalize(env, path, ty); + path.pop(); + ty + }) + .collect(), + nominalize(env, path, ty), + ), + _ => return t.clone(), + } + .into() +} + +fn nominalize_all(env: &TypeEnv, actor: &Option) -> (TypeEnv, Option) { + let mut res = TypeEnv(Default::default()); + for (id, ty) in env.0.iter() { + let ty = nominalize(&mut res, &mut vec![TypePath::Id(id.clone())], ty); + res.0.insert(id.to_string(), ty); + } + let actor = actor + .as_ref() + .map(|ty| nominalize(&mut res, &mut vec![], ty)); + (res, actor) +} diff --git a/src/ic-cdk-bindgen/src/lib.rs b/src/ic-cdk-bindgen/src/lib.rs index 265351ecc..66ce5e357 100644 --- a/src/ic-cdk-bindgen/src/lib.rs +++ b/src/ic-cdk-bindgen/src/lib.rs @@ -1,27 +1,30 @@ -use candid_parser::{bindings::rust, pretty_check_file, Principal}; +use candid::Principal; +use candid_parser::pretty_check_file; use std::env; use std::fs; use std::io::Write; use std::path::PathBuf; +mod code_generator; + #[derive(Clone)] pub struct Config { pub canister_name: String, pub candid_path: PathBuf, pub skip_existing_files: bool, - pub binding: rust::Config, + pub binding: code_generator::Config, } impl Config { pub fn new(canister_name: &str) -> Self { let (candid_path, canister_id) = resolve_candid_path_and_canister_id(canister_name); - let mut binding = rust::Config::new(); + let mut binding = code_generator::Config::new(); binding // User will depend on candid crate directly .set_candid_crate("candid".to_string()) .set_canister_id(canister_id) .set_service_name(canister_name.to_string()) - .set_target(rust::Target::CanisterCall); + .set_target(code_generator::Target::CanisterCall); Config { canister_name: canister_name.to_string(), @@ -115,7 +118,7 @@ impl Builder { for conf in self.configs.iter() { let (env, actor) = pretty_check_file(&conf.candid_path).expect("Cannot parse candid file"); - let content = rust::compile(&conf.binding, &env, &actor); + let content = code_generator::compile(&conf.binding, &env, &actor); let generated_path = out_path.join(format!("{}.rs", conf.canister_name)); if !(conf.skip_existing_files && generated_path.exists()) { fs::write(generated_path, content).expect("Cannot store generated binding"); From 2797f87537dceec0e5dd48d20f206ed15b8783cd Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 12 Apr 2024 14:52:11 -0400 Subject: [PATCH 206/234] replace deprecated URLs (#481) --- src/ic-cdk-macros/src/lib.rs | 2 +- src/ic-cdk/src/api/stable/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index 0aa73b91f..05966ac46 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -267,7 +267,7 @@ pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream { /// /// In this case, the argument will be read from `ic0.msg_arg_data_size/copy` and passed to the /// init function upon successful deserialization. -/// Refer to the [`canister_init` Specification](https://smartcontracts.org/docs/interface-spec/index.html#system-api-init) for more information. +/// Refer to the [`canister_init` Specification](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-init) for more information. #[proc_macro_attribute] pub fn init(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_init, "ic_init", attr, item) diff --git a/src/ic-cdk/src/api/stable/mod.rs b/src/ic-cdk/src/api/stable/mod.rs index 447313df3..46fe2e253 100644 --- a/src/ic-cdk/src/api/stable/mod.rs +++ b/src/ic-cdk/src/api/stable/mod.rs @@ -1,6 +1,6 @@ //! APIs to manage stable memory. //! -//! You can check the [Internet Computer Specification](https://smartcontracts.org/docs/interface-spec/index.html#system-api-stable-memory) +//! You can check the [Internet Computer Specification](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-stable-memory) //! for a in-depth explanation of stable memory. mod canister; mod private; From 70ddb3aa63d68b9f529df0e31c729cec621835e7 Mon Sep 17 00:00:00 2001 From: Ulan Degenbaev Date: Fri, 19 Apr 2024 17:24:46 +0200 Subject: [PATCH 207/234] feat: Add `wasm_memory_limit` to the management canister (#483) * feat: Add `wasm_memory_limit` to the management canister This adds `wasm_memory_limit` to `CanisterSettings` and `DefiniteCanisterSettings`. The corresponding spec change: - https://github.com/dfinity/interface-spec/pull/278 * Add the PR number to the change log * unify doc format * better test coverage --------- Co-authored-by: Linwei Shang --- e2e-tests/canisters/canister_info.rs | 1 + e2e-tests/canisters/management_caller.rs | 46 +++++++++++++----- src/ic-cdk/CHANGELOG.md | 6 +++ .../src/api/management_canister/main/types.rs | 48 +++++++++++++++++-- 4 files changed, 84 insertions(+), 17 deletions(-) diff --git a/e2e-tests/canisters/canister_info.rs b/e2e-tests/canisters/canister_info.rs index b04d38a34..33a108b22 100644 --- a/e2e-tests/canisters/canister_info.rs +++ b/e2e-tests/canisters/canister_info.rs @@ -72,6 +72,7 @@ async fn canister_lifecycle() -> Principal { memory_allocation: None, freezing_threshold: None, reserved_cycles_limit: None, + wasm_memory_limit: None, }, canister_id: canister_id.canister_id, }) diff --git a/e2e-tests/canisters/management_caller.rs b/e2e-tests/canisters/management_caller.rs index ecadb4b6b..07b9cb444 100644 --- a/e2e-tests/canisters/management_caller.rs +++ b/e2e-tests/canisters/management_caller.rs @@ -1,5 +1,8 @@ use ic_cdk::*; +/// Some management canister "main" methods are tested with other e2e canisters: +/// - canister_info.rs +/// - chunk.rs mod main { use super::*; use ic_cdk::api::management_canister::main::*; @@ -8,10 +11,14 @@ mod main { let arg = CreateCanisterArgument { settings: Some(CanisterSettings { controllers: Some(vec![ic_cdk::id()]), - compute_allocation: Some(0u8.into()), + // There is no canister in the subnet, so we can set it to 100. + compute_allocation: Some(100u8.into()), + // Though the upper limit is 256TiB, the actual subnet may have less memory resource (e.g. local replica). + // Here we set it to 10KiB for testing. memory_allocation: Some(10000u16.into()), - freezing_threshold: Some(10000u16.into()), - reserved_cycles_limit: Some(10000u16.into()), + freezing_threshold: Some(u64::MAX.into()), + reserved_cycles_limit: Some(u128::MAX.into()), + wasm_memory_limit: Some((2u64.pow(48) - 1).into()), }), }; let canister_id = create_canister(arg, 100_000_000_000u128 / 13) @@ -20,6 +27,21 @@ mod main { .0 .canister_id; + let canister_id_record = CanisterIdRecord { canister_id }; + let response = canister_status(canister_id_record).await.unwrap().0; + assert_eq!(response.status, CanisterStatusType::Running); + assert_eq!(response.reserved_cycles.0, 0u128.into()); + let definite_canister_setting = response.settings; + assert_eq!(definite_canister_setting.controllers, vec![ic_cdk::id()]); + assert_eq!(definite_canister_setting.compute_allocation, 100u8); + assert_eq!(definite_canister_setting.memory_allocation, 10000u16); + assert_eq!(definite_canister_setting.freezing_threshold, u64::MAX); + assert_eq!(definite_canister_setting.reserved_cycles_limit, u128::MAX); + assert_eq!( + definite_canister_setting.wasm_memory_limit, + 2u64.pow(48) - 1 + ); + let arg = UpdateSettingsArgument { canister_id, settings: CanisterSettings::default(), @@ -35,15 +57,14 @@ mod main { arg: vec![], }; install_code(arg).await.unwrap(); - let arg = CanisterIdRecord { canister_id }; - uninstall_code(arg).await.unwrap(); - start_canister(arg).await.unwrap(); - stop_canister(arg).await.unwrap(); - let response = canister_status(arg).await.unwrap().0; - assert_eq!(response.status, CanisterStatusType::Stopped); - assert_eq!(response.reserved_cycles.0, 0u128.into()); - deposit_cycles(arg, 1_000_000_000_000u128).await.unwrap(); - delete_canister(arg).await.unwrap(); + + uninstall_code(canister_id_record).await.unwrap(); + start_canister(canister_id_record).await.unwrap(); + stop_canister(canister_id_record).await.unwrap(); + deposit_cycles(canister_id_record, 1_000_000_000_000u128) + .await + .unwrap(); + delete_canister(canister_id_record).await.unwrap(); let response = raw_rand().await.unwrap().0; assert_eq!(response.len(), 32); } @@ -61,6 +82,7 @@ mod provisional { memory_allocation: Some(10000u16.into()), freezing_threshold: Some(10000u16.into()), reserved_cycles_limit: Some(10000u16.into()), + wasm_memory_limit: Some(10000u16.into()), }; let arg = ProvisionalCreateCanisterWithCyclesArgument { amount: Some(1_000_000_000u64.into()), diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 0532d2f13..014688e6c 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Added + +- Add `wasm_memory_limit` to the management canister API types: (#483) + * `CanisterSettings` + * `DefiniteCanisterSettings`. + ## [0.13.2] - 2024-04-08 ### Added diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index 5499c5087..fd047f735 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -6,22 +6,58 @@ pub type CanisterId = Principal; /// Canister settings. /// +/// The settings are optional. If they are not explicitly set, the default values will be applied automatically. +/// /// See [`settings`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-create_canister). #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, )] pub struct CanisterSettings { - /// A list of principals. Must be between 0 and 10 in size. + /// A list of at most 10 principals. + /// + /// The principals in this list become the *controllers* of the canister. + /// + /// Default value: A list containing only the caller of the create_canister call. pub controllers: Option>, /// Must be a number between 0 and 100, inclusively. + /// + /// It indicates how much compute power should be guaranteed to this canister, + /// expressed as a percentage of the maximum compute power that a single canister can allocate. + /// + /// If the IC cannot provide the requested allocation, + /// for example because it is oversubscribed, the call will be **rejected**. + /// + /// Default value: 0 pub compute_allocation: Option, - /// Must be a number between 0 and 2^48^ (i.e 256TB), inclusively. + /// Must be a number between 0 and 248 (i.e 256TB), inclusively. + /// + /// It indicates how much memory the canister is allowed to use in total. + /// + /// If the IC cannot provide the requested allocation, + /// for example because it is oversubscribed, the call will be **rejected**. + /// + /// If set to 0, then memory growth of the canister will be best-effort and subject to the available memory on the IC. + /// + /// Default value: 0 pub memory_allocation: Option, - /// Must be a number between 0 and 2^64^-1, inclusively, and indicates a length of time in seconds. + /// Must be a number between 0 and 264-1, inclusively. + /// + /// It indicates a length of time in seconds. + /// + /// Default value: 2592000 (approximately 30 days). pub freezing_threshold: Option, - /// Must be a number between 0 and 2^128^-1, inclusively, and indicates the - /// upper limit on cycles in the `reserved_cycles` balance of the canister. + /// Must be a number between 0 and 2128-1, inclusively. + /// + /// It indicates the upper limit on `reserved_cycles` of the canister. + /// + /// Default value: 5_000_000_000_000 (5 trillion cycles). pub reserved_cycles_limit: Option, + /// Must be a number between 0 and 248-1 (i.e 256TB), inclusively. + /// + /// It indicates the upper limit on the WASM heap memory consumption of the canister. + /// + /// Default value: 3_221_225_472 (3 GiB). + pub wasm_memory_limit: Option, } /// Argument type of [create_canister](super::create_canister). @@ -281,6 +317,8 @@ pub struct DefiniteCanisterSettings { pub freezing_threshold: Nat, /// Reserved cycles limit. pub reserved_cycles_limit: Nat, + /// The Wasm memory limit. + pub wasm_memory_limit: Nat, } /// Query statistics, returned by [canister_status](super::canister_status). From 2abc860ffc2584159a319315f0c2cab9955129eb Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 22 Apr 2024 10:31:44 -0400 Subject: [PATCH 208/234] chore: bump dependencies & improve doc tests (#484) * upgrade syn to v2 * move macros doc to ic-cdk for doc-tests * fix doc links * ci: add doc step which fail on warnings * fix cache key * bump dependency if major outdated --- .github/workflows/ci.yml | 30 +- Cargo.lock | 13 +- Cargo.toml | 2 +- src/ic-cdk-macros/Cargo.toml | 4 +- src/ic-cdk-macros/README.md | 22 +- src/ic-cdk-macros/src/export.rs | 3 +- src/ic-cdk-macros/src/lib.rs | 277 ----------------- src/ic-cdk/README.md | 16 +- src/ic-cdk/src/api/call.rs | 2 +- .../src/api/management_canister/main/types.rs | 2 +- src/ic-cdk/src/lib.rs | 7 +- src/ic-cdk/src/macros.rs | 285 ++++++++++++++++++ 12 files changed, 351 insertions(+), 312 deletions(-) create mode 100644 src/ic-cdk/src/macros.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 362314586..f21fe3748 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,8 +61,9 @@ jobs: run: | bash scripts/download_state_machine_binary.sh - name: Run tests - run: | - cargo test --workspace --exclude candid-extractor --all-targets + run: | # https://github.com/rust-lang/cargo/issues/6669 we have to run ALL tests with two commands + cargo test --all-targets + cargo test --doc fmt: name: cargo fmt @@ -110,10 +111,33 @@ jobs: run: | cargo clippy --tests --benches -- -D warnings + doc: + name: cargo doc + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Cache + uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-doc-${{ hashFiles('Cargo.lock', 'rust-toolchain.toml') }} + restore-keys: | + ${{ runner.os }}-doc- + ${{ runner.os }}- + - name: Run doc + run: | + RUSTDOCFLAGS="-D warnings" cargo doc + aggregate: name: ci:required if: ${{ always() }} - needs: [build, test, fmt, clippy] + needs: [build, test, fmt, clippy, doc] runs-on: ubuntu-latest steps: - name: check build result diff --git a/Cargo.lock b/Cargo.lock index 3a71713f3..1501aed6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,7 +215,7 @@ version = "0.1.2" dependencies = [ "anyhow", "quote", - "syn 1.0.109", + "syn 2.0.39", "wasmtime", ] @@ -924,7 +924,7 @@ dependencies = [ "quote", "serde", "serde_tokenstream", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] @@ -983,7 +983,7 @@ name = "ic0" version = "0.21.1" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] @@ -1686,13 +1686,14 @@ dependencies = [ [[package]] name = "serde_tokenstream" -version = "0.1.7" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "797ba1d80299b264f3aac68ab5d12e5825a561749db4df7cd7c8083900c5d4e9" +checksum = "8a00ffd23fd882d096f09fcaae2a9de8329a328628e86027e049ee051dc1621f" dependencies = [ "proc-macro2", + "quote", "serde", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8c240e513..ec9067831 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,4 +33,4 @@ serde = "1" serde_bytes = "0.11" sha2 = "0.10" slotmap = "1" -syn = "1" +syn = "2" diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 5b233489b..cd6926080 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -27,5 +27,5 @@ candid.workspace = true proc-macro2 = "1.0" quote.workspace = true serde.workspace = true -serde_tokenstream = "0.1.0" -syn = { workspace = true, features = ["fold", "full"] } +serde_tokenstream = "0.2.0" +syn = { workspace = true, features = ["fold", "full", "extra-traits"] } diff --git a/src/ic-cdk-macros/README.md b/src/ic-cdk-macros/README.md index c7dd633dc..26ef0af36 100644 --- a/src/ic-cdk-macros/README.md +++ b/src/ic-cdk-macros/README.md @@ -6,7 +6,11 @@ # ic-cdk-macros -This crate provides a set of macros to facilitate canister development. +This crate contains a collection of procedural macros that are utilized within the `ic-cdk` crate. + +The macros are re-exported in `ic-cdk`, and you can find their documentation [there](https://docs.rs/ic-cdk/latest/ic_cdk). + +--- The macros fall into two categories: @@ -17,16 +21,16 @@ The macros fall into two categories: These macros are directly related to the [Internet Computer Specification](https://internetcomputer.org/docs/current/references/ic-interface-spec#entry-points). -* [`init`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.init.html) -* [`pre_upgrade`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.pre_upgrade.html) -* [`post_upgrade`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.post_upgrade.html) -* [`inspect_message`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.inspect_message.html) -* [`heartbeat`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.heartbeat.html) -* [`update`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.update.html) -* [`query`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.query.html) +* [`init`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.init.html) +* [`pre_upgrade`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.pre_upgrade.html) +* [`post_upgrade`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.post_upgrade.html) +* [`inspect_message`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.inspect_message.html) +* [`heartbeat`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.heartbeat.html) +* [`update`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.update.html) +* [`query`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.query.html) ## Export Candid definitions -* [`export_candid`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/macro.export_candid.html) +* [`export_candid`](https://docs.rs/ic-cdk/latest/ic_cdk/macro.export_candid.html) Check [Generating Candid files for Rust canisters](https://internetcomputer.org/docs/current/developer-docs/backend/candid/generating-candid/) for more details. diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index a90e1991c..2141586c7 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -103,7 +103,8 @@ fn dfn_macro( attr: TokenStream, item: TokenStream, ) -> Result { - let attrs = from_tokenstream::(&attr)?; + let attrs = from_tokenstream::(&attr) + .map_err(|e| Error::new(attr.span(), format!("Failed to deserialize {attr}. \n{e}")))?; let fun: ItemFn = syn::parse2::(item.clone()).map_err(|e| { Error::new( diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index 05966ac46..d9e75e690 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -2,7 +2,6 @@ #![warn( elided_lifetimes_in_paths, missing_debug_implementations, - missing_docs, unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks, clippy::missing_safety_doc @@ -43,10 +42,6 @@ where result.map_or_else(|e| e.to_compile_error().into(), Into::into) } -/// Create a `get_candid_pointer` method so that `dfx` can execute it to extract candid definition. -/// -/// Call this macro only if you want the Candid export behavior. -/// Only call it once at the end of canister code outside query/update definition. #[proc_macro] pub fn export_candid(input: TokenStream) -> TokenStream { let input: proc_macro2::TokenStream = input.into(); @@ -62,308 +57,36 @@ pub fn export_candid(input: TokenStream) -> TokenStream { .into() } -/// Register a query call entry point. -/// -/// This attribute macro will export a function with name `canister_query ` -/// in the canister module. -/// -/// # Example -/// -/// ```rust -/// # use ic_cdk::query; -/// #[query] -/// fn query_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` -/// -/// You can also specify the name of the exported function. -/// -/// ```rust -/// # use ic_cdk::query; -/// #[query(name = "some_name")] -/// fn query_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` -/// -/// If you want to hide this method in the Candid generated by [export_candid!], -/// you will need to set `hidden` to `true`. The entry point still exists in the canister. -/// -/// ```rust -/// # use ic_cdk::query; -/// #[query(hidden = true)] -/// fn query_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` -/// -/// You can specify a guard function to be executed before the query function. -/// When the guard function returns an error, the query function will not proceed. -/// -/// ```rust -/// # use ic_cdk::query; -/// fn guard_function() -> Result<(), String> { -/// // ... -/// # unimplemented!() -/// } -/// #[query(guard = "guard_function")] -/// fn query_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` -/// -/// To be able to make inter-canister calls from a query call, it must be a *composite* query (which cannot be executed in replicated mode). -/// -/// ```rust -/// # use ic_cdk::query; -/// # fn wallet_canister_principal() -> candid::Principal { unimplemented!() } -/// #[query(composite = true)] -/// async fn composite_query_function() { -/// let (wallet_name,): (Option,) = ic_cdk::call(wallet_canister_principal(), "name", ()).await.unwrap(); -/// } -/// ``` -/// -/// If you would rather call the [`call::reply`] function than return a value, -/// you will need to set `manual_reply` to `true` so that the canister does not -/// trap. -/// -/// ```rust -/// # fn calculate_result() {} -/// # type MyResult = (); -/// # use ic_cdk::query; -/// use ic_cdk::api::call::{self, ManualReply}; -/// #[query(manual_reply = true)] -/// fn query_function() -> ManualReply { -/// let result = calculate_result(); -/// ManualReply::one(result) -/// } -/// ``` -/// -/// [`call::reply`]: https://docs.rs/ic-cdk/latest/ic_cdk/api/call/fn.reply.html #[proc_macro_attribute] pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_query, "ic_query", attr, item) } -/// Register an update call entry point. -/// -/// This attribute macro will export a function with name `canister_update ` -/// in the canister module. -/// -/// # Example -/// -/// ```rust -/// # use ic_cdk::update; -/// #[update] -/// fn update_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` -/// -/// You can also specify the name of the exported function. -/// -/// ```rust -/// # use ic_cdk::update; -/// #[update(name = "some_name")] -/// fn update_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` -/// -/// If you want to hide this method in the Candid generated by [export_candid!], -/// you will need to set `hidden` to `true`. The entry point still exists in the canister. -/// -/// ```rust -/// # use ic_cdk::update; -/// #[update(hidden = true)] -/// fn update_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` -/// -/// You can specify a guard function to be executed before the update function. -/// When the guard function returns an error, the update function will not proceed. -/// -/// ```rust -/// # use ic_cdk::update; -/// fn guard_function() -> Result<(), String> { -/// // ... -/// # unimplemented!() -/// } -/// #[update(guard = "guard_function")] -/// fn update_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` -/// -/// If you would rather call the [`call::reply`] function than return a value, -/// you will need to set `manual_reply` to `true` so that the canister does not -/// trap. -/// -/// ```rust -/// # fn calculate_result() {} -/// # type MyResult = (); -/// # use ic_cdk::update; -/// use ic_cdk::api::call::{self, ManualReply}; -/// #[update(manual_reply = true)] -/// fn update_function() -> ManualReply { -/// let result = calculate_result(); -/// ManualReply::one(result) -/// } -/// ``` -/// -/// [`call::reply`]: https://docs.rs/ic-cdk/latest/ic_cdk/api/call/fn.reply.html #[proc_macro_attribute] pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_update, "ic_update", attr, item) } -/// Register the `canister_init` entry point of a canister. -/// -/// This attribute macro will export the function `canister_init` -/// in the canister module. -/// -/// The function under this attribute must have no return value. -/// -/// Each canister can only have one `canister_init` entry point. -/// -/// # Example -/// -/// ```rust -/// # use ic_cdk::init; -/// #[init] -/// fn init_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` -/// -/// The init function may accept an argument, if that argument is a `CandidType`: -/// -/// ```rust -/// # use ic_cdk::init; -/// # use candid::*; -/// -/// #[derive(Clone, Debug, CandidType, Deserialize)] -/// struct InitArg { -/// foo: u8, -/// } -/// -/// #[init] -/// fn init_function(arg: InitArg) { -/// // ... -/// # unimplemented!() -/// } -/// ``` -/// -/// In this case, the argument will be read from `ic0.msg_arg_data_size/copy` and passed to the -/// init function upon successful deserialization. -/// Refer to the [`canister_init` Specification](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-init) for more information. #[proc_macro_attribute] pub fn init(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_init, "ic_init", attr, item) } -/// Register the `canister_pre_upgrade` entry point of a canister. -/// -/// This attribute macro will export the function `canister_pre_upgrade` -/// in the canister module. -/// -/// The function under this attribute must have no return value. -/// -/// Each canister can only have one `canister_pre_upgrade` entry point. -/// -/// # Example -/// -/// ```rust -/// # use ic_cdk::pre_upgrade; -/// #[pre_upgrade] -/// fn pre_upgrade_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` #[proc_macro_attribute] pub fn pre_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_pre_upgrade, "ic_pre_upgrade", attr, item) } -/// Register the `canister_post_upgrade` entry point of a canister. -/// -/// This attribute macro will export the function `canister_post_upgrade` -/// in the canister module. -/// -/// The function under this attribute must have no return value. -/// -/// Each canister can only have one `canister_post_upgrade` entry point. -/// -/// # Example -/// -/// ```rust -/// # use ic_cdk::post_upgrade; -/// #[post_upgrade] -/// fn post_upgrade_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` #[proc_macro_attribute] pub fn post_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_post_upgrade, "ic_post_upgrade", attr, item) } -/// Register the `canister_heartbeat` entry point of a canister. -/// -/// This attribute macro will export the function `canister_heartbeat` -/// in the canister module. -/// -/// The function under this attribute must have no return value. -/// -/// Each canister can only have one `canister_heartbeat` entry point. -/// -/// # Example -/// -/// ```rust -/// # use ic_cdk::heartbeat; -/// #[heartbeat] -/// fn heartbeat_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` #[proc_macro_attribute] pub fn heartbeat(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_heartbeat, "ic_heartbeat", attr, item) } -/// Register the `canister_inspect_message` entry point of a canister. -/// -/// This attribute macro will export the function `canister_inspect_message` -/// in the canister module. -/// -/// The function under this attribute must have no return value. -/// -/// Each canister can only have one `canister_inspect_message` entry point. -/// -/// # Example -/// -/// ```rust -/// # use ic_cdk::inspect_message; -/// #[inspect_message] -/// fn inspect_message_function() { -/// // ... -/// # unimplemented!() -/// } -/// ``` #[proc_macro_attribute] pub fn inspect_message(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_inspect_message, "ic_inspect_message", attr, item) diff --git a/src/ic-cdk/README.md b/src/ic-cdk/README.md index d3ec7ea20..4608337d6 100644 --- a/src/ic-cdk/README.md +++ b/src/ic-cdk/README.md @@ -54,17 +54,17 @@ The macros fall into two categories: These macros are directly related to the [Internet Computer Specification](https://internetcomputer.org/docs/current/references/ic-interface-spec#entry-points). -* [`init`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.init.html) -* [`pre_upgrade`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.pre_upgrade.html) -* [`post_upgrade`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.post_upgrade.html) -* [`inspect_message`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.inspect_message.html) -* [`heartbeat`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.heartbeat.html) -* [`update`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.update.html) -* [`query`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/attr.query.html) +* [`init`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.init.html) +* [`pre_upgrade`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.pre_upgrade.html) +* [`post_upgrade`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.post_upgrade.html) +* [`inspect_message`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.inspect_message.html) +* [`heartbeat`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.heartbeat.html) +* [`update`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.update.html) +* [`query`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.query.html) ### Export Candid definitions -* [`export_candid`](https://docs.rs/ic-cdk-macros/latest/ic_cdk_macros/macro.export_candid.html) +* [`export_candid`](https://docs.rs/ic-cdk/latest/ic_cdk/macro.export_candid.html) Check [Generating Candid files for Rust canisters](https://internetcomputer.org/docs/current/developer-docs/backend/candid/generating-candid/) for more details. diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index 1fe5e8f90..ca6fbac36 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -870,7 +870,7 @@ where /// When this happens the CDK will cancel the task, causing destructors to be run. If you need any functions to be run /// no matter what happens, they should happen in a destructor; the [`scopeguard`](https://docs.rs/scopeguard) crate /// provides a convenient wrapper for this. In a destructor, `is_recovering_from_trap` serves the same purpose as -/// [`is_panicking`](std::thread::is_panicking) - it tells you whether the destructor is executing *because* of a trap, +/// [std::thread::panicking] - it tells you whether the destructor is executing *because* of a trap, /// as opposed to just because the scope was exited, so you could e.g. implement mutex poisoning. pub fn is_recovering_from_trap() -> bool { crate::futures::CLEANUP.load(Ordering::Relaxed) diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index fd047f735..ac185fa01 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -102,7 +102,7 @@ pub(crate) struct UpdateSettingsArgumentExtended { pub sender_canister_version: Option, } -/// Argument type of [update_chunk](super::update_chunk). +/// Argument type of [update_chunk](super::upload_chunk). #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, )] diff --git a/src/ic-cdk/src/lib.rs b/src/ic-cdk/src/lib.rs index 20492aeff..4fbd1ac22 100644 --- a/src/ic-cdk/src/lib.rs +++ b/src/ic-cdk/src/lib.rs @@ -12,11 +12,9 @@ #[cfg(target_feature = "atomics")] compile_error!("This version of the CDK does not support multithreading."); -#[doc(inline)] -pub use ic_cdk_macros::*; - pub mod api; mod futures; +mod macros; mod printer; pub mod storage; @@ -29,6 +27,9 @@ pub use api::call::notify; #[doc(inline)] pub use api::{caller, id, print, trap}; +#[doc(inline)] +pub use macros::*; + static DONE: AtomicBool = AtomicBool::new(false); /// Setup the stdlib hooks. diff --git a/src/ic-cdk/src/macros.rs b/src/ic-cdk/src/macros.rs new file mode 100644 index 000000000..733be8117 --- /dev/null +++ b/src/ic-cdk/src/macros.rs @@ -0,0 +1,285 @@ +/// Create a `get_candid_pointer` method so that `dfx` can execute it to extract candid definition. +/// +/// Call this macro only if you want the Candid export behavior. +/// Only call it once at the end of canister code outside query/update definition. +pub use ic_cdk_macros::export_candid; + +/// Register a query call entry point. +/// +/// This attribute macro will export a function with name `canister_query ` +/// in the canister module. +/// +/// # Example +/// +/// ```rust +/// # use ic_cdk::query; +/// #[query] +/// fn query_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// +/// You can also specify the name of the exported function. +/// +/// ```rust +/// # use ic_cdk::query; +/// #[query(name = "some_name")] +/// fn query_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// +/// If you want to hide this method in the Candid generated by [export_candid!], +/// you will need to set `hidden` to `true`. The entry point still exists in the canister. +/// +/// ```rust +/// # use ic_cdk::query; +/// #[query(hidden = true)] +/// fn query_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// +/// You can specify a guard function to be executed before the query function. +/// When the guard function returns an error, the query function will not proceed. +/// +/// ```rust +/// # use ic_cdk::query; +/// fn guard_function() -> Result<(), String> { +/// // ... +/// # unimplemented!() +/// } +/// #[query(guard = "guard_function")] +/// fn query_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// +/// To be able to make inter-canister calls from a query call, it must be a *composite* query (which cannot be executed in replicated mode). +/// +/// ```rust +/// # use ic_cdk::query; +/// # fn wallet_canister_principal() -> candid::Principal { unimplemented!() } +/// #[query(composite = true)] +/// async fn composite_query_function() { +/// let (wallet_name,): (Option,) = ic_cdk::call(wallet_canister_principal(), "name", ()).await.unwrap(); +/// } +/// ``` +/// +/// If you would rather call the [`reply()`](crate::api::call::reply) function than return a value, +/// you will need to set `manual_reply` to `true` so that the canister does not trap. +/// +/// ```rust +/// # fn calculate_result() {} +/// # type MyResult = (); +/// # use ic_cdk::query; +/// use ic_cdk::api::call::{self, ManualReply}; +/// #[query(manual_reply = true)] +/// fn query_function() -> ManualReply { +/// let result = calculate_result(); +/// ManualReply::one(result) +/// } +/// ``` +pub use ic_cdk_macros::query; + +/// Register an update call entry point. +/// +/// This attribute macro will export a function with name `canister_update ` +/// in the canister module. +/// +/// # Example +/// +/// ```rust +/// # use ic_cdk::update; +/// #[update] +/// fn update_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// +/// You can also specify the name of the exported function. +/// +/// ```rust +/// # use ic_cdk::update; +/// #[update(name = "some_name")] +/// fn update_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// +/// If you want to hide this method in the Candid generated by [export_candid!], +/// you will need to set `hidden` to `true`. The entry point still exists in the canister. +/// +/// ```rust +/// # use ic_cdk::update; +/// #[update(hidden = true)] +/// fn update_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// +/// You can specify a guard function to be executed before the update function. +/// When the guard function returns an error, the update function will not proceed. +/// +/// ```rust +/// # use ic_cdk::update; +/// fn guard_function() -> Result<(), String> { +/// // ... +/// # unimplemented!() +/// } +/// #[update(guard = "guard_function")] +/// fn update_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// +/// If you would rather call the [`reply()`](crate::api::call::reply) function than return a value, +/// you will need to set `manual_reply` to `true` so that the canister does not trap. +/// +/// ```rust +/// # fn calculate_result() {} +/// # type MyResult = (); +/// # use ic_cdk::update; +/// use ic_cdk::api::call::{self, ManualReply}; +/// #[update(manual_reply = true)] +/// fn update_function() -> ManualReply { +/// let result = calculate_result(); +/// ManualReply::one(result) +/// } +/// ``` +pub use ic_cdk_macros::update; + +/// Register the `canister_init` entry point of a canister. +/// +/// This attribute macro will export the function `canister_init` +/// in the canister module. +/// +/// The function under this attribute must have no return value. +/// +/// Each canister can only have one `canister_init` entry point. +/// +/// # Example +/// +/// ```rust +/// # use ic_cdk::init; +/// #[init] +/// fn init_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// +/// The init function may accept an argument, if that argument is a `CandidType`: +/// +/// ```rust +/// # use ic_cdk::init; +/// # use candid::*; +/// +/// #[derive(Clone, Debug, CandidType, Deserialize)] +/// struct InitArg { +/// foo: u8, +/// } +/// +/// #[init] +/// fn init_function(arg: InitArg) { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// +/// In this case, the argument will be read from `ic0.msg_arg_data_size/copy` and passed to the +/// init function upon successful deserialization. +/// Refer to the [`canister_init` Specification](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-init) for more information. +pub use ic_cdk_macros::init; + +/// Register the `canister_pre_upgrade` entry point of a canister. +/// +/// This attribute macro will export the function `canister_pre_upgrade` +/// in the canister module. +/// +/// The function under this attribute must have no return value. +/// +/// Each canister can only have one `canister_pre_upgrade` entry point. +/// +/// # Example +/// +/// ```rust +/// # use ic_cdk::pre_upgrade; +/// #[pre_upgrade] +/// fn pre_upgrade_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +pub use ic_cdk_macros::pre_upgrade; + +/// Register the `canister_post_upgrade` entry point of a canister. +/// +/// This attribute macro will export the function `canister_post_upgrade` +/// in the canister module. +/// +/// The function under this attribute must have no return value. +/// +/// Each canister can only have one `canister_post_upgrade` entry point. +/// +/// # Example +/// +/// ```rust +/// # use ic_cdk::post_upgrade; +/// #[post_upgrade] +/// fn post_upgrade_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +pub use ic_cdk_macros::post_upgrade; + +/// Register the `canister_heartbeat` entry point of a canister. +/// +/// This attribute macro will export the function `canister_heartbeat` +/// in the canister module. +/// +/// The function under this attribute must have no return value. +/// +/// Each canister can only have one `canister_heartbeat` entry point. +/// +/// # Example +/// +/// ```rust +/// # use ic_cdk::heartbeat; +/// #[heartbeat] +/// fn heartbeat_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +pub use ic_cdk_macros::heartbeat; + +/// Register the `canister_inspect_message` entry point of a canister. +/// +/// This attribute macro will export the function `canister_inspect_message` +/// in the canister module. +/// +/// The function under this attribute must have no return value. +/// +/// Each canister can only have one `canister_inspect_message` entry point. +/// +/// # Example +/// +/// ```rust +/// # use ic_cdk::inspect_message; +/// #[inspect_message] +/// fn inspect_message_function() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +pub use ic_cdk_macros::inspect_message; From 8620c0e92802451ca5616d5e822a7712feb0ff21 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 22 Apr 2024 12:11:13 -0400 Subject: [PATCH 209/234] feat: candid-extractor supports --version (#485) * bump rust to v1.75.0 (same as sdk repo) * bump wasmtime to 19 and cargo update * add clap dependency * submodule extract * clap for --version and --help/-h * add changelog and bump to 0.1.3 * clippy from recent rust has a false positive * e2e test --- Cargo.lock | 1150 ++++++++++--------- Cargo.toml | 2 +- examples/print/tests/basic.bats | 11 + library/ic-certified-map/src/rbtree/test.rs | 1 + rust-toolchain.toml | 2 +- src/candid-extractor/CHANGELOG.md | 30 + src/candid-extractor/Cargo.toml | 5 +- src/candid-extractor/src/extract.rs | 38 + src/candid-extractor/src/main.rs | 60 +- 9 files changed, 729 insertions(+), 570 deletions(-) create mode 100644 src/candid-extractor/CHANGELOG.md create mode 100644 src/candid-extractor/src/extract.rs diff --git a/Cargo.lock b/Cargo.lock index 1501aed6e..f9a1be963 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "once_cell", @@ -25,18 +25,66 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "arbitrary" @@ -61,35 +109,26 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "base64" -version = "0.21.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" - -[[package]] -name = "basic-toml" -version = "0.1.7" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f2139706359229bfa8f19142ac1155b4b80beafb7a60471ac5dd109d4a19778" -dependencies = [ - "serde", -] +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "beef" @@ -152,9 +191,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" @@ -167,9 +206,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -188,9 +227,9 @@ dependencies = [ [[package]] name = "candid" -version = "0.10.4" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd70c7bed52cb20e38dd933c19c0c9abf0302b60db3fa3186e27ec53edf6ad" +checksum = "818394610ed32d9e4c81025f97c8580698b69542527efde18514cf9ad1f8f5f0" dependencies = [ "anyhow", "binread", @@ -211,11 +250,12 @@ dependencies = [ [[package]] name = "candid-extractor" -version = "0.1.2" +version = "0.1.3" dependencies = [ "anyhow", + "clap", "quote", - "syn 2.0.39", + "syn 2.0.60", "wasmtime", ] @@ -228,7 +268,7 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] @@ -252,9 +292,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34637b3140142bdf929fb439e8aa4ebad7651ebf7b1080b3930aa16ac1459ff" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ "serde", ] @@ -274,12 +314,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" dependencies = [ "jobserver", "libc", + "once_cell", ] [[package]] @@ -290,9 +331,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ciborium" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -301,20 +342,60 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", - "half", + "half 2.4.1", +] + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", ] +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.60", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -325,6 +406,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "convert_case" version = "0.6.0" @@ -336,36 +423,36 @@ dependencies = [ [[package]] name = "cpp_demangle" -version = "0.3.5" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" dependencies = [ "cfg-if", ] [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "cranelift-bforest" -version = "0.99.2" +version = "0.106.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a91a1ccf6fb772808742db2f51e2179f25b1ec559cbe39ea080c72ff61caf8f" +checksum = "3b57d4f3ffc28bbd6ef1ca7b50b20126717232f97487efe027d135d9d87eb29c" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.99.2" +version = "0.106.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "169db1a457791bff4fd1fc585bb5cc515609647e0420a7d5c98d7700c59c2d00" +checksum = "d1f7d0ac7fd53f2c29db3ff9a063f6ff5a8be2abaa8f6942aceb6e1521e70df7" dependencies = [ "bumpalo", "cranelift-bforest", @@ -375,7 +462,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.13.2", + "hashbrown 0.14.3", "log", "regalloc2", "smallvec", @@ -384,42 +471,43 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.99.2" +version = "0.106.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3486b93751ef19e6d6eef66d2c0e83ed3d2ba01da1919ed2747f2f7bd8ba3419" +checksum = "b40bf21460a600178956cb7fd900a7408c6587fbb988a8063f7215361801a1da" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.99.2" +version = "0.106.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86a1205ab18e7cd25dc4eca5246e56b506ced3feb8d95a8d776195e48d2cd4ef" +checksum = "d792ecc1243b7ebec4a7f77d9ed428ef27456eeb1f8c780587a6f5c38841be19" [[package]] name = "cranelift-control" -version = "0.99.2" +version = "0.106.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b108cae0f724ddfdec1871a0dc193a607e0c2d960f083cfefaae8ccf655eff2" +checksum = "cea2808043df964b73ad7582e09afbbe06a31f3fb9db834d53e74b4e16facaeb" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.99.2" +version = "0.106.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "720444006240622798665bfc6aa8178e2eed556da342fda62f659c5267c3c659" +checksum = "f1930946836da6f514da87625cd1a0331f3908e0de454628c24a0b97b130c4d4" dependencies = [ "serde", + "serde_derive", ] [[package]] name = "cranelift-frontend" -version = "0.99.2" +version = "0.106.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a94c4c5508b7407e125af9d5320694b7423322e59a4ac0d07919ae254347ca" +checksum = "5482a5fcdf98f2f31b21093643bdcfe9030866b8be6481117022e7f52baa0f2b" dependencies = [ "cranelift-codegen", "log", @@ -429,15 +517,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.99.2" +version = "0.106.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1f888d0845dcd6be4d625b91d9d8308f3d95bed5c5d4072ce38e1917faa505" +checksum = "6f6e1869b6053383bdb356900e42e33555b4c9ebee05699469b7c53cdafc82ea" [[package]] name = "cranelift-native" -version = "0.99.2" +version = "0.106.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ad5966da08f1e96a3ae63be49966a85c9b249fa465f8cf1b66469a82b1004a0" +checksum = "a91446e8045f1c4bc164b7bba68e2419c623904580d4b730877a663c6da38964" dependencies = [ "cranelift-codegen", "libc", @@ -446,14 +534,14 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.99.2" +version = "0.106.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8635c88b424f1d232436f683a301143b36953cd98fc6f86f7bac862dfeb6f5" +checksum = "f8b17979b862d3b0d52de6ae3294ffe4d86c36027b56ad0443a7c8c8f921d14f" dependencies = [ "cranelift-codegen", "cranelift-entity", "cranelift-frontend", - "itertools", + "itertools 0.12.1", "log", "smallvec", "wasmparser", @@ -462,45 +550,37 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -533,12 +613,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - [[package]] name = "digest" version = "0.10.7" @@ -582,9 +656,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "ena" @@ -596,16 +670,12 @@ dependencies = [ ] [[package]] -name = "env_logger" -version = "0.10.1" +name = "encoding_rs" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", + "cfg-if", ] [[package]] @@ -616,9 +686,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", "windows-sys", @@ -626,9 +696,9 @@ dependencies = [ [[package]] name = "escargot" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "768064bd3a0e2bedcba91dc87ace90beea91acc41b6a01a3ca8e9aa8827461bf" +checksum = "4f474c6844cbd04e783d0f25757583db4f491770ca618bedf2fb01815fc79939" dependencies = [ "log", "once_cell", @@ -638,19 +708,9 @@ dependencies = [ [[package]] name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "file-per-thread-logger" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3cc21c33af89af0930c8cae4ade5e6fdc17b5d2c97b3d2e2edb67a1cf683f3" -dependencies = [ - "env_logger", - "log", -] +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fixedbitset" @@ -664,20 +724,11 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - [[package]] name = "futures" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -690,9 +741,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -700,15 +751,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -717,38 +768,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -777,7 +828,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "debugid", "fxhash", "serde", @@ -796,9 +847,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -807,12 +858,12 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ "fallible-iterator", - "indexmap 1.9.3", + "indexmap", "stable_deref_trait", ] @@ -824,15 +875,19 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "half" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] -name = "hashbrown" -version = "0.12.3" +name = "half" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] [[package]] name = "hashbrown" @@ -845,9 +900,12 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", +] [[package]] name = "heck" @@ -856,10 +914,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] -name = "hermit-abi" -version = "0.3.3" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hex" @@ -867,12 +925,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "ic-cdk" version = "0.13.2" @@ -924,7 +976,7 @@ dependencies = [ "quote", "serde", "serde_tokenstream", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] @@ -983,21 +1035,19 @@ name = "ic0" version = "0.21.1" dependencies = [ "quote", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] name = "ic_principal" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899a4e8ddada85b91a2fe32b4dc6c0d475ef7bfef3f51cf2aecb26ee4ac4724f" +checksum = "1762deb6f7c8d8c2bdee4b6c5a47b60195b74e9b5280faa5ba29692f8e17429c" dependencies = [ "arbitrary", "crc32fast", "data-encoding", - "hex", "serde", - "serde_bytes", "sha2", "thiserror", ] @@ -1008,68 +1058,46 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "indexmap" -version = "1.9.3" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "serde", ] [[package]] -name = "is-terminal" -version = "0.4.9" +name = "itertools" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ - "hermit-abi", - "rustix", - "windows-sys", + "either", ] [[package]] name = "itertools" -version = "0.10.5" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "ittapi" -version = "0.3.5" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a5c0b993601cad796222ea076565c5d9f337d35592f8622c753724f06d7271" +checksum = "6b996fe614c41395cdaedf3cf408a9534851090959d90d54a535f675550b64b1" dependencies = [ "anyhow", "ittapi-sys", @@ -1078,52 +1106,51 @@ dependencies = [ [[package]] name = "ittapi-sys" -version = "0.3.5" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7b5e473765060536a660eed127f758cf1a810c73e49063264959c60d1727d9" +checksum = "52f5385394064fa2c886205dba02598013ce83d3e92d33dbdc0c52fe0e7bf4fc" dependencies = [ "cc", ] [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] [[package]] name = "lalrpop" -version = "0.20.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" +checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" dependencies = [ "ascii-canvas", "bit-set", - "diff", "ena", - "is-terminal", - "itertools", + "itertools 0.11.0", "lalrpop-util", "petgraph", "pico-args", "regex", - "regex-syntax 0.7.5", + "regex-syntax 0.8.3", "string_cache", "term", "tiny-keccak", "unicode-xid", + "walkdir", ] [[package]] name = "lalrpop-util" -version = "0.20.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex", + "regex-automata", ] [[package]] @@ -1140,26 +1167,25 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "libc", - "redox_syscall", ] [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" @@ -1173,9 +1199,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "logos" @@ -1197,7 +1223,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.6.29", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] @@ -1220,9 +1246,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memfd" @@ -1235,18 +1261,18 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] [[package]] name = "new_debug_unreachable" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "num-bigint" @@ -1262,40 +1288,39 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] [[package]] name = "object" -version = "0.31.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "crc32fast", - "hashbrown 0.13.2", - "indexmap 1.9.3", + "hashbrown 0.14.3", + "indexmap", "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking_lot" @@ -1317,7 +1342,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1326,12 +1351,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - [[package]] name = "petgraph" version = "0.6.4" @@ -1339,7 +1358,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap", ] [[package]] @@ -1359,9 +1378,9 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1371,15 +1390,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "precomputed-hash" @@ -1400,9 +1413,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] @@ -1416,61 +1429,20 @@ dependencies = [ "cc", ] -[[package]] -name = "pulldown-cmark" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" -dependencies = [ - "bitflags 1.3.2", - "memchr", - "unicase", -] - [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - [[package]] name = "rayon" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -1478,9 +1450,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -1497,9 +1469,9 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", @@ -1521,25 +1493,25 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -1550,15 +1522,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - -[[package]] -name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rstest" @@ -1596,11 +1562,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.25" +version = "0.38.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +checksum = "e3cc72858054fcff6d7dea32df2aeaee6a7c24227366d7ea429aada2f26b16ad" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", @@ -1609,15 +1575,24 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] [[package]] name = "scopeguard" @@ -1627,27 +1602,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.193" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.12" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" dependencies = [ "serde", ] @@ -1658,32 +1633,41 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ - "half", + "half 1.8.3", "serde", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "serde_tokenstream" version = "0.2.0" @@ -1693,7 +1677,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] @@ -1730,18 +1714,18 @@ checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" [[package]] name = "slotmap" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" dependencies = [ "version_check", ] [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "sptr" @@ -1781,6 +1765,12 @@ dependencies = [ "precomputed-hash", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "1.0.109" @@ -1794,9 +1784,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -1805,9 +1795,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.12" +version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "term" @@ -1822,31 +1812,31 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] @@ -1859,42 +1849,52 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.6.0" +name = "toml" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ - "tinyvec_macros", + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", ] [[package]] -name = "tinyvec_macros" -version = "0.1.1" +name = "toml_datetime" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] [[package]] -name = "toml" -version = "0.5.11" +name = "toml_edit" +version = "0.22.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" dependencies = [ + "indexmap", "serde", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] name = "trybuild" -version = "1.0.85" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196a58260a906cedb9bf6d8034b6379d0c11f552416960452f267402ceeddff1" +checksum = "8ad7eb6319ebadebca3dacf1f85a93bc54b73dd81b9036795f73de7ddfe27d5a" dependencies = [ - "basic-toml", "glob", "once_cell", "serde", "serde_derive", "serde_json", "termcolor", + "toml", ] [[package]] @@ -1909,41 +1909,17 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" @@ -1958,21 +1934,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] -name = "url" -version = "2.5.0" +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" [[package]] name = "version_check" @@ -1980,6 +1951,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1988,91 +1969,112 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-encoder" -version = "0.31.1" +version = "0.201.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41763f20eafed1399fff1afb466496d3a959f58241436cfdc17e3f5ca954de16" +checksum = "b9c7d2731df60006819b013f64ccc2019691deccf6e11a1804bc850cd6748f1a" dependencies = [ "leb128", ] [[package]] name = "wasm-encoder" -version = "0.38.0" +version = "0.205.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b09bc5df933a3dabbdb72ae4b6b71be8ae07f58774d5aa41bd20adcd41a235a" +checksum = "90e95b3563d164f33c1cfb0a7efbd5940c37710019be10cd09f800fdec8b0e5c" dependencies = [ "leb128", ] [[package]] name = "wasmparser" -version = "0.110.0" +version = "0.201.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dfcdb72d96f01e6c85b6bf20102e7423bdbaad5c337301bab2bbf253d26413c" +checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708" dependencies = [ - "indexmap 2.1.0", + "bitflags 2.5.0", + "indexmap", "semver", ] +[[package]] +name = "wasmprinter" +version = "0.201.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67e66da702706ba08729a78e3c0079085f6bfcb1a62e4799e97bbf728c2c265" +dependencies = [ + "anyhow", + "wasmparser", +] + [[package]] name = "wasmtime" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e87029cc5760db9a3774aff4708596fe90c20ed2baeef97212e98b812fd0fc" +checksum = "4e300c0e3f19dc9064e3b17ce661088646c70dbdde36aab46470ed68ba58db7d" dependencies = [ + "addr2line", "anyhow", "async-trait", "bincode", "bumpalo", "cfg-if", + "encoding_rs", "fxprof-processed-profile", - "indexmap 2.1.0", + "gimli", + "indexmap", + "ittapi", "libc", "log", "object", "once_cell", "paste", - "psm", "rayon", + "rustix", + "semver", "serde", + "serde_derive", "serde_json", "target-lexicon", - "wasm-encoder 0.31.1", + "wasm-encoder 0.201.0", "wasmparser", "wasmtime-cache", "wasmtime-component-macro", + "wasmtime-component-util", "wasmtime-cranelift", "wasmtime-environ", "wasmtime-fiber", - "wasmtime-jit", + "wasmtime-jit-debug", + "wasmtime-jit-icache-coherence", "wasmtime-runtime", + "wasmtime-slab", + "wasmtime-winch", "wat", "windows-sys", ] [[package]] name = "wasmtime-asm-macros" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d84f68d831200016e120f2ee79d81b50cf4c4123112914aefb168d036d445d" +checksum = "110aa598e02a136fb095ca70fa96367fc16bab55256a131e66f9b58f16c73daf" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31561fbbaa86d3c042696940bc9601146bf4aaec39ae725c86b5f1358d8d7023" +checksum = "c4e660537b0ac2fc76917fb0cc9d403d2448b6983a84e59c51f7fea7b7dae024" dependencies = [ "anyhow", "base64", "bincode", "directories-next", - "file-per-thread-logger", "log", "rustix", "serde", + "serde_derive", "sha2", "toml", "windows-sys", @@ -2081,14 +2083,14 @@ dependencies = [ [[package]] name = "wasmtime-component-macro" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e7e07b8da23838e870c4c092027208ac546398a2ac4f5afff33a1ea1d763ec0" +checksum = "091f32ce586251ac4d07019388fb665b010d9518ffe47be1ddbabb162eed6007" dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser", @@ -2096,17 +2098,18 @@ dependencies = [ [[package]] name = "wasmtime-component-util" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f421bc59c753dcd24e39601928a0f2915adf15f40d8ba0066c4cf23f92c9a0" +checksum = "0dd17dc1ebc0b28fd24b6b9d07638f55b82ae908918ff08fd221f8b0fefa9125" [[package]] name = "wasmtime-cranelift" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae8ed7a4845f22be6b1ad80f33f43fa03445b03a02f2d40dca695129769cd1a" +checksum = "e923262451a4b5b39fe02f69f1338d56356db470e289ea1887346b9c7f592738" dependencies = [ "anyhow", + "cfg-if", "cranelift-codegen", "cranelift-control", "cranelift-entity", @@ -2126,9 +2129,9 @@ dependencies = [ [[package]] name = "wasmtime-cranelift-shared" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b17099f9320a1c481634d88101258917d5065717cf22b04ed75b1a8ea062b4" +checksum = "508898cbbea0df81a5d29cfc1c7c72431a1bc4c9e89fd9514b4c868474c05c7a" dependencies = [ "anyhow", "cranelift-codegen", @@ -2142,29 +2145,37 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8b9227b1001229ff125e0f76bf1d5b9dc4895e6bcfd5cc35a56f84685964ec7" +checksum = "d7e3f2aa72dbb64c19708646e1ff97650f34e254598b82bad5578ea9c80edd30" dependencies = [ "anyhow", + "bincode", + "cpp_demangle", "cranelift-entity", "gimli", - "indexmap 2.1.0", + "indexmap", "log", "object", + "rustc-demangle", "serde", + "serde_derive", "target-lexicon", "thiserror", + "wasm-encoder 0.201.0", "wasmparser", + "wasmprinter", + "wasmtime-component-util", "wasmtime-types", ] [[package]] name = "wasmtime-fiber" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc8c8410c03a79073ea06806ccde3da4854c646bd646b3b2707b99b3746c3f70" +checksum = "9235b643527bcbac808216ed342e1fba324c95f14a62762acfa6f2e6ca5edbd6" dependencies = [ + "anyhow", "cc", "cfg-if", "rustix", @@ -2173,37 +2184,11 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "wasmtime-jit" -version = "12.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cce606b392c321d7272928003543447119ef937a9c3ebfce5c4bb0bf6b0f5bac" -dependencies = [ - "addr2line", - "anyhow", - "bincode", - "cfg-if", - "cpp_demangle", - "gimli", - "ittapi", - "log", - "object", - "rustc-demangle", - "rustix", - "serde", - "target-lexicon", - "wasmtime-environ", - "wasmtime-jit-debug", - "wasmtime-jit-icache-coherence", - "wasmtime-runtime", - "windows-sys", -] - [[package]] name = "wasmtime-jit-debug" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef27ea6c34ef888030d15560037fe7ef27a5609fbbba8e1e3e41dc4245f5bb2" +checksum = "92de34217bf7f0464262adf391a9950eba440f9dfc7d3b0e3209302875c6f65f" dependencies = [ "object", "once_cell", @@ -2213,9 +2198,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-icache-coherence" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b59f94b0409221873565419168e20b5aedf18c4bd64de5c38acf8f0634efeee3" +checksum = "c22ca2ef4d87b23d400660373453e274b2251bc2d674e3102497f690135e04b0" dependencies = [ "cfg-if", "libc", @@ -2224,84 +2209,117 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceb587a88ae5bb6ca248455a391aff29ac63329a404b2cdea36d91267c797db4" +checksum = "1806ee242ca4fd183309b7406e4e83ae7739b7569f395d56700de7c7ef9f5eb8" dependencies = [ "anyhow", "cc", "cfg-if", - "indexmap 2.1.0", + "encoding_rs", + "indexmap", "libc", "log", "mach", "memfd", "memoffset", "paste", - "rand", + "psm", "rustix", "sptr", - "wasm-encoder 0.31.1", + "wasm-encoder 0.201.0", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-fiber", "wasmtime-jit-debug", "wasmtime-versioned-export-macros", + "wasmtime-wmemcheck", "windows-sys", ] +[[package]] +name = "wasmtime-slab" +version = "19.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c58bef9ce877fd06acb58f08d003af17cb05cc51225b455e999fbad8e584c0" + [[package]] name = "wasmtime-types" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77943729d4b46141538e8d0b6168915dc5f88575ecdfea26753fd3ba8bab244a" +checksum = "cebe297aa063136d9d2e5b347c1528868aa43c2c8d0e1eb0eec144567e38fe0f" dependencies = [ "cranelift-entity", "serde", + "serde_derive", "thiserror", "wasmparser", ] [[package]] name = "wasmtime-versioned-export-macros" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca7af9bb3ee875c4907835e607a275d10b04d15623d3aebe01afe8fbd3f85050" +checksum = "ffaafa5c12355b1a9ee068e9295d50c4ca0a400c721950cdae4f5b54391a2da5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", +] + +[[package]] +name = "wasmtime-winch" +version = "19.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d618b4e90d3f259b1b77411ce573c9f74aade561957102132e169918aabdc863" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "object", + "target-lexicon", + "wasmparser", + "wasmtime-cranelift-shared", + "wasmtime-environ", + "winch-codegen", ] [[package]] name = "wasmtime-wit-bindgen" -version = "12.0.2" +version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14770d0820f56ba86cdd9987aef97cc3bacbb0394633c37dbfbc61ef29603a71" +checksum = "7c7a253c8505edd7493603e548bff3af937b0b7dbf2b498bd5ff2131b651af72" dependencies = [ "anyhow", - "heck", - "indexmap 2.1.0", + "heck 0.4.1", + "indexmap", "wit-parser", ] +[[package]] +name = "wasmtime-wmemcheck" +version = "19.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a8c62e9df8322b2166d2a6f096fbec195ddb093748fd74170dcf25ef596769" + [[package]] name = "wast" -version = "69.0.0" +version = "205.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa51b5ad1391943d1bfad537e50f28fe938199ee76b115be6bae83802cd5185" +checksum = "441a6a195b3b5245e26d450bbcc91366c6b652382a22f63cbe3c73240e13b2bb" dependencies = [ + "bumpalo", "leb128", "memchr", "unicode-width", - "wasm-encoder 0.38.0", + "wasm-encoder 0.205.0", ] [[package]] name = "wat" -version = "1.0.81" +version = "1.205.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74a4c2488d058326466e086a43f5d4ea448241a8d0975e3eb0642c0828be1eb3" +checksum = "19832624d606e7c6bf3cd4caa73578ecec5eac30c768269256d19c79900beb18" dependencies = [ "wast", ] @@ -2337,13 +2355,29 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winch-codegen" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d15869abc9e3bb29c017c003dbe007a08e9910e8ff9023a962aa13c1b2ee6af" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "regalloc2", + "smallvec", + "target-lexicon", + "wasmparser", + "wasmtime-environ", +] + [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.5", ] [[package]] @@ -2352,13 +2386,29 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -2367,56 +2417,115 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352" +dependencies = [ + "memchr", +] + [[package]] name = "wit-parser" -version = "0.9.2" +version = "0.201.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "541efa2046e544de53a9da1e2f6299e63079840360c9e106f1f8275a97771318" +checksum = "196d3ecfc4b759a8573bf86a9b3f8996b304b3732e4c7de81655f875f6efdca6" dependencies = [ "anyhow", "id-arena", - "indexmap 2.1.0", + "indexmap", "log", - "pulldown-cmark", "semver", + "serde", + "serde_derive", + "serde_json", "unicode-xid", - "url", + "wasmparser", ] [[package]] @@ -2436,33 +2545,32 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] name = "zstd" -version = "0.11.2+zstd.1.5.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" dependencies = [ - "libc", "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.10+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index ec9067831..2893e369a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/dfinity/cdk-rs" # MSRV # Avoid updating this field unless we use new Rust features # Sync with rust-toolchain.toml -rust-version = "1.70.0" +rust-version = "1.75.0" license = "Apache-2.0" [profile.canister-release] diff --git a/examples/print/tests/basic.bats b/examples/print/tests/basic.bats index 959f86313..aca0d2877 100644 --- a/examples/print/tests/basic.bats +++ b/examples/print/tests/basic.bats @@ -18,3 +18,14 @@ teardown() { run dfx canister call print print assert_success } + +@test "candid-extractor supports version and help" { + run candid-extractor --version + assert_success + run candid-extractor -V + assert_success + run candid-extractor --help + assert_success + run candid-extractor -h + assert_success +} diff --git a/library/ic-certified-map/src/rbtree/test.rs b/library/ic-certified-map/src/rbtree/test.rs index 40fa6a13f..a4ba5c590 100644 --- a/library/ic-certified-map/src/rbtree/test.rs +++ b/library/ic-certified-map/src/rbtree/test.rs @@ -323,6 +323,7 @@ fn test_witness_value_range() { } #[test] +#[allow(clippy::map_identity)] fn test_iter() { let mut t = TreeOfBytes::new(); let mut v = vec![]; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 22ff7da10..954f9d75d 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.70.0" # sync with rust-version in root Cargo.toml +channel = "1.75.0" # sync with rust-version in root Cargo.toml targets = ["wasm32-unknown-unknown"] components = ["rustfmt", "clippy"] diff --git a/src/candid-extractor/CHANGELOG.md b/src/candid-extractor/CHANGELOG.md new file mode 100644 index 000000000..859cf8751 --- /dev/null +++ b/src/candid-extractor/CHANGELOG.md @@ -0,0 +1,30 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [unreleased] + +## [0.1.3] - 2024-04-22 + +### Added + +- Use `clap` to support `-V`/`--version` and `-h`/`--help`. (#485) + +## [0.1.1] - 2023-10-11 + +### Added + +- Includes new system API `cycles_burn128`. (#434) +## [0.1.1] - 2023-09-19 + +### Added + +- Release from the [CI workflow](../../.github/workflows/release-candid-extractor.yml). (#427) + +## [0.1.0] - 2023-09-18 + +### Added + +- The first release. (#424) diff --git a/src/candid-extractor/Cargo.toml b/src/candid-extractor/Cargo.toml index 024ba79d2..7c7b8ba60 100644 --- a/src/candid-extractor/Cargo.toml +++ b/src/candid-extractor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid-extractor" -version = "0.1.2" +version = "0.1.3" authors.workspace = true edition.workspace = true license.workspace = true @@ -14,7 +14,8 @@ include = ["src", "Cargo.toml", "LICENSE", "README.md", "ic_mock.wat"] [dependencies] anyhow = "1.0.72" -wasmtime = "12" +wasmtime = "19" +clap = { version = "4", features = ["derive"] } [dev-dependencies] quote.workspace = true diff --git a/src/candid-extractor/src/extract.rs b/src/candid-extractor/src/extract.rs new file mode 100644 index 000000000..eaebd4033 --- /dev/null +++ b/src/candid-extractor/src/extract.rs @@ -0,0 +1,38 @@ +use anyhow::Result; +use std::path::Path; +use wasmtime::*; + +static IC0: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/ic_mock.wat")); + +pub(crate) fn extract_candid

(wasm_path: P) -> Result +where + P: AsRef, +{ + let mut store: Store<()> = Store::<()>::default(); + + let mut linker = Linker::new(store.engine()); + let ic0_module = Module::new(store.engine(), IC0)?; + let ic0 = linker.instantiate(&mut store, &ic0_module)?; + linker.instance(&mut store, "ic0", ic0)?; + + let module = Module::from_file(store.engine(), wasm_path)?; + let canister = linker.instantiate(&mut store, &module)?; + + let get_candid_pointer = + canister.get_typed_func::<(), i32>(&mut store, "get_candid_pointer")?; + let candid_pointer = get_candid_pointer.call(&mut store, ())?; + + let memory = canister + .get_memory(&mut store, "memory") + .ok_or_else(|| anyhow::format_err!("failed to find `memory` export"))?; + let memory_buffer = memory.data(&store); + + let mut i = candid_pointer as usize; + let mut str_vec = vec![]; + while memory_buffer[i] != 0 { + str_vec.push(memory_buffer[i]); + i += 1; + } + let s = String::from_utf8(str_vec)?; + Ok(s) +} diff --git a/src/candid-extractor/src/main.rs b/src/candid-extractor/src/main.rs index 6ef9a2472..0f3b2a699 100644 --- a/src/candid-extractor/src/main.rs +++ b/src/candid-extractor/src/main.rs @@ -1,50 +1,20 @@ -use std::path::Path; - -use anyhow::{bail, Result}; -use wasmtime::*; - -static IC0: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/ic_mock.wat")); - -fn generate_candid

(wasm_path: P) -> Result -where - P: AsRef, -{ - let mut store: Store<()> = Store::<()>::default(); - - let mut linker = Linker::new(store.engine()); - let ic0_module = Module::new(store.engine(), IC0)?; - let ic0 = linker.instantiate(&mut store, &ic0_module)?; - linker.instance(&mut store, "ic0", ic0)?; - - let module = Module::from_file(store.engine(), wasm_path)?; - let canister = linker.instantiate(&mut store, &module)?; - - let get_candid_pointer = - canister.get_typed_func::<(), i32>(&mut store, "get_candid_pointer")?; - let candid_pointer = get_candid_pointer.call(&mut store, ())?; - - let memory = canister - .get_memory(&mut store, "memory") - .ok_or_else(|| anyhow::format_err!("failed to find `memory` export"))?; - let memory_buffer = memory.data(&store); - - let mut i = candid_pointer as usize; - let mut str_vec = vec![]; - while memory_buffer[i] != 0 { - str_vec.push(memory_buffer[i]); - i += 1; - } - let s = String::from_utf8(str_vec)?; - Ok(s) +use anyhow::Result; +use clap::Parser; +use std::path::PathBuf; + +mod extract; + +/// Extract the Candid interface from a Canister WASM file. +#[derive(Parser)] +#[command(version, about)] +struct Cli { + /// Path to the Canister WASM file. + path: PathBuf, } fn main() -> Result<()> { - let args: Vec<_> = std::env::args().collect(); - if args.len() != 2 { - // The first arg will the name of current binary. - bail!("Expecting one argument: path to the canister WASM file"); - } - let c = generate_candid(args.last().unwrap())?; - println!("{c}"); + let cli = Cli::parse(); + let candid = extract::extract_candid(cli.path)?; + println!("{candid}"); Ok(()) } From 58faf92083add2f7821e7511f468d98897542233 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 6 May 2024 14:37:56 -0400 Subject: [PATCH 210/234] feat: add API `in_replicated_execution()` (#489) * update ic0.txt * auto-gen files * add the safe wrapper * e2e * Changelog --- Cargo.lock | 2 +- Cargo.toml | 2 +- e2e-tests/canisters/api_call.rs | 10 ++++++++++ e2e-tests/tests/e2e.rs | 8 ++++++++ ic0.txt | 10 ++++++---- src/candid-extractor/CHANGELOG.md | 5 +++++ src/candid-extractor/ic_mock.wat | 1 + src/ic-cdk/CHANGELOG.md | 9 +++++++-- src/ic-cdk/src/api/mod.rs | 12 ++++++++++++ src/ic0/Cargo.toml | 2 +- src/ic0/src/ic0.rs | 4 ++++ 11 files changed, 56 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9a1be963..049f28038 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1032,7 +1032,7 @@ dependencies = [ [[package]] name = "ic0" -version = "0.21.1" +version = "0.23.0" dependencies = [ "quote", "syn 2.0.60", diff --git a/Cargo.toml b/Cargo.toml index 2893e369a..cff29a409 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ lto = true opt-level = 'z' [workspace.dependencies] -ic0 = { path = "src/ic0", version = "0.21.1" } +ic0 = { path = "src/ic0", version = "0.23.0" } ic-cdk = { path = "src/ic-cdk", version = "0.13.2"} ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.7.0" } diff --git a/e2e-tests/canisters/api_call.rs b/e2e-tests/canisters/api_call.rs index 2f8f90002..06fe45c0c 100644 --- a/e2e-tests/canisters/api_call.rs +++ b/e2e-tests/canisters/api_call.rs @@ -15,4 +15,14 @@ fn cycles_burn(amount: u128) -> u128 { ic_cdk::api::cycles_burn(amount) } +#[update] +fn update_is_replicated() -> bool { + ic_cdk::api::in_replicated_execution() +} + +#[query] +fn query_is_not_replicated() -> bool { + ic_cdk::api::in_replicated_execution() +} + fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index bf9541df6..879d4598c 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -182,6 +182,14 @@ fn test_api_call() { ) .unwrap(); assert_eq!(result, WasmResult::Reject("manual reject".to_string())); + + let (result,): (bool,) = call_candid(&env, canister_id, "update_is_replicated", ()) + .expect("Failed to call update_is_replicated"); + assert!(result); + + let (result,): (bool,) = query_candid(&env, canister_id, "query_is_not_replicated", ()) + .expect("Failed to call query_is_not_replicated"); + assert!(!result); } #[test] diff --git a/ic0.txt b/ic0.txt index 29955e510..c842e930d 100644 --- a/ic0.txt +++ b/ic0.txt @@ -17,7 +17,8 @@ ic0.msg_cycles_refunded128 : (dst : i32) -> (); // R ic0.msg_cycles_accept : (max_amount : i64) -> (amount : i64); // U Rt Ry ic0.msg_cycles_accept128 : (max_amount_high : i64, max_amount_low: i64, dst : i32) -> (); // U Rt Ry -ic0.cycles_burn128 : (amount_high : i64, amount_low : i64, dst : i32) -> ();// I G U Ry Rt C T + +ic0.cycles_burn128 : (amount_high : i64, amount_low : i64, dst : i32) -> (); // I G U Ry Rt C T ic0.canister_self_size : () -> i32; // * ic0.canister_self_copy : (dst : i32, offset : i32, size : i32) -> (); // * @@ -57,13 +58,14 @@ ic0.stable64_read : (dst : i64, offset : i64, size : i64) -> (); // * ic0.certified_data_set : (src: i32, size: i32) -> (); // I G U Ry Rt T ic0.data_certificate_present : () -> i32; // * -ic0.data_certificate_size : () -> i32; // * -ic0.data_certificate_copy : (dst: i32, offset: i32, size: i32) -> (); // * +ic0.data_certificate_size : () -> i32; // Q CQ +ic0.data_certificate_copy : (dst: i32, offset: i32, size: i32) -> (); // Q CQ ic0.time : () -> (timestamp : i64); // * ic0.global_timer_set : (timestamp : i64) -> i64; // I G U Ry Rt C T ic0.performance_counter : (counter_type : i32) -> (counter : i64); // * s ic0.is_controller: (src: i32, size: i32) -> ( result: i32); // * s +ic0.in_replicated_execution: () -> (result: i32); // * s ic0.debug_print : (src : i32, size : i32) -> (); // * s -ic0.trap : (src : i32, size : i32) -> (); // * s \ No newline at end of file +ic0.trap : (src : i32, size : i32) -> (); // * s diff --git a/src/candid-extractor/CHANGELOG.md b/src/candid-extractor/CHANGELOG.md index 859cf8751..c8d023468 100644 --- a/src/candid-extractor/CHANGELOG.md +++ b/src/candid-extractor/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Added + +- Upgrade `ic0` to 0.23.0 which includes the new system API `in_replicated_execution`. + ## [0.1.3] - 2024-04-22 ### Added @@ -17,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Includes new system API `cycles_burn128`. (#434) + ## [0.1.1] - 2023-09-19 ### Added diff --git a/src/candid-extractor/ic_mock.wat b/src/candid-extractor/ic_mock.wat index 17e1f5d41..2886218a5 100644 --- a/src/candid-extractor/ic_mock.wat +++ b/src/candid-extractor/ic_mock.wat @@ -49,6 +49,7 @@ (func (export "global_timer_set") (param i64) (result i64) i64.const 0) (func (export "performance_counter") (param i32) (result i64) i64.const 0) (func (export "is_controller") (param i32 i32) (result i32) i32.const 0) + (func (export "in_replicated_execution") (result i32) i32.const 0) (func (export "debug_print") (param i32 i32) ) (func (export "trap") (param i32 i32) ) ) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 014688e6c..79e86f809 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -8,16 +8,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Add `wasm_memory_limit` to the management canister API types: (#483) +- Add `wasm_memory_limit` to the management canister API types: (#483) * `CanisterSettings` * `DefiniteCanisterSettings`. +- Provide safe wrapper of `in_replicated_execution` in ic-cdk. (#489) + +### Changed + +- Upgrade `ic0` to v0.23.0. (#489) ## [0.13.2] - 2024-04-08 ### Added - Management canister methods for interacting with the chunk store. (#461) -- Provide safe wrapper of global_timer_set in ic-cdk. (#475) +- Provide safe wrapper of `global_timer_set` in ic-cdk. (#475) ## [0.13.1] - 2024-03-01 diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index 5a2d5fcf2..5663b46fe 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -193,3 +193,15 @@ pub fn set_global_timer(timestamp: u64) -> u64 { // SAFETY: ic0.global_timer_set is always safe to call. unsafe { ic0::global_timer_set(timestamp as i64) as u64 } } + +/// Checks if in replicated execution. +/// +/// The canister can check whether it is currently running in replicated or non replicated execution. +pub fn in_replicated_execution() -> bool { + // SAFETY: ic0.in_replicated_execution is always safe to call. + match unsafe { ic0::in_replicated_execution() } { + 0 => false, + 1 => true, + _ => unreachable!(), + } +} diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml index 540cb3d99..266013dcf 100644 --- a/src/ic0/Cargo.toml +++ b/src/ic0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic0" -version = "0.21.1" +version = "0.23.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic0/src/ic0.rs b/src/ic0/src/ic0.rs index bac51bf5f..9a2ed93ed 100644 --- a/src/ic0/src/ic0.rs +++ b/src/ic0/src/ic0.rs @@ -60,6 +60,7 @@ extern "C" { pub fn global_timer_set(timestamp: i64) -> i64; pub fn performance_counter(counter_type: i32) -> i64; pub fn is_controller(src: i32, size: i32) -> i32; + pub fn in_replicated_execution() -> i32; pub fn debug_print(src: i32, size: i32); pub fn trap(src: i32, size: i32); } @@ -222,6 +223,9 @@ mod non_wasm { pub unsafe fn is_controller(src: i32, size: i32) -> i32 { panic!("is_controller should only be called inside canisters."); } + pub unsafe fn in_replicated_execution() -> i32 { + panic!("in_replicated_execution should only be called inside canisters."); + } pub unsafe fn debug_print(src: i32, size: i32) { panic!("debug_print should only be called inside canisters."); } From 05ca5719c3baf7fb4c4982e31097ff8b07fd8a25 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Fri, 10 May 2024 13:09:30 -0400 Subject: [PATCH 211/234] chore: release 20240510 (#491) --- Cargo.lock | 324 ++++++++++++------------------ Cargo.toml | 2 +- src/candid-extractor/CHANGELOG.md | 2 + src/candid-extractor/Cargo.toml | 2 +- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 2 + src/ic-cdk/Cargo.toml | 4 +- 7 files changed, 142 insertions(+), 196 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 049f28038..74e167a26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,47 +34,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys", @@ -82,9 +83,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" [[package]] name = "arbitrary" @@ -115,14 +116,14 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "base64" @@ -183,12 +184,6 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.5.0" @@ -227,9 +222,9 @@ dependencies = [ [[package]] name = "candid" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818394610ed32d9e4c81025f97c8580698b69542527efde18514cf9ad1f8f5f0" +checksum = "dd5902d37352dffd8bd9177a2daa6444ce3cd0279c91763fb0171c053aa04335" dependencies = [ "anyhow", "binread", @@ -250,12 +245,12 @@ dependencies = [ [[package]] name = "candid-extractor" -version = "0.1.3" +version = "0.1.4" dependencies = [ "anyhow", "clap", "quote", - "syn 2.0.60", + "syn 2.0.61", "wasmtime", ] @@ -268,7 +263,7 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -314,9 +309,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.95" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" dependencies = [ "jobserver", "libc", @@ -387,7 +382,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -408,9 +403,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "convert_case" @@ -462,7 +457,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "log", "regalloc2", "smallvec", @@ -600,9 +595,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "debugid" @@ -662,9 +657,9 @@ checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "ena" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" dependencies = [ "log", ] @@ -686,9 +681,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys", @@ -780,7 +775,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -828,7 +823,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" dependencies = [ - "bitflags 2.5.0", + "bitflags", "debugid", "fxhash", "serde", @@ -847,9 +842,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -900,9 +895,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", ] @@ -927,7 +922,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "ic-cdk" -version = "0.13.2" +version = "0.13.3" dependencies = [ "anyhow", "candid", @@ -969,14 +964,14 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.13.2" +version = "0.13.3" dependencies = [ "candid", "proc-macro2", "quote", "serde", "serde_tokenstream", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -1035,7 +1030,7 @@ name = "ic0" version = "0.23.0" dependencies = [ "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -1065,10 +1060,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itertools" version = "0.11.0" @@ -1167,9 +1168,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libredox" @@ -1177,7 +1178,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags", "libc", ] @@ -1189,9 +1190,9 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1223,7 +1224,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.6.29", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -1276,11 +1277,10 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ - "autocfg", "num-integer", "num-traits", "serde", @@ -1297,9 +1297,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -1311,7 +1311,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "crc32fast", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "indexmap", "memchr", ] @@ -1324,9 +1324,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -1334,28 +1334,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", "indexmap", @@ -1413,9 +1413,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] @@ -1460,11 +1460,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -1541,9 +1541,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -1562,11 +1562,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.33" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3cc72858054fcff6d7dea32df2aeaee6a7c24227366d7ea429aada2f26b16ad" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -1575,15 +1575,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -1602,18 +1602,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.198" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] @@ -1639,20 +1639,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -1677,7 +1677,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -1784,9 +1784,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" dependencies = [ "proc-macro2", "quote", @@ -1821,22 +1821,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -1884,12 +1884,11 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.91" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad7eb6319ebadebca3dacf1f85a93bc54b73dd81b9036795f73de7ddfe27d5a" +checksum = "4ddb747392ea12569d501a5bbca08852e4c8cd88b92566074b2243b8846f09e6" dependencies = [ "glob", - "once_cell", "serde", "serde_derive", "serde_json", @@ -1923,9 +1922,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unicode-xid" @@ -1978,9 +1977,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.205.0" +version = "0.207.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e95b3563d164f33c1cfb0a7efbd5940c37710019be10cd09f800fdec8b0e5c" +checksum = "d996306fb3aeaee0d9157adbe2f670df0236caf19f6728b221e92d0f27b3fe17" dependencies = [ "leb128", ] @@ -1991,7 +1990,7 @@ version = "0.201.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708" dependencies = [ - "bitflags 2.5.0", + "bitflags", "indexmap", "semver", ] @@ -2090,7 +2089,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser", @@ -2264,7 +2263,7 @@ checksum = "ffaafa5c12355b1a9ee068e9295d50c4ca0a400c721950cdae4f5b54391a2da5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -2304,22 +2303,22 @@ checksum = "c9a8c62e9df8322b2166d2a6f096fbec195ddb093748fd74170dcf25ef596769" [[package]] name = "wast" -version = "205.0.0" +version = "207.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "441a6a195b3b5245e26d450bbcc91366c6b652382a22f63cbe3c73240e13b2bb" +checksum = "0e40be9fd494bfa501309487d2dc0b3f229be6842464ecbdc54eac2679c84c93" dependencies = [ "bumpalo", "leb128", "memchr", "unicode-width", - "wasm-encoder 0.205.0", + "wasm-encoder 0.207.0", ] [[package]] name = "wat" -version = "1.205.0" +version = "1.207.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19832624d606e7c6bf3cd4caa73578ecec5eac30c768269256d19c79900beb18" +checksum = "8eb2b15e2d5f300f5e1209e7dc237f2549edbd4203655b6c6cab5cf180561ee7" dependencies = [ "wast", ] @@ -2342,11 +2341,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys", ] [[package]] @@ -2377,22 +2376,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -2401,46 +2385,28 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.5" @@ -2453,48 +2419,24 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.5" @@ -2503,9 +2445,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" dependencies = [ "memchr", ] @@ -2530,22 +2472,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cff29a409..78ad9238b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.23.0" } -ic-cdk = { path = "src/ic-cdk", version = "0.13.2"} +ic-cdk = { path = "src/ic-cdk", version = "0.13.3"} ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.7.0" } candid = "0.10.4" diff --git a/src/candid-extractor/CHANGELOG.md b/src/candid-extractor/CHANGELOG.md index c8d023468..ece920116 100644 --- a/src/candid-extractor/CHANGELOG.md +++ b/src/candid-extractor/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.1.4] - 2024-05-10 + ### Added - Upgrade `ic0` to 0.23.0 which includes the new system API `in_replicated_execution`. diff --git a/src/candid-extractor/Cargo.toml b/src/candid-extractor/Cargo.toml index 7c7b8ba60..42dbc1f86 100644 --- a/src/candid-extractor/Cargo.toml +++ b/src/candid-extractor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid-extractor" -version = "0.1.3" +version = "0.1.4" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index cd6926080..3cc45496f 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.13.2" # sync with ic-cdk +version = "0.13.3" # sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 79e86f809..23cb8570e 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.13.3] - 2024-05-10 + ### Added - Add `wasm_memory_limit` to the management canister API types: (#483) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 1993d34a3..6ca287897 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.13.2" # sync with ic-cdk-macros +version = "0.13.3" # sync with ic-cdk-macros authors.workspace = true edition.workspace = true license.workspace = true @@ -27,7 +27,7 @@ ic0.workspace = true # Dependents won't accidentaly upgrading ic-cdk-macros only but not ic-cdk. # ic-cdk-macros is a hidden dependency, re-exported by ic-cdk. # It should not be included by users direcly. -ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.13.2" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.13.3" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true } From 223c28283aca1d4c321e560d5a1818df21469a77 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Fri, 17 May 2024 11:38:13 -0700 Subject: [PATCH 212/234] chore: Release 0.14.0 (#494) * Release 0.14.0 * lockfile * ic-ledger-types and changelogs * mark yank --- Cargo.lock | 8 ++++---- Cargo.toml | 4 ++-- library/ic-ledger-types/CHANGELOG.md | 6 ++++++ library/ic-ledger-types/Cargo.toml | 2 +- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-timers/CHANGELOG.md | 6 ++++++ src/ic-cdk-timers/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 3 ++- src/ic-cdk/Cargo.toml | 4 ++-- 9 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74e167a26..d1fedada8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -922,7 +922,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "ic-cdk" -version = "0.13.3" +version = "0.14.0" dependencies = [ "anyhow", "candid", @@ -964,7 +964,7 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.13.3" +version = "0.14.0" dependencies = [ "candid", "proc-macro2", @@ -976,7 +976,7 @@ dependencies = [ [[package]] name = "ic-cdk-timers" -version = "0.7.0" +version = "0.8.0" dependencies = [ "futures", "ic-cdk", @@ -1002,7 +1002,7 @@ dependencies = [ [[package]] name = "ic-ledger-types" -version = "0.10.0" +version = "0.11.0" dependencies = [ "candid", "crc32fast", diff --git a/Cargo.toml b/Cargo.toml index 78ad9238b..14f536c9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,8 +21,8 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.23.0" } -ic-cdk = { path = "src/ic-cdk", version = "0.13.3"} -ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.7.0" } +ic-cdk = { path = "src/ic-cdk", version = "0.14.0"} +ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.8.0" } candid = "0.10.4" candid_parser = "0.1.4" diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index 997458b98..4f577b031 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.11.0] - 2024-05-17 + +### Changed + +- Upgrade `ic-cdk` to v0.14. + ## [0.10.0] - 2024-03-01 ### Changed diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index fe599cef6..0598de229 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.10.0" +version = "0.11.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 3cc45496f..22f66b642 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.13.3" # sync with ic-cdk +version = "0.14.0" # sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index 5ec74beec..76daa57d0 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.8.0] - 2024-05-17 + +### Changed + +- Upgrade `ic-cdk` to v0.14. + ## [0.7.0] - 2024-03-01 ### Changed diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index aa241dd9e..02262bf77 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.7.0" +version = "0.8.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 23cb8570e..e4fc05c7f 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,7 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -## [0.13.3] - 2024-05-10 +## [0.14.0] - 2024-05-17 +## [0.13.3] - 2024-05-10 (yanked) ### Added diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 6ca287897..0ed5cbf69 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.13.3" # sync with ic-cdk-macros +version = "0.14.0" # sync with ic-cdk-macros authors.workspace = true edition.workspace = true license.workspace = true @@ -27,7 +27,7 @@ ic0.workspace = true # Dependents won't accidentaly upgrading ic-cdk-macros only but not ic-cdk. # ic-cdk-macros is a hidden dependency, re-exported by ic-cdk. # It should not be included by users direcly. -ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.13.3" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.14.0" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true } From 7fa27b03d0d891b30a89b1b281ca3ba0661f2750 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 28 May 2024 10:28:48 -0400 Subject: [PATCH 213/234] test: use pocket-ic in e2e-tests (#495) * script to download pocket-ic binary * use pocket-ic in e2e tests * fix canister_info * fix test_call_management * fix test_chunk * fix test_cycles_burn * fix test_scheduling_many_timers * fix test_set_global_timers * raise init cycles * ci.yml * cargo update * Revert "cargo update" This reverts commit 6c969d06e03fa62988084c4ef995ba43b7c4b46d. * pocket-ic from mono-repo tag * run cargo test on macos too * fix ci --- .github/workflows/ci.yml | 12 +- .gitignore | 2 +- Cargo.lock | 1221 ++++++++++++++++++++-- e2e-tests/Cargo.toml | 4 +- e2e-tests/canisters/canister_info.rs | 11 +- e2e-tests/canisters/chunk.rs | 2 +- e2e-tests/canisters/management_caller.rs | 8 +- e2e-tests/tests/e2e.rs | 349 ++++--- scripts/download_pocket_ic.sh | 21 + scripts/download_state_machine_binary.sh | 18 - 10 files changed, 1364 insertions(+), 284 deletions(-) create mode 100755 scripts/download_pocket_ic.sh delete mode 100755 scripts/download_state_machine_binary.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f21fe3748..814e425b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,10 @@ jobs: test: name: cargo test - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-12] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -57,11 +60,12 @@ jobs: restore-keys: | ${{ runner.os }}-test- ${{ runner.os }}- - - name: Download ic-test-state-machine + - name: Download pocket-ic run: | - bash scripts/download_state_machine_binary.sh + bash scripts/download_pocket_ic.sh - name: Run tests - run: | # https://github.com/rust-lang/cargo/issues/6669 we have to run ALL tests with two commands + run: + | # https://github.com/rust-lang/cargo/issues/6669 we have to run ALL tests with two commands cargo test --all-targets cargo test --doc diff --git a/.gitignore b/.gitignore index 1ce6e64be..5a787c2e5 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,7 @@ examples/*/Cargo.lock **/*.rs.bk .DS_Store -ic-test-state-machine +e2e-tests/pocket-ic # Generated bindings **/declarations/ diff --git a/Cargo.lock b/Cargo.lock index d1fedada8..fcd8d63b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "gimli", ] +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "ahash" version = "0.8.11" @@ -68,7 +74,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -78,7 +84,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -119,18 +125,51 @@ dependencies = [ "syn 2.0.61", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64" version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "beef" version = "0.5.2" @@ -211,6 +250,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + [[package]] name = "camino" version = "1.1.6" @@ -296,15 +341,16 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.14.2" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", "semver", "serde", "serde_json", + "thiserror", ] [[package]] @@ -324,33 +370,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "ciborium" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" - -[[package]] -name = "ciborium-ll" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" -dependencies = [ - "ciborium-io", - "half 2.4.1", -] - [[package]] name = "clap" version = "4.5.4" @@ -416,6 +435,22 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "cpp_demangle" version = "0.4.3" @@ -552,6 +587,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -608,6 +652,15 @@ dependencies = [ "uuid", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "digest" version = "0.10.7" @@ -649,6 +702,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "either" version = "1.11.0" @@ -686,7 +745,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -719,6 +778,15 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "futures" version = "0.3.30" @@ -869,20 +937,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] -name = "half" -version = "1.8.3" +name = "h2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] [[package]] name = "half" -version = "2.4.1" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hashbrown" @@ -914,11 +991,130 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "hyper" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d8d52be92d09acc2e01dddb7fde3ad983fc6489c7db4837e605bc3fca4cb63e" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "ic-cdk" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8859bc2b863a77750acf199e1fb7e3fc403e1b475855ba13f59cb4e4036d238" +dependencies = [ + "candid", + "ic-cdk-macros 0.13.2", + "ic0 0.21.1", + "serde", + "serde_bytes", +] [[package]] name = "ic-cdk" @@ -926,8 +1122,8 @@ version = "0.14.0" dependencies = [ "anyhow", "candid", - "ic-cdk-macros", - "ic0", + "ic-cdk-macros 0.14.0", + "ic0 0.23.0", "rstest", "serde", "serde_bytes", @@ -954,14 +1150,28 @@ dependencies = [ "escargot", "futures", "hex", - "ic-cdk", + "ic-cdk 0.14.0", "ic-cdk-timers", - "ic-test-state-machine-client", "lazy_static", + "pocket-ic", "serde_bytes", "sha2", ] +[[package]] +name = "ic-cdk-macros" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a45800053d80a6df839a71aaea5797e723188c0b992618208ca3b941350c7355" +dependencies = [ + "candid", + "proc-macro2", + "quote", + "serde", + "serde_tokenstream 0.1.7", + "syn 1.0.109", +] + [[package]] name = "ic-cdk-macros" version = "0.14.0" @@ -970,7 +1180,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "serde_tokenstream", + "serde_tokenstream 0.2.0", "syn 2.0.61", ] @@ -979,8 +1189,8 @@ name = "ic-cdk-timers" version = "0.8.0" dependencies = [ "futures", - "ic-cdk", - "ic0", + "ic-cdk 0.14.0", + "ic0 0.23.0", "serde", "serde_bytes", "slotmap", @@ -993,7 +1203,7 @@ dependencies = [ "bincode", "candid", "hex", - "ic-cdk", + "ic-cdk 0.14.0", "serde", "serde_bytes", "serde_cbor", @@ -1007,23 +1217,17 @@ dependencies = [ "candid", "crc32fast", "hex", - "ic-cdk", + "ic-cdk 0.14.0", "serde", "serde_bytes", "sha2", ] [[package]] -name = "ic-test-state-machine-client" -version = "3.0.1" +name = "ic0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e05a81e0cbdf178228d72ace06c60ac7fa99927b49a238f9ccf5ef82eaced6" -dependencies = [ - "candid", - "ciborium", - "serde", - "serde_bytes", -] +checksum = "a54b5297861c651551676e8c43df805dad175cc33bc97dbd992edbbb85dcbcdf" [[package]] name = "ic0" @@ -1053,6 +1257,16 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" version = "2.2.6" @@ -1064,6 +1278,12 @@ dependencies = [ "serde", ] +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "is_terminal_polyfill" version = "1.70.0" @@ -1123,6 +1343,15 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lalrpop" version = "0.20.2" @@ -1151,7 +1380,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata", + "regex-automata 0.4.6", ] [[package]] @@ -1245,6 +1474,15 @@ dependencies = [ "libc", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.7.2" @@ -1269,12 +1507,48 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + [[package]] name = "new_debug_unreachable" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.5" @@ -1286,6 +1560,12 @@ dependencies = [ "serde", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.46" @@ -1304,6 +1584,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "object" version = "0.32.2" @@ -1322,6 +1612,18 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.2" @@ -1342,7 +1644,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.5", ] [[package]] @@ -1351,6 +1653,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "petgraph" version = "0.6.5" @@ -1376,6 +1684,26 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1395,7 +1723,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] -name = "precomputed-hash" +name = "pocket-ic" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9765eeff77b8750cf6258eaeea237b96607cd770aa3d4003f021924192b7e4e" +dependencies = [ + "async-trait", + "base64 0.13.1", + "candid", + "hex", + "ic-cdk 0.13.2", + "reqwest", + "schemars", + "serde", + "serde_bytes", + "serde_json", + "tracing", + "tracing-appender", + "tracing-subscriber", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "precomputed-hash" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" @@ -1499,10 +1854,19 @@ checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", - "regex-automata", + "regex-automata 0.4.6", "regex-syntax 0.8.3", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + [[package]] name = "regex-automata" version = "0.4.6" @@ -1526,6 +1890,68 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +[[package]] +name = "reqwest" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-native-certs", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-socks", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rstest" version = "0.12.0" @@ -1570,7 +1996,61 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustls-webpki" +version = "0.102.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] @@ -1594,12 +2074,68 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.61", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.23" @@ -1633,7 +2169,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ - "half 1.8.3", + "half", "serde", ] @@ -1648,6 +2184,17 @@ dependencies = [ "syn 2.0.61", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "serde_json" version = "1.0.117" @@ -1668,6 +2215,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_tokenstream" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "797ba1d80299b264f3aac68ab5d12e5825a561749db4df7cd7c8083900c5d4e9" +dependencies = [ + "proc-macro2", + "serde", + "syn 1.0.109", +] + [[package]] name = "serde_tokenstream" version = "0.2.0" @@ -1680,6 +2238,18 @@ dependencies = [ "syn 2.0.61", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha2" version = "0.10.8" @@ -1691,6 +2261,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -1727,6 +2306,22 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "sptr" version = "0.3.2" @@ -1771,6 +2366,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -1793,6 +2394,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "target-lexicon" version = "0.12.14" @@ -1839,6 +2446,47 @@ dependencies = [ "syn 2.0.61", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -1848,6 +2496,73 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-socks" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" +dependencies = [ + "either", + "futures-util", + "thiserror", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.8.12" @@ -1882,6 +2597,125 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror", + "time", + "tracing-subscriber", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "trybuild" version = "1.0.95" @@ -1908,12 +2742,27 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-segmentation" version = "1.11.0" @@ -1932,6 +2781,23 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "utf8parse" version = "0.2.1" @@ -1944,6 +2810,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" @@ -1960,12 +2832,87 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.61", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + [[package]] name = "wasm-encoder" version = "0.201.0" @@ -1984,6 +2931,19 @@ dependencies = [ "leb128", ] +[[package]] +name = "wasm-streams" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wasmparser" version = "0.201.0" @@ -2048,7 +3008,7 @@ dependencies = [ "wasmtime-slab", "wasmtime-winch", "wat", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2067,7 +3027,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4e660537b0ac2fc76917fb0cc9d403d2448b6983a84e59c51f7fea7b7dae024" dependencies = [ "anyhow", - "base64", + "base64 0.21.7", "bincode", "directories-next", "log", @@ -2076,7 +3036,7 @@ dependencies = [ "serde_derive", "sha2", "toml", - "windows-sys", + "windows-sys 0.52.0", "zstd", ] @@ -2180,7 +3140,7 @@ dependencies = [ "rustix", "wasmtime-asm-macros", "wasmtime-versioned-export-macros", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2203,7 +3163,7 @@ checksum = "c22ca2ef4d87b23d400660373453e274b2251bc2d674e3102497f690135e04b0" dependencies = [ "cfg-if", "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2233,7 +3193,7 @@ dependencies = [ "wasmtime-jit-debug", "wasmtime-versioned-export-macros", "wasmtime-wmemcheck", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2323,6 +3283,25 @@ dependencies = [ "wast", ] +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2345,7 +3324,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2370,13 +3349,37 @@ dependencies = [ "wasmtime-environ", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -2385,28 +3388,46 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.5" @@ -2419,24 +3440,48 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.5" @@ -2452,6 +3497,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "wit-parser" version = "0.201.0" @@ -2490,6 +3545,12 @@ dependencies = [ "syn 2.0.61", ] +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + [[package]] name = "zstd" version = "0.13.1" diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index a5fe20ec5..2466e94a2 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -10,7 +10,7 @@ publish = false [dependencies] candid.workspace = true -cargo_metadata = "0.14.2" +cargo_metadata = "0.18" escargot = { version = "0.5.7", features = ["print"] } ic-cdk.workspace = true ic-cdk-timers.workspace = true @@ -53,4 +53,4 @@ path = "canisters/chunk.rs" [dev-dependencies] hex.workspace = true -ic-test-state-machine-client = "3" +pocket-ic = "3" diff --git a/e2e-tests/canisters/canister_info.rs b/e2e-tests/canisters/canister_info.rs index 33a108b22..354d7fa1c 100644 --- a/e2e-tests/canisters/canister_info.rs +++ b/e2e-tests/canisters/canister_info.rs @@ -17,13 +17,10 @@ async fn info(canister_id: Principal) -> CanisterInfoResponse { #[ic_cdk::update] async fn canister_lifecycle() -> Principal { - let canister_id = create_canister( - CreateCanisterArgument { settings: None }, - 100_000_000_000 / 13, - ) - .await - .unwrap() - .0; + let canister_id = create_canister(CreateCanisterArgument { settings: None }, 1_000_000_000_000) + .await + .unwrap() + .0; install_code(InstallCodeArgument { mode: Install, arg: vec![], diff --git a/e2e-tests/canisters/chunk.rs b/e2e-tests/canisters/chunk.rs index ad46f7d3f..8eb977cdf 100644 --- a/e2e-tests/canisters/chunk.rs +++ b/e2e-tests/canisters/chunk.rs @@ -10,7 +10,7 @@ use ic_cdk::update; async fn call_create_canister() -> Principal { let arg = CreateCanisterArgument::default(); - create_canister(arg, 100_000_000_000u128) + create_canister(arg, 200_000_000_000u128) .await .unwrap() .0 diff --git a/e2e-tests/canisters/management_caller.rs b/e2e-tests/canisters/management_caller.rs index 07b9cb444..a5c1f53ca 100644 --- a/e2e-tests/canisters/management_caller.rs +++ b/e2e-tests/canisters/management_caller.rs @@ -12,7 +12,7 @@ mod main { settings: Some(CanisterSettings { controllers: Some(vec![ic_cdk::id()]), // There is no canister in the subnet, so we can set it to 100. - compute_allocation: Some(100u8.into()), + compute_allocation: Some(1u8.into()), // Though the upper limit is 256TiB, the actual subnet may have less memory resource (e.g. local replica). // Here we set it to 10KiB for testing. memory_allocation: Some(10000u16.into()), @@ -21,7 +21,7 @@ mod main { wasm_memory_limit: Some((2u64.pow(48) - 1).into()), }), }; - let canister_id = create_canister(arg, 100_000_000_000u128 / 13) + let canister_id = create_canister(arg, 200_000_000_000_000_000_000_000_000u128) .await .unwrap() .0 @@ -33,7 +33,7 @@ mod main { assert_eq!(response.reserved_cycles.0, 0u128.into()); let definite_canister_setting = response.settings; assert_eq!(definite_canister_setting.controllers, vec![ic_cdk::id()]); - assert_eq!(definite_canister_setting.compute_allocation, 100u8); + assert_eq!(definite_canister_setting.compute_allocation, 1u8); assert_eq!(definite_canister_setting.memory_allocation, 10000u16); assert_eq!(definite_canister_setting.freezing_threshold, u64::MAX); assert_eq!(definite_canister_setting.reserved_cycles_limit, u128::MAX); @@ -85,7 +85,7 @@ mod provisional { wasm_memory_limit: Some(10000u16.into()), }; let arg = ProvisionalCreateCanisterWithCyclesArgument { - amount: Some(1_000_000_000u64.into()), + amount: Some(10_000_000_000_000u64.into()), settings: Some(settings), }; let canister_id = provisional_create_canister_with_cycles(arg) diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 879d4598c..54a4f652c 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -1,6 +1,8 @@ use std::time::Duration; use std::time::SystemTime; +use candid::utils::ArgumentDecoder; +use candid::utils::ArgumentEncoder; use candid::{Encode, Principal}; use ic_cdk::api::management_canister::main::{ CanisterChange, CanisterChangeDetails, CanisterChangeOrigin, CanisterIdRecord, @@ -10,24 +12,27 @@ use ic_cdk::api::management_canister::main::{ FromUserRecord, InstallCodeArgument, }; use ic_cdk_e2e_tests::cargo_build_canister; -use ic_test_state_machine_client::{ - call_candid, call_candid_as, query_candid, CallError, ErrorCode, StateMachine, WasmResult, -}; +use pocket_ic::common::rest::RawEffectivePrincipal; +use pocket_ic::{call_candid_as, query_candid, CallError, ErrorCode, PocketIc, WasmResult}; + use serde_bytes::ByteBuf; use sha2::Digest; -pub static STATE_MACHINE_BINARY: &str = "../ic-test-state-machine"; - -pub fn env() -> StateMachine { - if !std::path::Path::new(STATE_MACHINE_BINARY).exists() { - eprintln!( - " -ERROR: Could not find state machine binary to run e2e tests. - Please run `bash scripts/download_state_machine_binary.sh`." - ); - } - - StateMachine::new(STATE_MACHINE_BINARY, false) +// 2T cycles +const INIT_CYCLES: u128 = 2_000_000_000_000; + +/// wrapper around `pocket_ic::call_candid` that uses None as the effective principal. +fn call_candid( + env: &PocketIc, + canister_id: Principal, + method: &str, + input: Input, +) -> Result +where + Input: ArgumentEncoder, + Output: for<'a> ArgumentDecoder<'a>, +{ + pocket_ic::call_candid(env, canister_id, RawEffectivePrincipal::None, method, input) } /// Checks that a canister that uses [`ic_cdk::storage::stable_store`] @@ -35,31 +40,33 @@ ERROR: Could not find state machine binary to run e2e tests. /// across upgrades. #[test] fn test_storage_roundtrip() { - let env = env(); + let pic = PocketIc::new(); let wasm = cargo_build_canister("simple-kv-store"); - let canister_id = env.create_canister(None); - env.install_canister(canister_id, wasm.clone(), vec![], None); + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, INIT_CYCLES); + pic.install_canister(canister_id, wasm.clone(), vec![], None); - let () = call_candid(&env, canister_id, "insert", (&"candid", &b"did")) + let () = call_candid(&pic, canister_id, "insert", (&"candid", &b"did")) .expect("failed to insert 'candid'"); - env.upgrade_canister(canister_id, wasm, vec![], None) + pic.upgrade_canister(canister_id, wasm, vec![], None) .expect("failed to upgrade the simple-kv-store canister"); let (result,): (Option,) = - query_candid(&env, canister_id, "lookup", (&"candid",)).expect("failed to lookup 'candid'"); + query_candid(&pic, canister_id, "lookup", (&"candid",)).expect("failed to lookup 'candid'"); assert_eq!(result, Some(ByteBuf::from(b"did".to_vec()))); } #[test] fn test_panic_after_async_frees_resources() { - let env = env(); + let pic: PocketIc = PocketIc::new(); let wasm = cargo_build_canister("async"); - let canister_id = env.create_canister(None); - env.install_canister(canister_id, wasm, vec![], None); + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, INIT_CYCLES); + pic.install_canister(canister_id, wasm, vec![], None); for i in 1..3 { - match call_candid(&env, canister_id, "panic_after_async", ()) { + match call_candid(&pic, canister_id, "panic_after_async", ()) { Ok(()) => (), Err(CallError::Reject(msg)) => panic!("unexpected reject: {}", msg), Err(CallError::UserError(e)) => { @@ -76,36 +83,37 @@ fn test_panic_after_async_frees_resources() { } } - let (n,): (u64,) = call_candid(&env, canister_id, "invocation_count", ()) + let (n,): (u64,) = call_candid(&pic, canister_id, "invocation_count", ()) .expect("failed to call invocation_count"); assert_eq!(i, n, "expected the invocation count to be {}, got {}", i, n); } let (message,): (String,) = - call_candid(&env, canister_id, "invalid_reply_payload_does_not_trap", ()) + call_candid(&pic, canister_id, "invalid_reply_payload_does_not_trap", ()) .expect("call failed"); assert_eq!(&message, "handled decoding error gracefully with code 5"); let err = - call_candid::<_, ()>(&env, canister_id, "panic_twice", ()).expect_err("failed to panic"); + call_candid::<_, ()>(&pic, canister_id, "panic_twice", ()).expect_err("failed to panic"); assert!( matches!(err, CallError::UserError(u) if u.description.contains("Call already trapped")) ); - let _: (u64,) = call_candid(&env, canister_id, "notifications_received", ()) + let _: (u64,) = call_candid(&pic, canister_id, "notifications_received", ()) .expect("failed to call unrelated function afterwards"); let _: (u64,) = - call_candid(&env, canister_id, "invocation_count", ()).expect("failed to recover lock"); + call_candid(&pic, canister_id, "invocation_count", ()).expect("failed to recover lock"); } #[test] fn test_raw_api() { - let env = env(); + let pic = PocketIc::new(); let wasm = cargo_build_canister("reverse"); - let canister_id = env.create_canister(None); - env.install_canister(canister_id, wasm, vec![], None); + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, INIT_CYCLES); + pic.install_canister(canister_id, wasm, vec![], None); - let result = env + let result = pic .query_call( canister_id, Principal::anonymous(), @@ -115,7 +123,7 @@ fn test_raw_api() { .unwrap(); assert_eq!(result, WasmResult::Reply(vec![4, 3, 2, 1])); - let result = env + let result = pic .update_call( canister_id, Principal::anonymous(), @@ -128,21 +136,23 @@ fn test_raw_api() { #[test] fn test_notify_calls() { - let env = env(); + let pic = PocketIc::new(); let wasm = cargo_build_canister("async"); - let sender_id = env.create_canister(None); - env.install_canister(sender_id, wasm.clone(), vec![], None); - let receiver_id = env.create_canister(None); - env.install_canister(receiver_id, wasm, vec![], None); - - let (n,): (u64,) = query_candid(&env, receiver_id, "notifications_received", ()) + let sender_id = pic.create_canister(); + pic.add_cycles(sender_id, INIT_CYCLES); + pic.install_canister(sender_id, wasm.clone(), vec![], None); + let receiver_id = pic.create_canister(); + pic.add_cycles(receiver_id, INIT_CYCLES); + pic.install_canister(receiver_id, wasm, vec![], None); + + let (n,): (u64,) = query_candid(&pic, receiver_id, "notifications_received", ()) .expect("failed to query 'notifications_received'"); assert_eq!(n, 0); - let () = call_candid(&env, sender_id, "notify", (receiver_id, "on_notify")) + let () = call_candid(&pic, sender_id, "notify", (receiver_id, "on_notify")) .expect("failed to call 'notify'"); - let (n,): (u64,) = query_candid(&env, receiver_id, "notifications_received", ()) + let (n,): (u64,) = query_candid(&pic, receiver_id, "notifications_received", ()) .expect("failed to query 'notifications_received'"); assert_eq!(n, 1); } @@ -151,29 +161,32 @@ fn test_notify_calls() { #[test] #[ignore] fn test_composite_query() { - let env = env(); + let pic = PocketIc::new(); let wasm = cargo_build_canister("async"); - let sender_id = env.create_canister(None); - env.install_canister(sender_id, wasm.clone(), vec![], None); - let receiver_id = env.create_canister(None); - env.install_canister(receiver_id, wasm, vec![], None); - - let (greeting,): (String,) = query_candid(&env, sender_id, "greet_self", (receiver_id,)) + let sender_id = pic.create_canister(); + pic.add_cycles(sender_id, INIT_CYCLES); + pic.install_canister(sender_id, wasm.clone(), vec![], None); + let receiver_id = pic.create_canister(); + pic.add_cycles(receiver_id, INIT_CYCLES); + pic.install_canister(receiver_id, wasm, vec![], None); + + let (greeting,): (String,) = query_candid(&pic, sender_id, "greet_self", (receiver_id,)) .expect("failed to query 'greet_self'"); assert_eq!(greeting, "Hello, myself"); } #[test] fn test_api_call() { - let env = env(); + let pic = PocketIc::new(); let wasm = cargo_build_canister("api-call"); - let canister_id = env.create_canister(None); - env.install_canister(canister_id, wasm, vec![], None); - let (result,): (u64,) = query_candid(&env, canister_id, "instruction_counter", ()) + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, INIT_CYCLES); + pic.install_canister(canister_id, wasm, vec![], None); + let (result,): (u64,) = query_candid(&pic, canister_id, "instruction_counter", ()) .expect("failed to query instruction_counter"); assert!(result > 0); - let result = env + let result = pic .query_call( canister_id, Principal::anonymous(), @@ -183,40 +196,41 @@ fn test_api_call() { .unwrap(); assert_eq!(result, WasmResult::Reject("manual reject".to_string())); - let (result,): (bool,) = call_candid(&env, canister_id, "update_is_replicated", ()) + let (result,): (bool,) = call_candid(&pic, canister_id, "update_is_replicated", ()) .expect("Failed to call update_is_replicated"); assert!(result); - let (result,): (bool,) = query_candid(&env, canister_id, "query_is_not_replicated", ()) + let (result,): (bool,) = query_candid(&pic, canister_id, "query_is_not_replicated", ()) .expect("Failed to call query_is_not_replicated"); assert!(!result); } #[test] fn test_timers() { - let env = env(); + let pic = PocketIc::new(); let wasm = cargo_build_canister("timers"); - let canister_id = env.create_canister(None); - env.install_canister(canister_id, wasm, vec![], None); + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, INIT_CYCLES); + pic.install_canister(canister_id, wasm, vec![], None); - call_candid::<(), ()>(&env, canister_id, "schedule", ()).expect("Failed to call schedule"); - advance_seconds(&env, 5); + call_candid::<(), ()>(&pic, canister_id, "schedule", ()).expect("Failed to call schedule"); + advance_seconds(&pic, 5); - call_candid::<_, ()>(&env, canister_id, "schedule_long", ()) + call_candid::<_, ()>(&pic, canister_id, "schedule_long", ()) .expect("Failed to call schedule_long"); - advance_seconds(&env, 5); - call_candid::<_, ()>(&env, canister_id, "cancel_long", ()).expect("Failed to call cancel_long"); - advance_seconds(&env, 5); + advance_seconds(&pic, 5); + call_candid::<_, ()>(&pic, canister_id, "cancel_long", ()).expect("Failed to call cancel_long"); + advance_seconds(&pic, 5); - call_candid::<_, ()>(&env, canister_id, "start_repeating", ()) + call_candid::<_, ()>(&pic, canister_id, "start_repeating", ()) .expect("Failed to call start_repeating"); - advance_seconds(&env, 3); - call_candid::<_, ()>(&env, canister_id, "stop_repeating", ()) + advance_seconds(&pic, 3); + call_candid::<_, ()>(&pic, canister_id, "stop_repeating", ()) .expect("Failed to call stop_repeating"); - advance_seconds(&env, 2); + advance_seconds(&pic, 2); let (events,): (Vec,) = - query_candid(&env, canister_id, "get_events", ()).expect("Failed to call get_events"); + query_candid(&pic, canister_id, "get_events", ()).expect("Failed to call get_events"); assert_eq!( events[..], ["1", "2", "3", "4", "repeat", "repeat", "repeat"] @@ -225,20 +239,21 @@ fn test_timers() { #[test] fn test_timers_can_cancel_themselves() { - let env = env(); + let pic = PocketIc::new(); let wasm = cargo_build_canister("timers"); - let canister_id = env.create_canister(None); - env.install_canister(canister_id, wasm, vec![], None); + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, INIT_CYCLES); + pic.install_canister(canister_id, wasm, vec![], None); - call_candid::<_, ()>(&env, canister_id, "set_self_cancelling_timer", ()) + call_candid::<_, ()>(&pic, canister_id, "set_self_cancelling_timer", ()) .expect("Failed to call set_self_cancelling_timer"); - call_candid::<_, ()>(&env, canister_id, "set_self_cancelling_periodic_timer", ()) + call_candid::<_, ()>(&pic, canister_id, "set_self_cancelling_periodic_timer", ()) .expect("Failed to call set_self_cancelling_periodic_timer"); - advance_seconds(&env, 1); + advance_seconds(&pic, 1); let (events,): (Vec,) = - query_candid(&env, canister_id, "get_events", ()).expect("Failed to call get_events"); + query_candid(&pic, canister_id, "get_events", ()).expect("Failed to call get_events"); assert_eq!( events, ["timer cancelled self", "periodic timer cancelled self"] @@ -249,82 +264,88 @@ fn test_timers_can_cancel_themselves() { fn test_scheduling_many_timers() { // Must be more than the queue limit (500) let timers_to_schedule = 1_000; - let env = env(); + let pic = PocketIc::new(); let wasm = cargo_build_canister("timers"); - let canister_id = env.create_canister(None); - env.install_canister(canister_id, wasm, vec![], None); + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, 100_000_000_000_000u128); + pic.install_canister(canister_id, wasm, vec![], None); let () = call_candid( - &env, + &pic, canister_id, "schedule_n_timers", (timers_to_schedule,), ) .expect("Error calling schedule_n_timers"); - // Up to 500 timers will be executed per round - advance_seconds(&env, timers_to_schedule / 500); + // Up to 20 timers will be executed per round + // Be conservative that advance 2 times the minimum number of rounds + const TIMERS_PER_ROUND: u32 = 20; + advance_seconds(&pic, 2 * timers_to_schedule / TIMERS_PER_ROUND); - let (executed_timers,): (u32,) = query_candid(&env, canister_id, "executed_timers", ()) + let (executed_timers,): (u32,) = query_candid(&pic, canister_id, "executed_timers", ()) .expect("Error querying executed_timers"); assert_eq!(timers_to_schedule, executed_timers); } -fn advance_seconds(env: &StateMachine, seconds: u32) { +fn advance_seconds(pic: &PocketIc, seconds: u32) { for _ in 0..seconds { - env.advance_time(Duration::from_secs(1)); - env.tick(); + pic.advance_time(Duration::from_secs(1)); + pic.tick(); } } #[test] fn test_set_global_timers() { - // Must be more than the queue limit (500) - let env = env(); - let system_time = std::time::SystemTime::now(); - - env.set_time(system_time); + let pic = PocketIc::new(); let wasm = cargo_build_canister("timers"); - let canister_id = env.create_canister(None); - env.install_canister(canister_id, wasm, vec![], None); + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, INIT_CYCLES); + pic.install_canister(canister_id, wasm, vec![], None); - call_candid::<_, ()>(&env, canister_id, "schedule_long", ()) - .expect("Failed to call schedule_long"); - let ts0 = system_time - .duration_since(std::time::UNIX_EPOCH) + // Set a 9s timer at t0, it expires at t1 = t0 + 9s + let t0 = pic + .get_time() + .duration_since(SystemTime::UNIX_EPOCH) .unwrap() - .as_nanos() as u64 - + 9_000_000_000; // the long event is scheduled 9 seconds from ts0 - advance_seconds(&env, 5); + .as_nanos() as u64; + let t1 = t0 + 9_000_000_000; + call_candid::<_, ()>(&pic, canister_id, "schedule_long", ()) + .expect("Failed to call schedule_long"); + + // 5 seconds later, the 9s timer is still active + advance_seconds(&pic, 5); - // set the timer to 5 seconds from ts0 - let ts1 = ts0 + 5_000_000_000; - let (previous,) = call_candid::<(u64,), (u64,)>(&env, canister_id, "set_global_timer", (ts1,)) + // Set the expiration time of the timer to t2 = t1 + 5s + let t2 = t1 + 5_000_000_000; + let (previous,) = call_candid::<(u64,), (u64,)>(&pic, canister_id, "set_global_timer", (t2,)) .expect("Failed to call set_global_timer"); - assert_eq!(previous, ts0); + assert!(previous.abs_diff(t1) < 2); // time error no more than 1 nanosecond - // deactivate the timer - let (previous,) = call_candid::<(u64,), (u64,)>(&env, canister_id, "set_global_timer", (0,)) + // Deactivate the timer + let (previous,) = call_candid::<(u64,), (u64,)>(&pic, canister_id, "set_global_timer", (0,)) .expect("Failed to call set_global_timer"); - assert_eq!(previous, ts1); + assert!(previous.abs_diff(t2) < 2); // time error no more than 1 nanosecond } #[test] fn test_canister_info() { - let env = env(); + let pic = PocketIc::new(); let wasm = cargo_build_canister("canister_info"); - let canister_id = env.create_canister(None); - env.add_cycles(canister_id, 1_000_000_000_000); - env.install_canister(canister_id, wasm, vec![], None); + pic.set_time(SystemTime::UNIX_EPOCH); + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, INIT_CYCLES); + pic.install_canister(canister_id, wasm, vec![], None); - let new_canister: (Principal,) = call_candid(&env, canister_id, "canister_lifecycle", ()) + let new_canister: (Principal,) = call_candid(&pic, canister_id, "canister_lifecycle", ()) .expect("Error calling canister_lifecycle"); let () = call_candid_as( - &env, + &pic, Principal::management_canister(), + RawEffectivePrincipal::None, Principal::anonymous(), "uninstall_code", (CanisterIdRecord { @@ -333,8 +354,9 @@ fn test_canister_info() { ) .expect("Error calling uninstall_code"); let () = call_candid_as( - &env, + &pic, Principal::management_canister(), + RawEffectivePrincipal::None, Principal::anonymous(), "install_code", (InstallCodeArgument { @@ -346,21 +368,16 @@ fn test_canister_info() { ) .expect("Error calling install_code"); - let info: (CanisterInfoResponse,) = call_candid(&env, canister_id, "info", (new_canister.0,)) + let info: (CanisterInfoResponse,) = call_candid(&pic, canister_id, "info", (new_canister.0,)) .expect("Error calling canister_info"); - let timestamp_nanos = env - .time() - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap() - .as_nanos() as u64; assert_eq!( info.0, CanisterInfoResponse { total_num_changes: 9, recent_changes: vec![ CanisterChange { - timestamp_nanos, + timestamp_nanos: 4, canister_version: 0, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -371,7 +388,7 @@ fn test_canister_info() { }), }, CanisterChange { - timestamp_nanos, + timestamp_nanos: 6, canister_version: 1, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -386,7 +403,7 @@ fn test_canister_info() { }), }, CanisterChange { - timestamp_nanos, + timestamp_nanos: 8, canister_version: 2, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -395,7 +412,7 @@ fn test_canister_info() { details: CanisterChangeDetails::CodeUninstall, }, CanisterChange { - timestamp_nanos, + timestamp_nanos: 10, canister_version: 3, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -410,7 +427,7 @@ fn test_canister_info() { }), }, CanisterChange { - timestamp_nanos, + timestamp_nanos: 12, canister_version: 4, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -425,7 +442,7 @@ fn test_canister_info() { }), }, CanisterChange { - timestamp_nanos, + timestamp_nanos: 14, canister_version: 5, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -440,7 +457,7 @@ fn test_canister_info() { }), }, CanisterChange { - timestamp_nanos, + timestamp_nanos: 16, canister_version: 6, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -451,7 +468,7 @@ fn test_canister_info() { }), }, CanisterChange { - timestamp_nanos, + timestamp_nanos: 18, canister_version: 7, origin: CanisterChangeOrigin::FromUser(FromUserRecord { user_id: Principal::anonymous(), @@ -459,7 +476,7 @@ fn test_canister_info() { details: CanisterChangeDetails::CodeUninstall, }, CanisterChange { - timestamp_nanos, + timestamp_nanos: 19, canister_version: 8, origin: CanisterChangeOrigin::FromUser(FromUserRecord { user_id: Principal::anonymous(), @@ -484,59 +501,57 @@ fn test_canister_info() { #[test] fn test_cycles_burn() { - let env = env(); + let pic = PocketIc::new(); let wasm = cargo_build_canister("api-call"); - let canister_id = env.create_canister(None); - env.add_cycles(canister_id, 1500); + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, INIT_CYCLES); - env.install_canister(canister_id, wasm, vec![], None); + pic.install_canister(canister_id, wasm, vec![], None); eprintln!("Canister installed."); - let balance1 = env.cycle_balance(canister_id); + let balance1 = pic.cycle_balance(canister_id); eprintln!("Balance 1: {balance1}"); - let attempted = 1000u128; - // Scenario 1: burn less than balance - let (burned,): (u128,) = call_candid(&env, canister_id, "cycles_burn", (attempted,)) + let attempted1 = 1000u128; + let (burned,): (u128,) = call_candid(&pic, canister_id, "cycles_burn", (attempted1,)) .expect("Error calling cycles_burn"); - eprintln!("Attempted to burn {attempted}, actually burned {burned}"); - assert_eq!(burned, attempted); - let balance2 = env.cycle_balance(canister_id); + eprintln!("Attempted to burn {attempted1}, actually burned {burned}"); + assert_eq!(burned, attempted1); + let balance2 = pic.cycle_balance(canister_id); eprintln!("Balance 2: {balance2}"); // Scenario 2: burn more than balance - let (burned,): (u128,) = call_candid(&env, canister_id, "cycles_burn", (attempted,)) + let attempted2 = balance2 + 1; + let (burned,): (u128,) = call_candid(&pic, canister_id, "cycles_burn", (attempted2,)) .expect("Error calling cycles_burn"); - eprintln!("Attempted to burn {attempted}, actually burned {burned}"); - assert!(burned < attempted); - assert_eq!(burned, balance2); - let balance3 = env.cycle_balance(canister_id); + eprintln!("Attempted to burn {attempted2}, actually burned {burned}"); + assert!(burned < balance2); // restrained by reserved_balance and freezing_limit + let balance3 = pic.cycle_balance(canister_id); eprintln!("Balance 3: {balance3}"); - assert_eq!(balance3, 0); } #[test] -fn call_management() { - let env = env(); +fn test_call_management() { + let pic = PocketIc::new(); let wasm = cargo_build_canister("management_caller"); - let canister_id = env.create_canister(None); - env.add_cycles(canister_id, 100_000_000_000_000); - env.install_canister(canister_id, wasm, vec![], None); - let () = call_candid(&env, canister_id, "execute_main_methods", ()) + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, 300_000_000_000_000_000_000_000_000u128); + pic.install_canister(canister_id, wasm, vec![], None); + let () = call_candid(&pic, canister_id, "execute_main_methods", ()) .expect("Error calling execute_main_methods"); - let () = call_candid(&env, canister_id, "execute_provisional_methods", ()) + let () = call_candid(&pic, canister_id, "execute_provisional_methods", ()) .expect("Error calling execute_provisional_methods"); } #[test] fn test_chunk() { - let env = env(); + let pic = PocketIc::new(); let wasm = cargo_build_canister("chunk"); - let canister_id = env.create_canister(None); - env.add_cycles(canister_id, 100_000_000_000_000); - env.install_canister(canister_id, wasm, vec![], None); + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, 100_000_000_000_000); + pic.install_canister(canister_id, wasm, vec![], None); let (target_canister_id,): (Principal,) = - call_candid(&env, canister_id, "call_create_canister", ()) + call_candid(&pic, canister_id, "call_create_canister", ()) .expect("Error calling call_create_canister"); let wasm_module = b"\x00asm\x01\x00\x00\x00".to_vec(); @@ -547,7 +562,7 @@ fn test_chunk() { let hash2_expected = sha2::Sha256::digest(&chunk2).to_vec(); let (hash1_return,): (Vec,) = call_candid( - &env, + &pic, canister_id, "call_upload_chunk", (target_canister_id, chunk1.clone()), @@ -556,7 +571,7 @@ fn test_chunk() { assert_eq!(&hash1_return, &hash1_expected); let () = call_candid( - &env, + &pic, canister_id, "call_clear_chunk_store", (target_canister_id,), @@ -564,14 +579,14 @@ fn test_chunk() { .expect("Error calling call_clear_chunk_store"); let (_hash1_return,): (Vec,) = call_candid( - &env, + &pic, canister_id, "call_upload_chunk", (target_canister_id, chunk1), ) .expect("Error calling call_upload_chunk"); let (_hash2_return,): (Vec,) = call_candid( - &env, + &pic, canister_id, "call_upload_chunk", (target_canister_id, chunk2), @@ -579,7 +594,7 @@ fn test_chunk() { .expect("Error calling call_upload_chunk"); let (hashes,): (Vec>,) = call_candid( - &env, + &pic, canister_id, "call_stored_chunks", (target_canister_id,), @@ -591,7 +606,7 @@ fn test_chunk() { assert!(hashes.contains(&hash2_expected)); let () = call_candid( - &env, + &pic, canister_id, "call_install_chunked_code", ( diff --git a/scripts/download_pocket_ic.sh b/scripts/download_pocket_ic.sh new file mode 100755 index 000000000..545dd8306 --- /dev/null +++ b/scripts/download_pocket_ic.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Make sure we always run from the root +SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "$SCRIPTS_DIR/../e2e-tests" + +uname_sys=$(uname -s | tr '[:upper:]' '[:lower:]') +echo "uname_sys: $uname_sys" + +tag="release-2024-05-22_23-01-base" + +curl -sL "https://github.com/dfinity/ic/releases/download/$tag/pocket-ic-x86_64-$uname_sys.gz" --output pocket-ic.gz +gzip -df pocket-ic.gz +chmod a+x pocket-ic +./pocket-ic --version + +if [[ "$uname_sys" == "darwin" ]]; then + xattr -dr com.apple.quarantine pocket-ic +fi diff --git a/scripts/download_state_machine_binary.sh b/scripts/download_state_machine_binary.sh deleted file mode 100755 index 1f75ff622..000000000 --- a/scripts/download_state_machine_binary.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -# Make sure we always run from the root -SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd "$SCRIPTS_DIR/.." - -uname_sys=$(uname -s | tr '[:upper:]' '[:lower:]') -echo "uname_sys: $uname_sys" -# Check https://gitlab.com/dfinity-lab/public/ic/-/commits/master -# Find the most recent commit with a green check mark (the artifacts were built successfully) -commit_sha="ba6d8b136549f0acf8a2eafddab031156d53accd" - -curl -sLO "https://download.dfinity.systems/ic/$commit_sha/binaries/x86_64-$uname_sys/ic-test-state-machine.gz" -gzip -d ic-test-state-machine.gz -chmod a+x ic-test-state-machine -./ic-test-state-machine --version From 8857ee400c271654ec6e8a0a5a94c1e4a94943c9 Mon Sep 17 00:00:00 2001 From: Severin Siffert Date: Thu, 27 Jun 2024 22:50:54 +0200 Subject: [PATCH 214/234] feat: support log_visibility canister setting (#497) --- e2e-tests/canisters/canister_info.rs | 1 + e2e-tests/canisters/management_caller.rs | 7 +++++++ src/ic-cdk-bindgen/CHANGELOG.md | 2 ++ .../src/api/management_canister/main/types.rs | 20 +++++++++++++++++++ 4 files changed, 30 insertions(+) diff --git a/e2e-tests/canisters/canister_info.rs b/e2e-tests/canisters/canister_info.rs index 354d7fa1c..9a4bc2078 100644 --- a/e2e-tests/canisters/canister_info.rs +++ b/e2e-tests/canisters/canister_info.rs @@ -69,6 +69,7 @@ async fn canister_lifecycle() -> Principal { memory_allocation: None, freezing_threshold: None, reserved_cycles_limit: None, + log_visibility: None, wasm_memory_limit: None, }, canister_id: canister_id.canister_id, diff --git a/e2e-tests/canisters/management_caller.rs b/e2e-tests/canisters/management_caller.rs index a5c1f53ca..db662d6b4 100644 --- a/e2e-tests/canisters/management_caller.rs +++ b/e2e-tests/canisters/management_caller.rs @@ -18,6 +18,7 @@ mod main { memory_allocation: Some(10000u16.into()), freezing_threshold: Some(u64::MAX.into()), reserved_cycles_limit: Some(u128::MAX.into()), + log_visibility: Some(LogVisibility::Public), wasm_memory_limit: Some((2u64.pow(48) - 1).into()), }), }; @@ -37,6 +38,10 @@ mod main { assert_eq!(definite_canister_setting.memory_allocation, 10000u16); assert_eq!(definite_canister_setting.freezing_threshold, u64::MAX); assert_eq!(definite_canister_setting.reserved_cycles_limit, u128::MAX); + assert_eq!( + definite_canister_setting.log_visibility, + LogVisibility::Public + ); assert_eq!( definite_canister_setting.wasm_memory_limit, 2u64.pow(48) - 1 @@ -72,6 +77,7 @@ mod main { mod provisional { use super::*; + use api::management_canister::main::LogVisibility; use ic_cdk::api::management_canister::provisional::*; #[update] @@ -82,6 +88,7 @@ mod provisional { memory_allocation: Some(10000u16.into()), freezing_threshold: Some(10000u16.into()), reserved_cycles_limit: Some(10000u16.into()), + log_visibility: Some(LogVisibility::Public), wasm_memory_limit: Some(10000u16.into()), }; let arg = ProvisionalCreateCanisterWithCyclesArgument { diff --git a/src/ic-cdk-bindgen/CHANGELOG.md b/src/ic-cdk-bindgen/CHANGELOG.md index 6c1c2941a..6135674ed 100644 --- a/src/ic-cdk-bindgen/CHANGELOG.md +++ b/src/ic-cdk-bindgen/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +- Support canister setting `log_visibility`. + ### Changed - Refactor!: move Rust code generation logic from candid_parser. (#480) diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index ac185fa01..97c284fd3 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -4,6 +4,20 @@ use serde::{Deserialize, Serialize}; /// Canister ID is Principal. pub type CanisterId = Principal; +/// todo +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub enum LogVisibility { + #[default] + #[serde(rename = "controllers")] + /// Only controllers of the canister can access the logs. + Controllers, + #[serde(rename = "public")] + /// Everyone is allowed to access the canister's logs. + Public, +} + /// Canister settings. /// /// The settings are optional. If they are not explicitly set, the default values will be applied automatically. @@ -52,6 +66,10 @@ pub struct CanisterSettings { /// /// Default value: 5_000_000_000_000 (5 trillion cycles). pub reserved_cycles_limit: Option, + /// Defines who is allowed to read the canister's logs. + /// + /// Default value: Controllers + pub log_visibility: Option, /// Must be a number between 0 and 248-1 (i.e 256TB), inclusively. /// /// It indicates the upper limit on the WASM heap memory consumption of the canister. @@ -317,6 +335,8 @@ pub struct DefiniteCanisterSettings { pub freezing_threshold: Nat, /// Reserved cycles limit. pub reserved_cycles_limit: Nat, + /// Visibility of canister logs. + pub log_visibility: LogVisibility, /// The Wasm memory limit. pub wasm_memory_limit: Nat, } From 1a1cb07309b7d19b7cd0fa6cc0e7d423ff04d684 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 1 Jul 2024 12:44:32 -0400 Subject: [PATCH 215/234] feat!: Stable Memory always use 64-bit addresses and `stable64_*` system API. (#498) * feat!: only use stable64 API * changelog * clippy --- src/ic-cdk/CHANGELOG.md | 4 + src/ic-cdk/src/api/stable/canister.rs | 37 +--- src/ic-cdk/src/api/stable/mod.rs | 301 ++++++++++++-------------- src/ic-cdk/src/api/stable/private.rs | 52 ----- src/ic-cdk/src/api/stable/tests.rs | 74 +++---- 5 files changed, 170 insertions(+), 298 deletions(-) delete mode 100644 src/ic-cdk/src/api/stable/private.rs diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index e4fc05c7f..ab4bda0b7 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Changed + +- BREAKING: Stable Memory always use 64-bit addresses and `stable64_*` system API. + ## [0.14.0] - 2024-05-17 ## [0.13.3] - 2024-05-10 (yanked) diff --git a/src/ic-cdk/src/api/stable/canister.rs b/src/ic-cdk/src/api/stable/canister.rs index 12186bf4c..248b1980c 100644 --- a/src/ic-cdk/src/api/stable/canister.rs +++ b/src/ic-cdk/src/api/stable/canister.rs @@ -7,27 +7,12 @@ use super::*; pub struct CanisterStableMemory {} impl StableMemory for CanisterStableMemory { - fn stable_size(&self) -> u32 { - // SAFETY: ic0.stable_size is always safe to call. - unsafe { ic0::stable_size() as u32 } - } - - fn stable64_size(&self) -> u64 { + fn stable_size(&self) -> u64 { // SAFETY: ic0.stable64_size is always safe to call. unsafe { ic0::stable64_size() as u64 } } - fn stable_grow(&self, new_pages: u32) -> Result { - // SAFETY: ic0.stable_grow is always safe to call. - unsafe { - match ic0::stable_grow(new_pages as i32) { - -1 => Err(StableMemoryError::OutOfMemory), - x => Ok(x as u32), - } - } - } - - fn stable64_grow(&self, new_pages: u64) -> Result { + fn stable_grow(&self, new_pages: u64) -> Result { // SAFETY: ic0.stable64_grow is always safe to call. unsafe { match ic0::stable64_grow(new_pages as i64) { @@ -37,28 +22,14 @@ impl StableMemory for CanisterStableMemory { } } - fn stable_write(&self, offset: u32, buf: &[u8]) { - // SAFETY: `buf`, being &[u8], is a readable sequence of bytes, and therefore valid to pass to ic0.stable_write. - unsafe { - ic0::stable_write(offset as i32, buf.as_ptr() as i32, buf.len() as i32); - } - } - - fn stable64_write(&self, offset: u64, buf: &[u8]) { + fn stable_write(&self, offset: u64, buf: &[u8]) { // SAFETY: `buf`, being &[u8], is a readable sequence of bytes, and therefore valid to pass to ic0.stable64_write. unsafe { ic0::stable64_write(offset as i64, buf.as_ptr() as i64, buf.len() as i64); } } - fn stable_read(&self, offset: u32, buf: &mut [u8]) { - // SAFETY: `buf`, being &mut [u8], is a writable sequence of bytes, and therefore valid to pass to ic0.stable_read. - unsafe { - ic0::stable_read(buf.as_ptr() as i32, offset as i32, buf.len() as i32); - } - } - - fn stable64_read(&self, offset: u64, buf: &mut [u8]) { + fn stable_read(&self, offset: u64, buf: &mut [u8]) { // SAFETY: `buf`, being &mut [u8], is a writable sequence of bytes, and therefore valid to pass to ic0.stable64_read. unsafe { ic0::stable64_read(buf.as_ptr() as i64, offset as i64, buf.len() as i64); diff --git a/src/ic-cdk/src/api/stable/mod.rs b/src/ic-cdk/src/api/stable/mod.rs index 46fe2e253..47ead7ccf 100644 --- a/src/ic-cdk/src/api/stable/mod.rs +++ b/src/ic-cdk/src/api/stable/mod.rs @@ -3,7 +3,6 @@ //! You can check the [Internet Computer Specification](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-stable-memory) //! for a in-depth explanation of stable memory. mod canister; -mod private; #[cfg(test)] mod tests; @@ -11,17 +10,14 @@ pub use canister::CanisterStableMemory; use std::{error, fmt, io}; /// WASM page size in bytes. -pub const WASM_PAGE_SIZE_IN_BYTES: usize = 64 * 1024; // 64KB +pub const WASM_PAGE_SIZE_IN_BYTES: u64 = 64 * 1024; // 64KB static CANISTER_STABLE_MEMORY: CanisterStableMemory = CanisterStableMemory {}; /// A trait defining the stable memory API which each canister running on the IC can make use of pub trait StableMemory { /// Gets current size of the stable memory (in WASM pages). - fn stable_size(&self) -> u32; - - /// Similar to `stable_size` but with support for 64-bit addressed memory. - fn stable64_size(&self) -> u64; + fn stable_size(&self) -> u64; /// Attempts to grow the stable memory by `new_pages` (added pages). /// @@ -29,37 +25,23 @@ pub trait StableMemory { /// size that was reserved. /// /// *Note*: Pages are 64KiB in WASM. - fn stable_grow(&self, new_pages: u32) -> Result; - - /// Similar to `stable_grow` but with support for 64-bit addressed memory. - fn stable64_grow(&self, new_pages: u64) -> Result; + fn stable_grow(&self, new_pages: u64) -> Result; /// Writes data to the stable memory location specified by an offset. /// /// Warning - this will panic if `offset + buf.len()` exceeds the current size of stable memory. /// Use `stable_grow` to request more stable memory if needed. - fn stable_write(&self, offset: u32, buf: &[u8]); - - /// Similar to `stable_write` but with support for 64-bit addressed memory. - fn stable64_write(&self, offset: u64, buf: &[u8]); + fn stable_write(&self, offset: u64, buf: &[u8]); /// Reads data from the stable memory location specified by an offset. - fn stable_read(&self, offset: u32, buf: &mut [u8]); - - /// Similar to `stable_read` but with support for 64-bit addressed memory. - fn stable64_read(&self, offset: u64, buf: &mut [u8]); + fn stable_read(&self, offset: u64, buf: &mut [u8]); } /// Gets current size of the stable memory (in WASM pages). -pub fn stable_size() -> u32 { +pub fn stable_size() -> u64 { CANISTER_STABLE_MEMORY.stable_size() } -/// Similar to `stable_size` but with support for 64-bit addressed memory. -pub fn stable64_size() -> u64 { - CANISTER_STABLE_MEMORY.stable64_size() -} - /// A possible error value when dealing with stable memory. #[derive(Debug)] pub enum StableMemoryError { @@ -86,49 +68,40 @@ impl error::Error for StableMemoryError {} /// size that was reserved. /// /// *Note*: Pages are 64KiB in WASM. -pub fn stable_grow(new_pages: u32) -> Result { +pub fn stable_grow(new_pages: u64) -> Result { CANISTER_STABLE_MEMORY.stable_grow(new_pages) } -/// Similar to `stable_grow` but with support for 64-bit addressed memory. -pub fn stable64_grow(new_pages: u64) -> Result { - CANISTER_STABLE_MEMORY.stable64_grow(new_pages) -} - /// Writes data to the stable memory location specified by an offset. /// /// Warning - this will panic if `offset + buf.len()` exceeds the current size of stable memory. /// Use `stable_grow` to request more stable memory if needed. -pub fn stable_write(offset: u32, buf: &[u8]) { +pub fn stable_write(offset: u64, buf: &[u8]) { CANISTER_STABLE_MEMORY.stable_write(offset, buf) } -/// Similar to `stable_write` but with support for 64-bit addressed memory. -pub fn stable64_write(offset: u64, buf: &[u8]) { - CANISTER_STABLE_MEMORY.stable64_write(offset, buf) -} - /// Reads data from the stable memory location specified by an offset. -pub fn stable_read(offset: u32, buf: &mut [u8]) { +pub fn stable_read(offset: u64, buf: &mut [u8]) { CANISTER_STABLE_MEMORY.stable_read(offset, buf) } -/// Similar to `stable_read` but with support for 64-bit addressed memory. -pub fn stable64_read(offset: u64, buf: &mut [u8]) { - CANISTER_STABLE_MEMORY.stable64_read(offset, buf) -} - /// Returns a copy of the stable memory. /// /// This will map the whole memory (even if not all of it has been written to). +/// +/// # Panics +/// +/// When the bytes of the stable memory cannot fit into a `Vec` which constrained by the usize. pub fn stable_bytes() -> Vec { - let size = (stable_size() as usize) << 16; + let size = (stable_size() << 16) + .try_into() + .expect("overflow: stable memory too large to read in one go"); let mut vec = Vec::with_capacity(size); // SAFETY: // `vec`, being mutable and allocated to `size` bytes, is safe to pass to ic0.stable_read with no offset. // ic0.stable_read writes to all of `vec[0..size]`, so `set_len` is safe to call with the new size. unsafe { - ic0::stable_read(vec.as_ptr() as i32, 0, size as i32); + ic0::stable64_read(vec.as_ptr() as i64, 0, size as i64); vec.set_len(size); } vec @@ -143,12 +116,12 @@ pub fn stable_bytes() -> Vec { /// Will attempt to grow the memory as it writes, /// and keep offsets and total capacity. #[derive(Debug)] -pub struct StableIO { +pub struct StableIO { /// The offset of the next write. - offset: A, + offset: u64, /// The capacity, in pages. - capacity: A, + capacity: u64, /// The stable memory to write data to. memory: M, @@ -164,127 +137,119 @@ impl Default for StableIO { // // We use a macro here since capturing all the traits required to add and manipulate memory // addresses with generics becomes cumbersome. -macro_rules! impl_stable_io { - ($address:ty) => { - impl + StableMemory> StableIO { - /// Creates a new `StableIO` which writes to the selected memory - pub fn with_memory(memory: M, offset: $address) -> Self { - let capacity = memory.stable_size_(); - - Self { - offset, - capacity, - memory, - } - } - /// Returns the offset of the writer - pub fn offset(&self) -> $address { - self.offset - } - - /// Attempts to grow the memory by adding new pages. - pub fn grow(&mut self, new_pages: $address) -> Result<(), StableMemoryError> { - let old_page_count = self.memory.stable_grow_(new_pages)?; - self.capacity = old_page_count + new_pages; - Ok(()) - } +impl StableIO { + /// Creates a new `StableIO` which writes to the selected memory + pub fn with_memory(memory: M, offset: u64) -> Self { + let capacity = memory.stable_size(); + Self { + offset, + capacity, + memory, + } + } - /// Writes a byte slice to the buffer. - /// - /// The only condition where this will - /// error out is if it cannot grow the memory. - pub fn write(&mut self, buf: &[u8]) -> Result { - let required_capacity_bytes = self.offset + buf.len() as $address; - let required_capacity_pages = - ((required_capacity_bytes + WASM_PAGE_SIZE_IN_BYTES as $address - 1) - / WASM_PAGE_SIZE_IN_BYTES as $address); - let current_pages = self.capacity; - let additional_pages_required = - required_capacity_pages.saturating_sub(current_pages); - - if additional_pages_required > 0 { - self.grow(additional_pages_required)?; - } - - self.memory.stable_write_(self.offset, buf); - self.offset += buf.len() as $address; - Ok(buf.len()) - } + /// Returns the offset of the writer + pub fn offset(&self) -> u64 { + self.offset + } - /// Reads data from the stable memory location specified by an offset. - /// - /// Note: - /// The stable memory size is cached on creation of the StableReader. - /// Therefore, in following scenario, it will get an `OutOfBounds` error: - /// 1. Create a StableReader - /// 2. Write some data to the stable memory which causes it grow - /// 3. call `read()` to read the newly written bytes - pub fn read(&mut self, buf: &mut [u8]) -> Result { - let capacity_bytes = self.capacity * WASM_PAGE_SIZE_IN_BYTES as $address; - let read_buf = if buf.len() as $address + self.offset > capacity_bytes { - if self.offset < capacity_bytes { - &mut buf[..(capacity_bytes - self.offset) as usize] - } else { - return Err(StableMemoryError::OutOfBounds); - } - } else { - buf - }; - self.memory.stable_read_(self.offset, read_buf); - self.offset += read_buf.len() as $address; - Ok(read_buf.len()) - } + /// Attempts to grow the memory by adding new pages. + pub fn grow(&mut self, new_pages: u64) -> Result<(), StableMemoryError> { + let old_page_count = self.memory.stable_grow(new_pages)?; + self.capacity = old_page_count + new_pages; + Ok(()) + } - // Helper used to implement io::Seek - fn seek(&mut self, offset: io::SeekFrom) -> io::Result { - self.offset = match offset { - io::SeekFrom::Start(offset) => offset as $address, - io::SeekFrom::End(offset) => { - ((self.capacity * WASM_PAGE_SIZE_IN_BYTES as $address) as i64 + offset) - as $address - } - io::SeekFrom::Current(offset) => (self.offset as i64 + offset) as $address, - }; - - Ok(self.offset as u64) - } + /// Writes a byte slice to the buffer. + /// + /// # Errors + /// + /// When it cannot grow the memory to accommodate the new data. + pub fn write(&mut self, buf: &[u8]) -> Result { + let required_capacity_bytes = self.offset + buf.len() as u64; + let required_capacity_pages = + (required_capacity_bytes + WASM_PAGE_SIZE_IN_BYTES - 1) / WASM_PAGE_SIZE_IN_BYTES; + let current_pages = self.capacity; + let additional_pages_required = required_capacity_pages.saturating_sub(current_pages); + + if additional_pages_required > 0 { + self.grow(additional_pages_required)?; } - impl + StableMemory> io::Write - for StableIO - { - fn write(&mut self, buf: &[u8]) -> Result { - self.write(buf) - .map_err(|e| io::Error::new(io::ErrorKind::OutOfMemory, e)) - } + self.memory.stable_write(self.offset, buf); + self.offset += buf.len() as u64; + Ok(buf.len()) + } - fn flush(&mut self) -> Result<(), io::Error> { - // Noop. - Ok(()) + /// Reads data from the stable memory location specified by an offset. + /// + /// # Errors + /// + /// The stable memory size is cached on creation of the StableReader. + /// Therefore, in following scenario, it will get an `OutOfBounds` error: + /// 1. Create a StableReader + /// 2. Write some data to the stable memory which causes it grow + /// 3. call `read()` to read the newly written bytes + pub fn read(&mut self, buf: &mut [u8]) -> Result { + let capacity_bytes = self.capacity * WASM_PAGE_SIZE_IN_BYTES; + let read_buf = if buf.len() as u64 + self.offset > capacity_bytes { + if self.offset < capacity_bytes { + // When usize=u32: + // (capacity_bytes - self.offset) < buf.len() <= u32::MAX == usize::MAX. + // So the cast below won't panic. + &mut buf[..(capacity_bytes - self.offset).try_into().unwrap()] + } else { + return Err(StableMemoryError::OutOfBounds); } - } + } else { + buf + }; + self.memory.stable_read(self.offset, read_buf); + self.offset += read_buf.len() as u64; + Ok(read_buf.len()) + } - impl + StableMemory> io::Read - for StableIO - { - fn read(&mut self, buf: &mut [u8]) -> Result { - Self::read(self, buf).or(Ok(0)) // Read defines EOF to be success + // Helper used to implement io::Seek + fn seek(&mut self, offset: io::SeekFrom) -> io::Result { + self.offset = match offset { + io::SeekFrom::Start(offset) => offset, + io::SeekFrom::End(offset) => { + ((self.capacity * WASM_PAGE_SIZE_IN_BYTES) as i64 + offset) as u64 } - } + io::SeekFrom::Current(offset) => (self.offset as i64 + offset) as u64, + }; - impl + StableMemory> io::Seek - for StableIO - { - fn seek(&mut self, offset: io::SeekFrom) -> io::Result { - self.seek(offset) - } - } - }; + Ok(self.offset) + } +} + +impl io::Write for StableIO { + fn write(&mut self, buf: &[u8]) -> Result { + self.write(buf) + .map_err(|e| io::Error::new(io::ErrorKind::OutOfMemory, e)) + } + + fn flush(&mut self) -> Result<(), io::Error> { + // Noop. + Ok(()) + } +} + +impl io::Read for StableIO { + fn read(&mut self, buf: &mut [u8]) -> Result { + Self::read(self, buf).or(Ok(0)) // Read defines EOF to be success + } +} + +impl io::Seek for StableIO { + fn seek(&mut self, offset: io::SeekFrom) -> io::Result { + self.seek(offset) + } } -impl_stable_io!(u32); -impl_stable_io!(u64); +// impl_stable_io!(u32); +// impl_stable_io!(u64); /// A writer to the stable memory. /// @@ -294,7 +259,7 @@ impl_stable_io!(u64); /// Will attempt to grow the memory as it writes, /// and keep offsets and total capacity. #[derive(Debug)] -pub struct StableWriter(StableIO); +pub struct StableWriter(StableIO); #[allow(clippy::derivable_impls)] impl Default for StableWriter { @@ -307,19 +272,19 @@ impl Default for StableWriter { impl StableWriter { /// Creates a new `StableWriter` which writes to the selected memory #[inline] - pub fn with_memory(memory: M, offset: usize) -> Self { - Self(StableIO::::with_memory(memory, offset as u32)) + pub fn with_memory(memory: M, offset: u64) -> Self { + Self(StableIO::::with_memory(memory, offset)) } /// Returns the offset of the writer #[inline] - pub fn offset(&self) -> usize { - self.0.offset() as usize + pub fn offset(&self) -> u64 { + self.0.offset() } /// Attempts to grow the memory by adding new pages. #[inline] - pub fn grow(&mut self, new_pages: u32) -> Result<(), StableMemoryError> { + pub fn grow(&mut self, new_pages: u64) -> Result<(), StableMemoryError> { self.0.grow(new_pages) } @@ -387,7 +352,7 @@ impl BufferedStableWriter { } /// Returns the offset of the writer - pub fn offset(&self) -> usize { + pub fn offset(&self) -> u64 { self.inner.get_ref().offset() } } @@ -413,7 +378,7 @@ impl io::Seek for BufferedStableWriter { /// /// Keeps an offset and reads off stable memory consecutively. #[derive(Debug)] -pub struct StableReader(StableIO); +pub struct StableReader(StableIO); #[allow(clippy::derivable_impls)] impl Default for StableReader { @@ -425,14 +390,14 @@ impl Default for StableReader { impl StableReader { /// Creates a new `StableReader` which reads from the selected memory #[inline] - pub fn with_memory(memory: M, offset: usize) -> Self { - Self(StableIO::::with_memory(memory, offset as u32)) + pub fn with_memory(memory: M, offset: u64) -> Self { + Self(StableIO::::with_memory(memory, offset)) } /// Returns the offset of the reader #[inline] - pub fn offset(&self) -> usize { - self.0.offset() as usize + pub fn offset(&self) -> u64 { + self.0.offset() } /// Reads data from the stable memory location specified by an offset. @@ -491,7 +456,7 @@ impl BufferedStableReader { } /// Returns the offset of the reader - pub fn offset(&self) -> usize { + pub fn offset(&self) -> u64 { self.inner.get_ref().offset() } } diff --git a/src/ic-cdk/src/api/stable/private.rs b/src/ic-cdk/src/api/stable/private.rs deleted file mode 100644 index e5f967b4a..000000000 --- a/src/ic-cdk/src/api/stable/private.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! Private module for traits that provide implementations for both u32 and u64 address space. - -use super::*; -pub trait AddressSize {} -impl AddressSize for u64 {} -impl AddressSize for u32 {} - -// An internal helper trait to have stable memory API specific to an address size -pub trait StableMemory_ { - fn stable_size_(&self) -> A; - fn stable_grow_(&self, new_pages: A) -> Result; - fn stable_write_(&self, offset: A, buf: &[u8]); - fn stable_read_(&self, offset: A, buf: &mut [u8]); -} - -// Blanket implementation for 32-bit addresses for any stable memory implementation -impl StableMemory_ for M { - fn stable_read_(&self, offset: u32, buf: &mut [u8]) { - StableMemory::stable_read(self, offset, buf) - } - - fn stable_grow_(&self, new_pages: u32) -> Result { - StableMemory::stable_grow(self, new_pages) - } - - fn stable_size_(&self) -> u32 { - StableMemory::stable_size(self) - } - - fn stable_write_(&self, offset: u32, buf: &[u8]) { - StableMemory::stable_write(self, offset, buf) - } -} - -// Blanket implementation for 64-bit addresses for any stable memory implementation -impl StableMemory_ for M { - fn stable_read_(&self, offset: u64, buf: &mut [u8]) { - StableMemory::stable64_read(self, offset, buf) - } - - fn stable_grow_(&self, new_pages: u64) -> Result { - StableMemory::stable64_grow(self, new_pages) - } - - fn stable_size_(&self) -> u64 { - StableMemory::stable64_size(self) - } - - fn stable_write_(&self, offset: u64, buf: &[u8]) { - StableMemory::stable64_write(self, offset, buf) - } -} diff --git a/src/ic-cdk/src/api/stable/tests.rs b/src/ic-cdk/src/api/stable/tests.rs index 5141238e4..aaf592849 100644 --- a/src/ic-cdk/src/api/stable/tests.rs +++ b/src/ic-cdk/src/api/stable/tests.rs @@ -13,7 +13,10 @@ impl TestStableMemory { if bytes_len > 0 { let pages_required = pages_required(bytes_len); let bytes_required = pages_required * WASM_PAGE_SIZE_IN_BYTES; - memory.lock().unwrap().resize(bytes_required, 0); + memory + .lock() + .unwrap() + .resize(bytes_required.try_into().unwrap(), 0); } TestStableMemory { memory } @@ -21,30 +24,22 @@ impl TestStableMemory { } impl StableMemory for TestStableMemory { - fn stable_size(&self) -> u32 { + fn stable_size(&self) -> u64 { let bytes_len = self.memory.lock().unwrap().len(); - pages_required(bytes_len) as u32 + pages_required(bytes_len) } - fn stable64_size(&self) -> u64 { - self.stable_size() as u64 - } - - fn stable_grow(&self, new_pages: u32) -> Result { - let new_bytes = new_pages as usize * WASM_PAGE_SIZE_IN_BYTES; + fn stable_grow(&self, new_pages: u64) -> Result { + let new_bytes = new_pages * WASM_PAGE_SIZE_IN_BYTES; let mut vec = self.memory.lock().unwrap(); - let previous_len = vec.len(); - let new_len = vec.len() + new_bytes; - vec.resize(new_len, 0); - Ok((previous_len / WASM_PAGE_SIZE_IN_BYTES) as u32) - } - - fn stable64_grow(&self, new_pages: u64) -> Result { - self.stable_grow(new_pages as u32).map(|len| len as u64) + let previous_len = vec.len() as u64; + let new_len = vec.len() as u64 + new_bytes; + vec.resize(new_len.try_into().unwrap(), 0); + Ok(previous_len / WASM_PAGE_SIZE_IN_BYTES) } - fn stable_write(&self, offset: u32, buf: &[u8]) { + fn stable_write(&self, offset: u64, buf: &[u8]) { let offset = offset as usize; let mut vec = self.memory.lock().unwrap(); @@ -54,11 +49,7 @@ impl StableMemory for TestStableMemory { vec[offset..(offset + buf.len())].clone_from_slice(buf); } - fn stable64_write(&self, offset: u64, buf: &[u8]) { - self.stable_write(offset as u32, buf) - } - - fn stable_read(&self, offset: u32, buf: &mut [u8]) { + fn stable_read(&self, offset: u64, buf: &mut [u8]) { let offset = offset as usize; let vec = self.memory.lock().unwrap(); @@ -66,15 +57,11 @@ impl StableMemory for TestStableMemory { buf[..count_to_copy].copy_from_slice(&vec[offset..offset + count_to_copy]); } - - fn stable64_read(&self, offset: u64, buf: &mut [u8]) { - self.stable_read(offset as u32, buf) - } } -fn pages_required(bytes_len: usize) -> usize { +fn pages_required(bytes_len: usize) -> u64 { let page_size = WASM_PAGE_SIZE_IN_BYTES; - (bytes_len + page_size - 1) / page_size + (bytes_len as u64 + page_size - 1) / page_size } mod stable_writer_tests { @@ -146,11 +133,11 @@ mod stable_writer_tests { } writer.flush().unwrap(); - let capacity_pages = TestStableMemory::new(memory).stable64_size(); + let capacity_pages = TestStableMemory::new(memory).stable_size(); let min_pages_required = - (total_bytes + WASM_PAGE_SIZE_IN_BYTES - 1) / WASM_PAGE_SIZE_IN_BYTES; + (total_bytes as u64 + WASM_PAGE_SIZE_IN_BYTES - 1) / WASM_PAGE_SIZE_IN_BYTES; - assert_eq!(capacity_pages, min_pages_required as u64); + assert_eq!(capacity_pages, min_pages_required); } #[test] @@ -161,7 +148,7 @@ mod stable_writer_tests { let mut writer = StableWriter::with_memory(TestStableMemory::new(memory.clone()), 0); assert_eq!(writer.offset(), 0); assert_eq!(writer.write(&vec![0; WRITE_SIZE]).unwrap(), WRITE_SIZE); - assert_eq!(writer.offset(), WRITE_SIZE); + assert_eq!(writer.offset(), WRITE_SIZE as u64); let mut writer = BufferedStableWriter::with_writer( WRITE_SIZE - 1, @@ -169,7 +156,7 @@ mod stable_writer_tests { ); assert_eq!(writer.offset(), 0); assert_eq!(writer.write(&vec![0; WRITE_SIZE]).unwrap(), WRITE_SIZE); - assert_eq!(writer.offset(), WRITE_SIZE); + assert_eq!(writer.offset(), WRITE_SIZE as u64); } #[test] @@ -177,18 +164,15 @@ mod stable_writer_tests { let memory = Rc::new(Mutex::new(Vec::new())); let mut writer = StableWriter::with_memory(TestStableMemory::new(memory.clone()), 0); writer - .seek(std::io::SeekFrom::Start(WASM_PAGE_SIZE_IN_BYTES as u64)) + .seek(std::io::SeekFrom::Start(WASM_PAGE_SIZE_IN_BYTES)) .unwrap(); - assert_eq!( - writer.stream_position().unwrap() as usize, - WASM_PAGE_SIZE_IN_BYTES - ); + assert_eq!(writer.stream_position().unwrap(), WASM_PAGE_SIZE_IN_BYTES); assert_eq!(writer.write(&[1_u8]).unwrap(), 1); assert_eq!( - writer.seek(std::io::SeekFrom::End(0)).unwrap() as usize, + writer.seek(std::io::SeekFrom::End(0)).unwrap(), WASM_PAGE_SIZE_IN_BYTES * 2 ); - let capacity_pages = TestStableMemory::new(memory).stable64_size(); + let capacity_pages = TestStableMemory::new(memory).stable_size(); assert_eq!(capacity_pages, 2); } @@ -233,7 +217,7 @@ mod stable_reader_tests { assert_eq!(reader.offset(), 0); let mut bytes = vec![0; READ_SIZE]; assert_eq!(reader.read(&mut bytes).unwrap(), READ_SIZE); - assert_eq!(reader.offset(), READ_SIZE); + assert_eq!(reader.offset(), READ_SIZE as u64); let mut reader = BufferedStableReader::with_reader( READ_SIZE - 1, @@ -242,7 +226,7 @@ mod stable_reader_tests { assert_eq!(reader.offset(), 0); let mut bytes = vec![0; READ_SIZE]; assert_eq!(reader.read(&mut bytes).unwrap(), READ_SIZE); - assert_eq!(reader.offset(), READ_SIZE); + assert_eq!(reader.offset(), READ_SIZE as u64); } #[test] @@ -260,11 +244,11 @@ mod stable_reader_tests { assert_eq!(reader.read(&mut bytes).unwrap(), 1); assert_eq!(&bytes, &[OFFSET as u8]); assert_eq!( - reader.seek(std::io::SeekFrom::End(0)).unwrap() as usize, + reader.seek(std::io::SeekFrom::End(0)).unwrap(), WASM_PAGE_SIZE_IN_BYTES ); reader - .seek(std::io::SeekFrom::Start(WASM_PAGE_SIZE_IN_BYTES as u64 * 2)) + .seek(std::io::SeekFrom::Start(WASM_PAGE_SIZE_IN_BYTES * 2)) .unwrap(); // out of bounds so should fail assert!(reader.read(&mut bytes).is_err()); From cdb98e421cb35c4500d6417926a3094bfbddb665 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Mon, 1 Jul 2024 13:18:57 -0400 Subject: [PATCH 216/234] chore: release 0.15.0 (#499) * bump ic-cdk to 0.15.0 * bump timers and ledger-types * update README --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 4 ++-- README.md | 2 +- library/ic-ledger-types/CHANGELOG.md | 6 ++++++ library/ic-ledger-types/Cargo.toml | 2 +- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-timers/CHANGELOG.md | 6 ++++++ src/ic-cdk-timers/Cargo.toml | 2 +- src/ic-cdk-timers/README.md | 2 +- src/ic-cdk/CHANGELOG.md | 13 +++++++++---- src/ic-cdk/Cargo.toml | 4 ++-- src/ic-cdk/README.md | 2 +- 12 files changed, 40 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fcd8d63b1..e3d3e46d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1118,11 +1118,11 @@ dependencies = [ [[package]] name = "ic-cdk" -version = "0.14.0" +version = "0.15.0" dependencies = [ "anyhow", "candid", - "ic-cdk-macros 0.14.0", + "ic-cdk-macros 0.15.0", "ic0 0.23.0", "rstest", "serde", @@ -1150,7 +1150,7 @@ dependencies = [ "escargot", "futures", "hex", - "ic-cdk 0.14.0", + "ic-cdk 0.15.0", "ic-cdk-timers", "lazy_static", "pocket-ic", @@ -1174,7 +1174,7 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.14.0" +version = "0.15.0" dependencies = [ "candid", "proc-macro2", @@ -1186,10 +1186,10 @@ dependencies = [ [[package]] name = "ic-cdk-timers" -version = "0.8.0" +version = "0.9.0" dependencies = [ "futures", - "ic-cdk 0.14.0", + "ic-cdk 0.15.0", "ic0 0.23.0", "serde", "serde_bytes", @@ -1203,7 +1203,7 @@ dependencies = [ "bincode", "candid", "hex", - "ic-cdk 0.14.0", + "ic-cdk 0.15.0", "serde", "serde_bytes", "serde_cbor", @@ -1212,12 +1212,12 @@ dependencies = [ [[package]] name = "ic-ledger-types" -version = "0.11.0" +version = "0.12.0" dependencies = [ "candid", "crc32fast", "hex", - "ic-cdk 0.14.0", + "ic-cdk 0.15.0", "serde", "serde_bytes", "sha2", diff --git a/Cargo.toml b/Cargo.toml index 14f536c9e..f17419d37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,8 +21,8 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.23.0" } -ic-cdk = { path = "src/ic-cdk", version = "0.14.0"} -ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.8.0" } +ic-cdk = { path = "src/ic-cdk", version = "0.15.0" } +ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.9.0" } candid = "0.10.4" candid_parser = "0.1.4" diff --git a/README.md b/README.md index cff587ef6..6aff8e388 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ In Cargo.toml: crate-type = ["cdylib"] [dependencies] -ic-cdk = "0.12" +ic-cdk = "0.15" # Only necessary if you want to define Candid data types candid = "0.10" ``` diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index 4f577b031..1a0d69ad9 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.12.0] - 2024-07-01 + +### Changed + +- Upgrade `ic-cdk` to v0.15. + ## [0.11.0] - 2024-05-17 ### Changed diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 0598de229..2e051ff20 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.11.0" +version = "0.12.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 22f66b642..7be3dc13e 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.14.0" # sync with ic-cdk +version = "0.15.0" # sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index 76daa57d0..743d4fd47 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.9.0] - 2024-07-01 + +### Changed + +- Upgrade `ic-cdk` to v0.15. + ## [0.8.0] - 2024-05-17 ### Changed diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index 02262bf77..1e0b95336 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.8.0" +version = "0.9.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-timers/README.md b/src/ic-cdk-timers/README.md index bf0cdb021..4539793ef 100644 --- a/src/ic-cdk-timers/README.md +++ b/src/ic-cdk-timers/README.md @@ -16,7 +16,7 @@ In `Cargo.toml`: ```toml [dependencies] -ic-cdk-timers = "0.4.0" +ic-cdk-timers = "0.9.0" ``` To schedule a one-shot task to be executed 1s later: diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index ab4bda0b7..21850b17d 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,23 +6,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.15.0] - 2024-07-01 + ### Changed -- BREAKING: Stable Memory always use 64-bit addresses and `stable64_*` system API. +- BREAKING: Stable Memory always use 64-bit addresses and `stable64_*` system API. (#498) +- BREAKING: Add `log_visibility` to the management canister API types: (#497) + - `CanisterSettings` + - `DefiniteCanisterSettings`. ## [0.14.0] - 2024-05-17 ## [0.13.3] - 2024-05-10 (yanked) ### Added -- Add `wasm_memory_limit` to the management canister API types: (#483) - * `CanisterSettings` - * `DefiniteCanisterSettings`. - Provide safe wrapper of `in_replicated_execution` in ic-cdk. (#489) ### Changed - Upgrade `ic0` to v0.23.0. (#489) +- BREAKING: Add `wasm_memory_limit` to the management canister API types: (#483) + - `CanisterSettings` + - `DefiniteCanisterSettings`. ## [0.13.2] - 2024-04-08 diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 0ed5cbf69..bbda394fd 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.14.0" # sync with ic-cdk-macros +version = "0.15.0" # sync with ic-cdk-macros authors.workspace = true edition.workspace = true license.workspace = true @@ -27,7 +27,7 @@ ic0.workspace = true # Dependents won't accidentaly upgrading ic-cdk-macros only but not ic-cdk. # ic-cdk-macros is a hidden dependency, re-exported by ic-cdk. # It should not be included by users direcly. -ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.14.0" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.15.0" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true } diff --git a/src/ic-cdk/README.md b/src/ic-cdk/README.md index 4608337d6..5fa3244e1 100644 --- a/src/ic-cdk/README.md +++ b/src/ic-cdk/README.md @@ -25,7 +25,7 @@ In Cargo.toml: crate-type = ["cdylib"] [dependencies] -ic-cdk = "0.12" +ic-cdk = "0.15" # Only necessary if you want to define Candid data types candid = "0.10" ``` From 5ae05523f2f1ee5f965324e4c8e83957e09d4a78 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Fri, 5 Jul 2024 12:27:44 -0700 Subject: [PATCH 217/234] fix: ld-compatible symbols (#500) --- src/ic-cdk-macros/CHANGELOG.md | 4 ++++ src/ic-cdk-macros/src/export.rs | 25 +++++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index 1393753d8..86df405c8 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Fixed + +- `cargo build` should no longer give a confusing linkage error on Linux. + ## [0.13.2] - 2024-04-08 ### Changed diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index 2141586c7..6d087d398 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -162,6 +162,7 @@ fn dfn_macro( } format!("canister_{method} {function_name}") }; + let host_compatible_name = export_name.replace(' ', ".").replace(['-', '<', '>'], "_"); let function_call = if is_async { quote! { #name ( #(#arg_tuple),* ) .await } @@ -256,7 +257,8 @@ fn dfn_macro( }; Ok(quote! { - #[export_name = #export_name] + #[cfg_attr(target_family = "wasm", export_name = #export_name)] + #[cfg_attr(not(target_family = "wasm"), export_name = #host_compatible_name)] fn #outer_function_ident() { ic_cdk::setup(); @@ -327,7 +329,8 @@ mod test { }; let expected = quote! { - #[export_name = "canister_query query"] + #[cfg_attr(target_family = "wasm", export_name = "canister_query query")] + #[cfg_attr(not(target_family = "wasm"), export_name = "canister_query.query")] fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { @@ -369,7 +372,8 @@ mod test { }; let expected = quote! { - #[export_name = "canister_query query"] + #[cfg_attr(target_family = "wasm", export_name = "canister_query query")] + #[cfg_attr(not(target_family = "wasm"), export_name = "canister_query.query")] fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { @@ -412,7 +416,8 @@ mod test { }; let expected = quote! { - #[export_name = "canister_query query"] + #[cfg_attr(target_family = "wasm", export_name = "canister_query query")] + #[cfg_attr(not(target_family = "wasm"), export_name = "canister_query.query")] fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { @@ -455,7 +460,8 @@ mod test { }; let expected = quote! { - #[export_name = "canister_query query"] + #[cfg_attr(target_family = "wasm", export_name = "canister_query query")] + #[cfg_attr(not(target_family = "wasm"), export_name = "canister_query.query")] fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { @@ -498,7 +504,8 @@ mod test { }; let expected = quote! { - #[export_name = "canister_query query"] + #[cfg_attr(target_family = "wasm", export_name = "canister_query query")] + #[cfg_attr(not(target_family = "wasm"), export_name = "canister_query.query")] fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { @@ -541,7 +548,8 @@ mod test { }; let expected = quote! { - #[export_name = "canister_query query"] + #[cfg_attr(target_family = "wasm", export_name = "canister_query query")] + #[cfg_attr(not(target_family = "wasm"), export_name = "canister_query.query")] fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { @@ -584,7 +592,8 @@ mod test { }; let expected = quote! { - #[export_name = "canister_query custom_query"] + #[cfg_attr(target_family = "wasm", export_name = "canister_query custom_query")] + #[cfg_attr(not(target_family = "wasm"), export_name = "canister_query.custom_query")] fn #fn_name() { ic_cdk::setup(); ic_cdk::spawn(async { From 59795716487fbb8a9910ac503bcea1e0cb08c932 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Wed, 24 Jul 2024 10:48:12 -0700 Subject: [PATCH 218/234] Use ld-compatible symbol in ic-cdk-timers (#503) --- src/ic-cdk-timers/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ic-cdk-timers/src/lib.rs b/src/ic-cdk-timers/src/lib.rs index 863ae8a16..845958d40 100644 --- a/src/ic-cdk-timers/src/lib.rs +++ b/src/ic-cdk-timers/src/lib.rs @@ -260,7 +260,14 @@ fn update_ic0_timer() { }); } -#[export_name = "canister_update timer_executor"] +#[cfg_attr( + target_family = "wasm", + export_name = "canister_update timer_executor" +)] +#[cfg_attr( + not(target_family = "wasm"), + export_name = "canister_update_ic_cdk_internal.timer_executor" +)] extern "C" fn timer_executor() { if ic_cdk::api::caller() != ic_cdk::api::id() { ic_cdk::trap("This function is internal to ic-cdk and should not be called externally."); From a8a7d4e5bd9707c69fca41986b9fe7798fa7d58f Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 8 Aug 2024 13:26:59 -0400 Subject: [PATCH 219/234] feat!: canister state snapshots (#504) * snapshot types * snapshot methods * types cont. * update pocket-ic which support nonmainnet features * e2e test * add LoadSnapshot variant to CanisterChangeDetails * changelog * fix canister_info e2e test * show canister_info after snapshot operations * ci test show output * revert canister_info.rs * revert ci.yml * canister_info changes can have load_snapshot records --- Cargo.lock | 82 +++++++++++++------ e2e-tests/Cargo.toml | 2 +- e2e-tests/canisters/management_caller.rs | 68 +++++++++++++++ e2e-tests/tests/e2e.rs | 44 +++++++--- scripts/download_pocket_ic.sh | 2 +- src/ic-cdk/CHANGELOG.md | 10 +++ .../src/api/management_canister/main/mod.rs | 54 ++++++++++++ .../src/api/management_canister/main/types.rs | 69 ++++++++++++++++ 8 files changed, 295 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e3d3e46d0..686acd2b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1513,6 +1513,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.7.3" @@ -1524,13 +1534,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1584,16 +1595,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" version = "0.32.2" @@ -1724,11 +1725,10 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "pocket-ic" -version = "3.1.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9765eeff77b8750cf6258eaeea237b96607cd770aa3d4003f021924192b7e4e" +checksum = "629f46b7ab8a8d2fee02220ef8e99ae552c7e220117efa1ce0882ff09c8fb038" dependencies = [ - "async-trait", "base64 0.13.1", "candid", "hex", @@ -1738,6 +1738,8 @@ dependencies = [ "serde", "serde_bytes", "serde_json", + "sha2", + "tokio", "tracing", "tracing-appender", "tracing-subscriber", @@ -1912,6 +1914,7 @@ dependencies = [ "js-sys", "log", "mime", + "mime_guess", "once_cell", "percent-encoding", "pin-project-lite", @@ -2147,9 +2150,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.201" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] @@ -2175,9 +2178,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", @@ -2270,6 +2273,15 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -2513,18 +2525,31 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", - "windows-sys 0.48.0", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", ] [[package]] @@ -2742,6 +2767,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 2466e94a2..ac646bb3b 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -53,4 +53,4 @@ path = "canisters/chunk.rs" [dev-dependencies] hex.workspace = true -pocket-ic = "3" +pocket-ic = "4" diff --git a/e2e-tests/canisters/management_caller.rs b/e2e-tests/canisters/management_caller.rs index db662d6b4..6c9ee51ba 100644 --- a/e2e-tests/canisters/management_caller.rs +++ b/e2e-tests/canisters/management_caller.rs @@ -109,4 +109,72 @@ mod provisional { } } +mod snapshot { + use super::*; + use ic_cdk::api::management_canister::main::*; + + #[update] + async fn execute_snapshot_methods() { + let arg = CreateCanisterArgument::default(); + let canister_id = create_canister(arg, 2_000_000_000_000u128) + .await + .unwrap() + .0 + .canister_id; + + // Cannot take a snapshot of a canister that is empty. + // So we install a minimal wasm module. + let arg = InstallCodeArgument { + mode: CanisterInstallMode::Install, + canister_id, + // A minimal valid wasm module + // wat2wasm "(module)" + wasm_module: b"\x00asm\x01\x00\x00\x00".to_vec(), + arg: vec![], + }; + install_code(arg).await.unwrap(); + + let arg = TakeCanisterSnapshotArgs { + canister_id, + replace_snapshot: None, + }; + let snapshot = take_canister_snapshot(arg).await.unwrap().0; + + let arg = LoadCanisterSnapshotArgs { + canister_id, + snapshot_id: snapshot.id.clone(), + sender_canister_version: None, + }; + assert!(load_canister_snapshot(arg).await.is_ok()); + + let canister_id_record = CanisterIdRecord { canister_id }; + let snapshots = list_canister_snapshots(canister_id_record).await.unwrap().0; + assert_eq!(snapshots.len(), 1); + assert_eq!(snapshots[0].id, snapshot.id); + + let arg = DeleteCanisterSnapshotArgs { + canister_id, + snapshot_id: snapshot.id.clone(), + }; + assert!(delete_canister_snapshot(arg).await.is_ok()); + + let arg = CanisterInfoRequest { + canister_id, + num_requested_changes: Some(1), + }; + let canister_info_response = canister_info(arg).await.unwrap().0; + assert_eq!(canister_info_response.total_num_changes, 3); + assert_eq!(canister_info_response.recent_changes.len(), 1); + if let CanisterChange { + details: CanisterChangeDetails::LoadSnapshot(load_snapshot_record), + .. + } = &canister_info_response.recent_changes[0] + { + assert_eq!(load_snapshot_record.snapshot_id, snapshot.id); + } else { + panic!("Expected the most recent change to be LoadSnapshot"); + } + } +} + fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 54a4f652c..57268ae5f 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -1,5 +1,6 @@ use std::time::Duration; use std::time::SystemTime; +use std::time::UNIX_EPOCH; use candid::utils::ArgumentDecoder; use candid::utils::ArgumentEncoder; @@ -13,6 +14,7 @@ use ic_cdk::api::management_canister::main::{ }; use ic_cdk_e2e_tests::cargo_build_canister; use pocket_ic::common::rest::RawEffectivePrincipal; +use pocket_ic::PocketIcBuilder; use pocket_ic::{call_candid_as, query_candid, CallError, ErrorCode, PocketIc, WasmResult}; use serde_bytes::ByteBuf; @@ -334,7 +336,15 @@ fn test_set_global_timers() { fn test_canister_info() { let pic = PocketIc::new(); let wasm = cargo_build_canister("canister_info"); - pic.set_time(SystemTime::UNIX_EPOCH); + // As of PocketIC server v5.0.0 and client v4.0.0, the first canister creation happens at (time0+4). + // Each operation advances the Pic by 2 nanos, except for the last operation which advances only by 1 nano. + let time0: u64 = pic + .get_time() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos() + .try_into() + .unwrap(); let canister_id = pic.create_canister(); pic.add_cycles(canister_id, INIT_CYCLES); pic.install_canister(canister_id, wasm, vec![], None); @@ -377,7 +387,7 @@ fn test_canister_info() { total_num_changes: 9, recent_changes: vec![ CanisterChange { - timestamp_nanos: 4, + timestamp_nanos: time0 + 4, canister_version: 0, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -388,7 +398,7 @@ fn test_canister_info() { }), }, CanisterChange { - timestamp_nanos: 6, + timestamp_nanos: time0 + 6, canister_version: 1, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -403,7 +413,7 @@ fn test_canister_info() { }), }, CanisterChange { - timestamp_nanos: 8, + timestamp_nanos: time0 + 8, canister_version: 2, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -412,7 +422,7 @@ fn test_canister_info() { details: CanisterChangeDetails::CodeUninstall, }, CanisterChange { - timestamp_nanos: 10, + timestamp_nanos: time0 + 10, canister_version: 3, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -427,7 +437,7 @@ fn test_canister_info() { }), }, CanisterChange { - timestamp_nanos: 12, + timestamp_nanos: time0 + 12, canister_version: 4, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -442,7 +452,7 @@ fn test_canister_info() { }), }, CanisterChange { - timestamp_nanos: 14, + timestamp_nanos: time0 + 14, canister_version: 5, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -457,7 +467,7 @@ fn test_canister_info() { }), }, CanisterChange { - timestamp_nanos: 16, + timestamp_nanos: time0 + 16, canister_version: 6, origin: CanisterChangeOrigin::FromCanister(FromCanisterRecord { canister_id, @@ -468,7 +478,7 @@ fn test_canister_info() { }), }, CanisterChange { - timestamp_nanos: 18, + timestamp_nanos: time0 + 18, canister_version: 7, origin: CanisterChangeOrigin::FromUser(FromUserRecord { user_id: Principal::anonymous(), @@ -476,7 +486,7 @@ fn test_canister_info() { details: CanisterChangeDetails::CodeUninstall, }, CanisterChange { - timestamp_nanos: 19, + timestamp_nanos: time0 + 19, canister_version: 8, origin: CanisterChangeOrigin::FromUser(FromUserRecord { user_id: Principal::anonymous(), @@ -543,6 +553,20 @@ fn test_call_management() { .expect("Error calling execute_provisional_methods"); } +#[test] +fn test_snapshot() { + let pic = PocketIcBuilder::new() + .with_application_subnet() + .with_nonmainnet_features(true) + .build(); + let wasm = cargo_build_canister("management_caller"); + let canister_id = pic.create_canister(); + pic.add_cycles(canister_id, 300_000_000_000_000_000_000_000_000u128); + pic.install_canister(canister_id, wasm, vec![], None); + let () = call_candid(&pic, canister_id, "execute_snapshot_methods", ()) + .expect("Error calling execute_snapshot_methods"); +} + #[test] fn test_chunk() { let pic = PocketIc::new(); diff --git a/scripts/download_pocket_ic.sh b/scripts/download_pocket_ic.sh index 545dd8306..b0191645c 100755 --- a/scripts/download_pocket_ic.sh +++ b/scripts/download_pocket_ic.sh @@ -9,7 +9,7 @@ cd "$SCRIPTS_DIR/../e2e-tests" uname_sys=$(uname -s | tr '[:upper:]' '[:lower:]') echo "uname_sys: $uname_sys" -tag="release-2024-05-22_23-01-base" +tag="release-2024-08-02_01-30-base" curl -sL "https://github.com/dfinity/ic/releases/download/$tag/pocket-ic-x86_64-$uname_sys.gz" --output pocket-ic.gz gzip -df pocket-ic.gz diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 21850b17d..e5ad83969 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Changed + +- BREAKING: Add the `LoadSnapshot` variant to `CanisterChangeDetails`. (#504) + +### Added + +- Support Canister State Snapshots. (#504) + - Add methods: `take_canister_snapshot`, `load_canister_snapshot`, `list_canister_snapshots`, `delete_canister_snapshot` + - Add types: `LoadSnapshotRecord`, `SnapshotId`, `Snapshot`, `TakeCanisterSnapshotArgs`, `LoadCanisterSnapshotArgs`, `DeleteCanisterSnapshotArgs` + ## [0.15.0] - 2024-07-01 ### Changed diff --git a/src/ic-cdk/src/api/management_canister/main/mod.rs b/src/ic-cdk/src/api/management_canister/main/mod.rs index d1cd9de3e..9f686c4f8 100644 --- a/src/ic-cdk/src/api/management_canister/main/mod.rs +++ b/src/ic-cdk/src/api/management_canister/main/mod.rs @@ -185,3 +185,57 @@ pub async fn raw_rand() -> CallResult<(Vec,)> { pub async fn canister_info(arg: CanisterInfoRequest) -> CallResult<(CanisterInfoResponse,)> { call(Principal::management_canister(), "canister_info", (arg,)).await } + +/// Take a snapshot of the specified canister. +/// +/// A snapshot consists of the wasm memory, stable memory, certified variables, wasm chunk store and wasm binary. +/// +/// See [IC method `take_canister_snapshot`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-take_canister_snapshot). +pub async fn take_canister_snapshot(arg: TakeCanisterSnapshotArgs) -> CallResult<(Snapshot,)> { + call( + Principal::management_canister(), + "take_canister_snapshot", + (arg,), + ) + .await +} + +/// Load a snapshot onto the canister. +/// +/// It fails if no snapshot with the specified `snapshot_id` can be found. +/// +/// See [IC method `load_canister_snapshot`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-load_canister_snapshot). +pub async fn load_canister_snapshot(arg: LoadCanisterSnapshotArgs) -> CallResult<()> { + call( + Principal::management_canister(), + "load_canister_snapshot", + (arg,), + ) + .await +} + +/// List the snapshots of the canister. +/// +/// See [IC method `list_canister_snapshots`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-list_canister_snapshots). +pub async fn list_canister_snapshots(arg: CanisterIdRecord) -> CallResult<(Vec,)> { + call( + Principal::management_canister(), + "list_canister_snapshots", + (arg,), + ) + .await +} + +/// Delete a specified snapshot that belongs to an existing canister. +/// +/// An error will be returned if the snapshot is not found. +/// +/// See [IC method `delete_canister_snapshot`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-delete_canister_snapshot). +pub async fn delete_canister_snapshot(arg: DeleteCanisterSnapshotArgs) -> CallResult<()> { + call( + Principal::management_canister(), + "delete_canister_snapshot", + (arg,), + ) + .await +} diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index 97c284fd3..d08ca652f 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -454,6 +454,19 @@ pub struct CodeDeploymentRecord { pub module_hash: Vec, } +/// Details about loading canister snapshot. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct LoadSnapshotRecord { + /// The version of the canister at the time that the snapshot was taken + pub canister_version: u64, + /// The ID of the snapshot that was loaded. + pub snapshot_id: SnapshotId, + /// The timestamp at which the snapshot was taken. + pub taken_at_timestamp: u64, +} + /// Details about updating canister controllers. #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, @@ -477,6 +490,9 @@ pub enum CanisterChangeDetails { /// See [CodeDeploymentRecord]. #[serde(rename = "code_deployment")] CodeDeployment(CodeDeploymentRecord), + /// See [LoadSnapshotRecord]. + #[serde(rename = "load_snapshot")] + LoadSnapshot(LoadSnapshotRecord), /// See [ControllersChangeRecord]. #[serde(rename = "controllers_change")] ControllersChange(ControllersChangeRecord), @@ -526,3 +542,56 @@ pub struct CanisterInfoResponse { /// Controllers of the canister. pub controllers: Vec, } + +/// ID of a canister snapshot. +pub type SnapshotId = Vec; + +/// A snapshot of the state of the canister at a given point in time. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct Snapshot { + /// ID of the snapshot. + pub id: SnapshotId, + /// The timestamp at which the snapshot was taken. + pub taken_at_timestamp: u64, + /// The size of the snapshot in bytes. + pub total_size: u64, +} + +/// Argument type of [take_canister_snapshot](super::take_canister_snapshot). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct TakeCanisterSnapshotArgs { + /// Principal of the canister. + pub canister_id: CanisterId, + /// An optional snapshot ID to be replaced by the new snapshot. + /// + /// The snapshot identified by the specified ID will be deleted once a new snapshot has been successfully created. + pub replace_snapshot: Option, +} + +/// Argument type of [load_canister_snapshot](super::load_canister_snapshot). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct LoadCanisterSnapshotArgs { + /// Principal of the canister. + pub canister_id: CanisterId, + /// ID of the snapshot to be loaded. + pub snapshot_id: SnapshotId, + /// sender_canister_version must be set to ic_cdk::api::canister_version(). + pub sender_canister_version: Option, +} + +/// Argument type of [delete_canister_snapshot](super::delete_canister_snapshot). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct DeleteCanisterSnapshotArgs { + /// Principal of the canister. + pub canister_id: CanisterId, + /// ID of the snapshot to be deleted. + pub snapshot_id: SnapshotId, +} From 3a42917fa48a42e6fb756d791c19b52b1bed010e Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Wed, 14 Aug 2024 10:45:34 -0700 Subject: [PATCH 220/234] chore: update deprecated actions (#507) --- .github/workflows/release-candid-extractor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-candid-extractor.yml b/.github/workflows/release-candid-extractor.yml index e5ae44bfb..fdf73b069 100644 --- a/.github/workflows/release-candid-extractor.yml +++ b/.github/workflows/release-candid-extractor.yml @@ -20,10 +20,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cargo/bin/ From deb1e15ae4c60333636f0581e0f30d169d8c9a0a Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 15 Aug 2024 11:32:19 -0400 Subject: [PATCH 221/234] docs: clarify post_upgrade argument types (#508) * Improve READMEs * clarify post_upgrade arg type --- README.md | 5 ++--- src/ic-cdk/README.md | 3 +-- src/ic-cdk/src/macros.rs | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6aff8e388..2e0ecadc7 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ This repo provides libraries and tools to facilitate developing canisters in Rus - [`ic0`](src/ic0): Internet Computer System API binding. - [`ic-cdk`](src/ic-cdk): -Internet Computer Canister Development Kit +Internet Computer Canister Development Kit. - [`ic-cdk-bindgen`](src/ic-cdk-bindgen): Generate Rust bindings from Candid to make inter-canister calls. - [`ic-cdk-macros`](src/ic-cdk-macros): @@ -53,8 +53,7 @@ crate-type = ["cdylib"] [dependencies] ic-cdk = "0.15" -# Only necessary if you want to define Candid data types -candid = "0.10" +candid = "0.10" # required if you want to define Candid data types ``` Then in Rust source code: diff --git a/src/ic-cdk/README.md b/src/ic-cdk/README.md index 5fa3244e1..aaa8b802d 100644 --- a/src/ic-cdk/README.md +++ b/src/ic-cdk/README.md @@ -26,8 +26,7 @@ crate-type = ["cdylib"] [dependencies] ic-cdk = "0.15" -# Only necessary if you want to define Candid data types -candid = "0.10" +candid = "0.10" # required if you want to define Candid data types ``` Then in Rust source code: diff --git a/src/ic-cdk/src/macros.rs b/src/ic-cdk/src/macros.rs index 733be8117..8c3162875 100644 --- a/src/ic-cdk/src/macros.rs +++ b/src/ic-cdk/src/macros.rs @@ -177,12 +177,15 @@ pub use ic_cdk_macros::update; /// } /// ``` /// -/// The init function may accept an argument, if that argument is a `CandidType`: +/// The init function may accept an argument. +/// +/// The argument must implement the `CandidType` trait. +/// +/// And it should match the initialization parameters of the service constructor in the Candid interface. /// /// ```rust /// # use ic_cdk::init; /// # use candid::*; -/// /// #[derive(Clone, Debug, CandidType, Deserialize)] /// struct InitArg { /// foo: u8, @@ -197,6 +200,8 @@ pub use ic_cdk_macros::update; /// /// In this case, the argument will be read from `ic0.msg_arg_data_size/copy` and passed to the /// init function upon successful deserialization. +/// +/// /// Refer to the [`canister_init` Specification](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-init) for more information. pub use ic_cdk_macros::init; @@ -240,6 +245,31 @@ pub use ic_cdk_macros::pre_upgrade; /// # unimplemented!() /// } /// ``` +/// +/// The post_upgrade function may accept an argument. +/// +/// The argument must implement the `CandidType` trait. +/// +/// And it should match the initialization parameters of the service constructor in the Candid interface. +/// Therefore, the init function and the post_upgrade function should take the same argument type. +/// +/// ```rust +/// # use ic_cdk::post_upgrade; +/// # use candid::*; +/// #[derive(Clone, Debug, CandidType, Deserialize)] +/// struct InitArg { +/// foo: u8, +/// } +/// +/// #[post_upgrade] +/// fn post_upgrade_function(arg: InitArg) { +/// // ... +/// # unimplemented!() +/// } +/// ``` +/// +/// In this case, the argument will be read from `ic0.msg_arg_data_size/copy` and passed to the +/// post_upgrade function upon successful deserialization. pub use ic_cdk_macros::post_upgrade; /// Register the `canister_heartbeat` entry point of a canister. From bd17d57a7b8ca59665fea5fad6143ca02724d03b Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:06:55 -0700 Subject: [PATCH 222/234] fix: Fix memory leak in CallFuture (#509) --- src/ic-cdk/src/api/call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ic-cdk/src/api/call.rs b/src/ic-cdk/src/api/call.rs index ca6fbac36..2fd130210 100644 --- a/src/ic-cdk/src/api/call.rs +++ b/src/ic-cdk/src/api/call.rs @@ -74,7 +74,6 @@ impl> Future for CallFuture { fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll { let self_ref = Pin::into_inner(self); - let state_ptr = Weak::into_raw(Arc::downgrade(&self_ref.state)); let mut state = self_ref.state.write().unwrap(); if let Some(result) = state.result.take() { @@ -85,6 +84,7 @@ impl> Future for CallFuture { let method = &state.method; let args = state.arg.as_ref(); let payment = state.payment; + let state_ptr = Weak::into_raw(Arc::downgrade(&self_ref.state)); // SAFETY: // `callee`, being &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_new. // `method`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.call_new. From 3e54016734c8f73fb3acabc9c9e72c960c85eb3b Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 27 Aug 2024 09:38:03 -0400 Subject: [PATCH 223/234] chore: release ic-cdk v0.16.0 (#513) --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 4 ++-- library/ic-ledger-types/CHANGELOG.md | 6 ++++++ library/ic-ledger-types/Cargo.toml | 2 +- src/ic-cdk-macros/CHANGELOG.md | 9 +++++++-- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-timers/CHANGELOG.md | 6 ++++++ src/ic-cdk-timers/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 2 ++ src/ic-cdk/Cargo.toml | 4 ++-- 10 files changed, 37 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 686acd2b4..182cbbf8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1118,11 +1118,11 @@ dependencies = [ [[package]] name = "ic-cdk" -version = "0.15.0" +version = "0.16.0" dependencies = [ "anyhow", "candid", - "ic-cdk-macros 0.15.0", + "ic-cdk-macros 0.16.0", "ic0 0.23.0", "rstest", "serde", @@ -1150,7 +1150,7 @@ dependencies = [ "escargot", "futures", "hex", - "ic-cdk 0.15.0", + "ic-cdk 0.16.0", "ic-cdk-timers", "lazy_static", "pocket-ic", @@ -1174,7 +1174,7 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.15.0" +version = "0.16.0" dependencies = [ "candid", "proc-macro2", @@ -1186,10 +1186,10 @@ dependencies = [ [[package]] name = "ic-cdk-timers" -version = "0.9.0" +version = "0.10.0" dependencies = [ "futures", - "ic-cdk 0.15.0", + "ic-cdk 0.16.0", "ic0 0.23.0", "serde", "serde_bytes", @@ -1203,7 +1203,7 @@ dependencies = [ "bincode", "candid", "hex", - "ic-cdk 0.15.0", + "ic-cdk 0.16.0", "serde", "serde_bytes", "serde_cbor", @@ -1212,12 +1212,12 @@ dependencies = [ [[package]] name = "ic-ledger-types" -version = "0.12.0" +version = "0.13.0" dependencies = [ "candid", "crc32fast", "hex", - "ic-cdk 0.15.0", + "ic-cdk 0.16.0", "serde", "serde_bytes", "sha2", diff --git a/Cargo.toml b/Cargo.toml index f17419d37..7864d033d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,8 +21,8 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.23.0" } -ic-cdk = { path = "src/ic-cdk", version = "0.15.0" } -ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.9.0" } +ic-cdk = { path = "src/ic-cdk", version = "0.16.0" } +ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.10.0" } candid = "0.10.4" candid_parser = "0.1.4" diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index 1a0d69ad9..b5d8be669 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.13.0] - 2024-08-27 + +### Changed + +- Upgrade `ic-cdk` to v0.16. + ## [0.12.0] - 2024-07-01 ### Changed diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 2e051ff20..2f4d483a0 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.12.0" +version = "0.13.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-macros/CHANGELOG.md b/src/ic-cdk-macros/CHANGELOG.md index 86df405c8..8609dd37e 100644 --- a/src/ic-cdk-macros/CHANGELOG.md +++ b/src/ic-cdk-macros/CHANGELOG.md @@ -1,11 +1,16 @@ # Changelog + +This file will no longer be updated. + +Please check [`ic-cdk` changelog](../ic-cdk/CHANGELOG.md). + +--- + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [unreleased] - ### Fixed - `cargo build` should no longer give a confusing linkage error on Linux. diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 7be3dc13e..3cc05e464 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.15.0" # sync with ic-cdk +version = "0.16.0" # sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index 743d4fd47..e1bb9e7b8 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.10.0] - 2024-08-27 + +### Changed + +- Upgrade `ic-cdk` to v0.16. + ## [0.9.0] - 2024-07-01 ### Changed diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index 1e0b95336..58da23362 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.9.0" +version = "0.10.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index e5ad83969..3bd84028d 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.16.0] - 2024-08-27 + ### Changed - BREAKING: Add the `LoadSnapshot` variant to `CanisterChangeDetails`. (#504) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index bbda394fd..a4064e045 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.15.0" # sync with ic-cdk-macros +version = "0.16.0" # sync with ic-cdk-macros authors.workspace = true edition.workspace = true license.workspace = true @@ -27,7 +27,7 @@ ic0.workspace = true # Dependents won't accidentaly upgrading ic-cdk-macros only but not ic-cdk. # ic-cdk-macros is a hidden dependency, re-exported by ic-cdk. # It should not be included by users direcly. -ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.15.0" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.16.0" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true } From 97c4e19c76b7f072ce8507cb7e7a527582111272 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan <103510076+maksymar@users.noreply.github.com> Date: Fri, 6 Sep 2024 21:10:42 +0200 Subject: [PATCH 224/234] feat: add AllowedViewers variant to LogVisibility enum (#512) --- src/ic-cdk/CHANGELOG.md | 2 ++ src/ic-cdk/src/api/management_canister/main/types.rs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 3bd84028d..2acde0b7d 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +* Add `AllowedViewers` to `LogVisibility` enum. + ## [0.16.0] - 2024-08-27 ### Changed diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index d08ca652f..ec68304d5 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -16,6 +16,9 @@ pub enum LogVisibility { #[serde(rename = "public")] /// Everyone is allowed to access the canister's logs. Public, + #[serde(rename = "allowed_viewers")] + /// Canister logs are visible to a set of principals. + AllowedViewers(Vec), } /// Canister settings. From 19bfaf3a1203673c25e78606cc53f1d361a60402 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Tue, 17 Sep 2024 07:01:31 -0700 Subject: [PATCH 225/234] feat: Add Schnorr signing API (#518) Co-authored-by: Severin Siffert --- .../management_canister/src/caller/lib.rs | 34 ++++++++ examples/management_canister/tests/basic.bats | 7 ++ src/ic-cdk/CHANGELOG.md | 8 +- .../src/api/management_canister/ecdsa/mod.rs | 4 +- src/ic-cdk/src/api/management_canister/mod.rs | 1 + .../api/management_canister/schnorr/mod.rs | 43 ++++++++++ .../api/management_canister/schnorr/types.rs | 86 +++++++++++++++++++ 7 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 src/ic-cdk/src/api/management_canister/schnorr/mod.rs create mode 100644 src/ic-cdk/src/api/management_canister/schnorr/types.rs diff --git a/examples/management_canister/src/caller/lib.rs b/examples/management_canister/src/caller/lib.rs index 901b0362e..2ac5d9b94 100644 --- a/examples/management_canister/src/caller/lib.rs +++ b/examples/management_canister/src/caller/lib.rs @@ -85,6 +85,40 @@ mod ecdsa { } } +mod schnorr { + use super::*; + use ic_cdk::api::management_canister::schnorr::*; + + #[update] + async fn execute_schnorr_methods() { + let key_id = SchnorrKeyId { + algorithm: SchnorrAlgorithm::Bip340secp256k1, + name: "dfx_test_key".to_string(), + }; + let derivation_path = vec![]; + let arg = SchnorrPublicKeyArgument { + canister_id: None, + derivation_path: derivation_path.clone(), + key_id: key_id.clone(), + }; + let SchnorrPublicKeyResponse { + public_key, + chain_code, + } = schnorr_public_key(arg).await.unwrap().0; + assert_eq!(public_key.len(), 33); + assert_eq!(chain_code.len(), 32); + + let message = "hello world".into(); + let arg = SignWithSchnorrArgument { + message, + derivation_path, + key_id, + }; + let SignWithSchnorrResponse { signature } = sign_with_schnorr(arg).await.unwrap().0; + assert_eq!(signature.len(), 64); + } +} + mod bitcoin { use super::*; use ic_cdk::api::{call::RejectionCode, management_canister::bitcoin::*}; diff --git a/examples/management_canister/tests/basic.bats b/examples/management_canister/tests/basic.bats index 8c51a7fa8..6abf4d195 100644 --- a/examples/management_canister/tests/basic.bats +++ b/examples/management_canister/tests/basic.bats @@ -24,6 +24,13 @@ teardown() { assert_success } +@test "schnorr methods succeed" { + dfx start --clean --background + dfx deploy + run dfx canister call caller execute_schnorr_methods + assert_success +} + @test "bitcoin methods succeed" { bitcoind -regtest -daemonwait diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 2acde0b7d..2c58efa9d 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,7 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -* Add `AllowedViewers` to `LogVisibility` enum. +### Changed + +- Add `AllowedViewers` variant to `LogVisibility` enum. (#512) + +### Added + +- Support Threshold Schnorr signing management canister API. (#518) ## [0.16.0] - 2024-08-27 diff --git a/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs b/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs index edd19ae94..4be77769c 100644 --- a/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs +++ b/src/ic-cdk/src/api/management_canister/ecdsa/mod.rs @@ -1,4 +1,4 @@ -//! The ECDSA API. +//! Threshold ECDSA signing API. use crate::api::call::{call, call_with_payment128, CallResult}; use candid::Principal; @@ -23,7 +23,7 @@ pub async fn ecdsa_public_key( /// /// This call requires cycles payment. /// This method handles the cycles cost under the hood. -/// Check [Gas and cycles cost](https://internetcomputer.org/docs/current/developer-docs/gas-cost) for more details. +/// Check [Threshold signatures](https://internetcomputer.org/docs/current/references/t-sigs-how-it-works) for more details. pub async fn sign_with_ecdsa(arg: SignWithEcdsaArgument) -> CallResult<(SignWithEcdsaResponse,)> { call_with_payment128( Principal::management_canister(), diff --git a/src/ic-cdk/src/api/management_canister/mod.rs b/src/ic-cdk/src/api/management_canister/mod.rs index 85481ce5b..dd9c83a77 100644 --- a/src/ic-cdk/src/api/management_canister/mod.rs +++ b/src/ic-cdk/src/api/management_canister/mod.rs @@ -15,3 +15,4 @@ pub mod ecdsa; pub mod http_request; pub mod main; pub mod provisional; +pub mod schnorr; diff --git a/src/ic-cdk/src/api/management_canister/schnorr/mod.rs b/src/ic-cdk/src/api/management_canister/schnorr/mod.rs new file mode 100644 index 000000000..36e6fe15c --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/schnorr/mod.rs @@ -0,0 +1,43 @@ +//! Threshold Schnorr signing API. + +use crate::api::call::{call, call_with_payment128, CallResult}; +use candid::Principal; + +mod types; +pub use types::*; + +// Source: https://internetcomputer.org/docs/current/references/t-sigs-how-it-works/#fees-for-the-t-schnorr-production-key +const SIGN_WITH_SCHNORR_FEE: u128 = 26_153_846_153; + +/// Return a SEC1 encoded Schnorr public key for the given canister using the given derivation path. +/// +/// See [IC method `schnorr_public_key`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-schnorr_public_key). +pub async fn schnorr_public_key( + arg: SchnorrPublicKeyArgument, +) -> CallResult<(SchnorrPublicKeyResponse,)> { + call( + Principal::management_canister(), + "schnorr_public_key", + (arg,), + ) + .await +} + +/// Return a new Schnorr signature of the given message that can be separately verified against a derived Schnorr public key. +/// +/// See [IC method `sign_with_schnorr`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-sign_with_schnorr). +/// +/// This call requires cycles payment. +/// This method handles the cycles cost under the hood. +/// Check [Threshold signatures](https://internetcomputer.org/docs/current/references/t-sigs-how-it-works) for more details. +pub async fn sign_with_schnorr( + arg: SignWithSchnorrArgument, +) -> CallResult<(SignWithSchnorrResponse,)> { + call_with_payment128( + Principal::management_canister(), + "sign_with_schnorr", + (arg,), + SIGN_WITH_SCHNORR_FEE, + ) + .await +} diff --git a/src/ic-cdk/src/api/management_canister/schnorr/types.rs b/src/ic-cdk/src/api/management_canister/schnorr/types.rs new file mode 100644 index 000000000..6760b9097 --- /dev/null +++ b/src/ic-cdk/src/api/management_canister/schnorr/types.rs @@ -0,0 +1,86 @@ +use candid::CandidType; +use serde::{Deserialize, Serialize}; + +use super::super::main::CanisterId; + +/// Argument Type of [schnorr_public_key](super::schnorr_public_key). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct SchnorrPublicKeyArgument { + /// Canister id, default to the canister id of the caller if None. + pub canister_id: Option, + /// A vector of variable length byte strings. + pub derivation_path: Vec>, + /// See [SchnorrKeyId]. + pub key_id: SchnorrKeyId, +} + +/// Response Type of [schnorr_public_key](super::schnorr_public_key). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct SchnorrPublicKeyResponse { + /// An Schnorr public key encoded in SEC1 compressed form. + pub public_key: Vec, + /// Can be used to deterministically derive child keys of the public_key. + pub chain_code: Vec, +} + +/// Argument Type of [sign_with_schnorr](super::sign_with_schnorr). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct SignWithSchnorrArgument { + /// Message to be signed. + pub message: Vec, + /// A vector of variable length byte strings. + pub derivation_path: Vec>, + /// See [SchnorrKeyId]. + pub key_id: SchnorrKeyId, +} + +/// Response Type of [sign_with_schnorr](super::sign_with_schnorr). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct SignWithSchnorrResponse { + /// The encoding of the signature depends on the key ID's algorithm. + pub signature: Vec, +} + +/// Schnorr KeyId. +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct SchnorrKeyId { + /// See [SchnorrAlgorithm]. + pub algorithm: SchnorrAlgorithm, + /// Name. + pub name: String, +} + +/// Schnorr Algorithm. +#[derive( + CandidType, + Serialize, + Deserialize, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Clone, + Copy, + Default, +)] +pub enum SchnorrAlgorithm { + /// BIP-340 secp256k1. + #[serde(rename = "bip340secp256k1")] + #[default] + Bip340secp256k1, + /// ed25519. + #[serde(rename = "ed25519")] + Ed25519, +} From 882fa28116c84887be626a44ce031b739e45e3d5 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 25 Sep 2024 18:00:23 +0200 Subject: [PATCH 226/234] feat(ic-ledger-types): Add AccountIdentifier.as_bytes() (#520) --- library/ic-ledger-types/CHANGELOG.md | 3 +++ library/ic-ledger-types/src/lib.rs | 27 ++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index b5d8be669..9a3df14ef 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Added +- as_bytes method to AccountIdentifier in ic-ledger-types + ## [0.13.0] - 2024-08-27 ### Changed diff --git a/library/ic-ledger-types/src/lib.rs b/library/ic-ledger-types/src/lib.rs index f1a171e6d..53ae8a601 100644 --- a/library/ic-ledger-types/src/lib.rs +++ b/library/ic-ledger-types/src/lib.rs @@ -218,6 +218,11 @@ impl AccountIdentifier { hex::encode(self.0) } + /// Provide the account identifier as bytes. + pub fn as_bytes(&self) -> &[u8; 32] { + &self.0 + } + /// Returns the checksum of the account identifier. pub fn generate_checksum(&self) -> [u8; 4] { let mut hasher = crc32fast::Hasher::new(); @@ -883,8 +888,11 @@ mod tests { ) } + /// Verifies that these conversions yield the same result: + /// * bytes -> AccountIdentifier -> hex -> AccountIdentifier + /// * bytes -> AccountIdentifier #[test] - fn check_round_trip() { + fn check_hex_round_trip() { let bytes: [u8; 32] = [ 237, 196, 46, 168, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, @@ -899,6 +907,23 @@ mod tests { ) } + /// Verifies that this convertion yields the original data: + /// * bytes -> AccountIdentifier -> bytes + #[test] + fn check_bytes_round_trip() { + let bytes: [u8; 32] = [ + 237, 196, 46, 168, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, + ]; + assert_eq!( + AccountIdentifier::from_slice(&bytes) + .expect("Failed to parse bytes as principal") + .as_bytes(), + &bytes, + "The account identifier doesn't change after going back and forth between a string" + ) + } + #[test] fn test_account_id_from_slice() { let length_27 = b"123456789_123456789_1234567".to_vec(); From 13d01ed231a8859a0a2498e3b6354e3fb32d1eb5 Mon Sep 17 00:00:00 2001 From: Severin Siffert Date: Mon, 28 Oct 2024 15:23:58 +0100 Subject: [PATCH 227/234] chore: update license file (#526) --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index b27ba1fe8..b752c47a2 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2020 DFINITY LLC. + Copyright 2020 DFINITY Stiftung. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 9a65c417f30f2df7000b32feb7cd688a46b2954f Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Mon, 4 Nov 2024 13:06:23 -0800 Subject: [PATCH 228/234] feat: Implement low wasm memory hook (#528) --- src/ic-cdk-macros/src/export.rs | 24 +++++++++++++++++------- src/ic-cdk-macros/src/lib.rs | 10 ++++++++++ src/ic-cdk/CHANGELOG.md | 1 + src/ic-cdk/README.md | 1 + src/ic-cdk/src/macros.rs | 21 +++++++++++++++++++++ src/ic-cdk/tests/pass/blank_methods.rs | 7 ++++++- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/ic-cdk-macros/src/export.rs b/src/ic-cdk-macros/src/export.rs index 6d087d398..320c94d77 100644 --- a/src/ic-cdk-macros/src/export.rs +++ b/src/ic-cdk-macros/src/export.rs @@ -33,18 +33,20 @@ enum MethodType { Query, Heartbeat, InspectMessage, + OnLowWasmMemory, } impl MethodType { pub fn is_lifecycle(&self) -> bool { - matches!( - self, + match self { MethodType::Init - | MethodType::PreUpgrade - | MethodType::PostUpgrade - | MethodType::Heartbeat - | MethodType::InspectMessage - ) + | MethodType::PreUpgrade + | MethodType::PostUpgrade + | MethodType::Heartbeat + | MethodType::InspectMessage + | MethodType::OnLowWasmMemory => true, + MethodType::Update | MethodType::Query => false, + } } } @@ -58,6 +60,7 @@ impl std::fmt::Display for MethodType { MethodType::Update => f.write_str("update"), MethodType::Heartbeat => f.write_str("heartbeat"), MethodType::InspectMessage => f.write_str("inspect_message"), + MethodType::OnLowWasmMemory => f.write_str("on_low_wasm_memory"), } } } @@ -309,6 +312,13 @@ pub(crate) fn ic_inspect_message( dfn_macro(MethodType::InspectMessage, attr, item) } +pub(crate) fn ic_on_low_wasm_memory( + attr: TokenStream, + item: TokenStream, +) -> Result { + dfn_macro(MethodType::OnLowWasmMemory, attr, item) +} + #[cfg(test)] mod test { use super::*; diff --git a/src/ic-cdk-macros/src/lib.rs b/src/ic-cdk-macros/src/lib.rs index d9e75e690..00a0d566d 100644 --- a/src/ic-cdk-macros/src/lib.rs +++ b/src/ic-cdk-macros/src/lib.rs @@ -91,3 +91,13 @@ pub fn heartbeat(attr: TokenStream, item: TokenStream) -> TokenStream { pub fn inspect_message(attr: TokenStream, item: TokenStream) -> TokenStream { handle_debug_and_errors(export::ic_inspect_message, "ic_inspect_message", attr, item) } + +#[proc_macro_attribute] +pub fn on_low_wasm_memory(attr: TokenStream, item: TokenStream) -> TokenStream { + handle_debug_and_errors( + export::ic_on_low_wasm_memory, + "ic_on_low_wasm_memory", + attr, + item, + ) +} diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 2c58efa9d..55d130c1d 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Attribute `#[on_low_wasm_memory]` for low-memory hook. (#528) - Support Threshold Schnorr signing management canister API. (#518) ## [0.16.0] - 2024-08-27 diff --git a/src/ic-cdk/README.md b/src/ic-cdk/README.md index aaa8b802d..80d7ffcf2 100644 --- a/src/ic-cdk/README.md +++ b/src/ic-cdk/README.md @@ -58,6 +58,7 @@ These macros are directly related to the [Internet Computer Specification](https * [`post_upgrade`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.post_upgrade.html) * [`inspect_message`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.inspect_message.html) * [`heartbeat`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.heartbeat.html) +* [`on_low_wasm_memory`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.on_low_wasm_memory.html) * [`update`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.update.html) * [`query`](https://docs.rs/ic-cdk/latest/ic_cdk/attr.query.html) diff --git a/src/ic-cdk/src/macros.rs b/src/ic-cdk/src/macros.rs index 8c3162875..e2f88c5b9 100644 --- a/src/ic-cdk/src/macros.rs +++ b/src/ic-cdk/src/macros.rs @@ -313,3 +313,24 @@ pub use ic_cdk_macros::heartbeat; /// } /// ``` pub use ic_cdk_macros::inspect_message; + +/// Register the `canister_on_low_wasm_memory` entry point of a canister. +/// +/// This attribute macro will export the function `canister_on_low_wasm_memory` +/// in the canister module. +/// +/// The function under this attribute must have no return value. +/// +/// Each canister can only have one `canister_on_low_wasm_memory` entry point. +/// +/// # Example +/// +/// ```rust +/// # use ic_cdk::on_low_wasm_memory; +/// #[on_low_wasm_memory] +/// fn low_memory_handler() { +/// // ... +/// # unimplemented!() +/// } +/// ``` +pub use ic_cdk_macros::on_low_wasm_memory; diff --git a/src/ic-cdk/tests/pass/blank_methods.rs b/src/ic-cdk/tests/pass/blank_methods.rs index bd3922901..32e4440e6 100644 --- a/src/ic-cdk/tests/pass/blank_methods.rs +++ b/src/ic-cdk/tests/pass/blank_methods.rs @@ -1,4 +1,6 @@ -use ic_cdk::{heartbeat, init, inspect_message, post_upgrade, pre_upgrade, query, update}; +use ic_cdk::{ + heartbeat, init, inspect_message, on_low_wasm_memory, post_upgrade, pre_upgrade, query, update, +}; #[init] fn init() {} @@ -30,4 +32,7 @@ fn heartbeat() {} #[inspect_message] fn inspect_message() {} +#[on_low_wasm_memory] +fn on_low_wasm_memory() {} + fn main() {} From 4e628a8b4ca0d2eb5736e01fdca604707b7e294f Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Mon, 4 Nov 2024 15:01:09 -0800 Subject: [PATCH 229/234] fix: Update CanisterInstallMode signature (#527) --- .github/workflows/ci.yml | 2 +- .../src/api/management_canister/main/types.rs | 36 +++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 814e425b4..6a5341580 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-12] + os: [ubuntu-latest, macos-13-large] steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index ec68304d5..9eea37e81 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -191,10 +191,10 @@ pub enum CanisterInstallMode { Reinstall, /// Upgrade an existing canister. #[serde(rename = "upgrade")] - Upgrade(Option), + Upgrade(Option), } -/// If set to true, the pre_upgrade step will be skipped during the canister upgrade +/// Flags for canister installation with [`CanisterInstallMode::Upgrade`]. #[derive( CandidType, Serialize, @@ -209,7 +209,37 @@ pub enum CanisterInstallMode { Copy, Default, )] -pub struct SkipPreUpgrade(pub Option); +pub struct UpgradeFlags { + /// If set to `true`, the `pre_upgrade` step will be skipped during the canister upgrade + pub skip_pre_upgrade: Option, + /// If set to `Keep`, the WASM heap memory will be preserved instead of cleared. + pub wasm_memory_persistence: Option, +} + +/// WASM memory persistence setting for [`UpgradeFlags`]. +#[derive( + CandidType, + Serialize, + Deserialize, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Clone, + Copy, + Default, +)] +pub enum WasmPersistenceMode { + /// Preserve heap memory (only officially supported by Motoko) + #[serde(rename = "keep")] + Keep, + /// Clear heap memory + #[serde(rename = "replace")] + #[default] + Replace, +} /// WASM module. pub type WasmModule = Vec; From 2ebd180fe97995e70c0451e9164dd55d8e5ba006 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Tue, 5 Nov 2024 03:45:35 -0800 Subject: [PATCH 230/234] Release ic-cdk 0.17 (#529) --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 4 ++-- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk-timers/CHANGELOG.md | 6 ++++++ src/ic-cdk-timers/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 2 ++ src/ic-cdk/Cargo.toml | 4 ++-- 7 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 182cbbf8c..62a8c0391 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1118,11 +1118,11 @@ dependencies = [ [[package]] name = "ic-cdk" -version = "0.16.0" +version = "0.17.0" dependencies = [ "anyhow", "candid", - "ic-cdk-macros 0.16.0", + "ic-cdk-macros 0.17.0", "ic0 0.23.0", "rstest", "serde", @@ -1150,7 +1150,7 @@ dependencies = [ "escargot", "futures", "hex", - "ic-cdk 0.16.0", + "ic-cdk 0.17.0", "ic-cdk-timers", "lazy_static", "pocket-ic", @@ -1174,7 +1174,7 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.16.0" +version = "0.17.0" dependencies = [ "candid", "proc-macro2", @@ -1186,10 +1186,10 @@ dependencies = [ [[package]] name = "ic-cdk-timers" -version = "0.10.0" +version = "0.11.0" dependencies = [ "futures", - "ic-cdk 0.16.0", + "ic-cdk 0.17.0", "ic0 0.23.0", "serde", "serde_bytes", @@ -1203,7 +1203,7 @@ dependencies = [ "bincode", "candid", "hex", - "ic-cdk 0.16.0", + "ic-cdk 0.17.0", "serde", "serde_bytes", "serde_cbor", @@ -1217,7 +1217,7 @@ dependencies = [ "candid", "crc32fast", "hex", - "ic-cdk 0.16.0", + "ic-cdk 0.17.0", "serde", "serde_bytes", "sha2", diff --git a/Cargo.toml b/Cargo.toml index 7864d033d..a5b3262fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,8 +21,8 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.23.0" } -ic-cdk = { path = "src/ic-cdk", version = "0.16.0" } -ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.10.0" } +ic-cdk = { path = "src/ic-cdk", version = "0.17.0" } +ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.11.0" } candid = "0.10.4" candid_parser = "0.1.4" diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index 3cc05e464..c0723e860 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.16.0" # sync with ic-cdk +version = "0.17.0" # sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk-timers/CHANGELOG.md b/src/ic-cdk-timers/CHANGELOG.md index e1bb9e7b8..ff67fb194 100644 --- a/src/ic-cdk-timers/CHANGELOG.md +++ b/src/ic-cdk-timers/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.11.0] - 2024-11-04 + +### Changed + +- Upgrade `ic-cdk` to v0.17. + ## [0.10.0] - 2024-08-27 ### Changed diff --git a/src/ic-cdk-timers/Cargo.toml b/src/ic-cdk-timers/Cargo.toml index 58da23362..3ebb7788f 100644 --- a/src/ic-cdk-timers/Cargo.toml +++ b/src/ic-cdk-timers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-timers" -version = "0.10.0" +version = "0.11.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 55d130c1d..139f53f5d 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.17.0] - 2024-11-04 + ### Changed - Add `AllowedViewers` variant to `LogVisibility` enum. (#512) diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index a4064e045..49397ec3d 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.16.0" # sync with ic-cdk-macros +version = "0.17.0" # sync with ic-cdk-macros authors.workspace = true edition.workspace = true license.workspace = true @@ -27,7 +27,7 @@ ic0.workspace = true # Dependents won't accidentaly upgrading ic-cdk-macros only but not ic-cdk. # ic-cdk-macros is a hidden dependency, re-exported by ic-cdk. # It should not be included by users direcly. -ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.16.0" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.17.0" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true } From 8f57d6d26b1d142b5be4b39ea8ade59d7c848cde Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Fri, 8 Nov 2024 05:25:44 -0800 Subject: [PATCH 231/234] chore: release ic-ledger-types v0.14 (#531) --- Cargo.lock | 2 +- library/ic-ledger-types/CHANGELOG.md | 6 ++++++ library/ic-ledger-types/Cargo.toml | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 62a8c0391..39b838b65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1212,7 +1212,7 @@ dependencies = [ [[package]] name = "ic-ledger-types" -version = "0.13.0" +version = "0.14.0" dependencies = [ "candid", "crc32fast", diff --git a/library/ic-ledger-types/CHANGELOG.md b/library/ic-ledger-types/CHANGELOG.md index 9a3df14ef..44938ef9b 100644 --- a/library/ic-ledger-types/CHANGELOG.md +++ b/library/ic-ledger-types/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.14.0] - 2024-11-08 + +### Changed + +- Upgrade `ic-cdk` to v0.17. + ### Added - as_bytes method to AccountIdentifier in ic-ledger-types diff --git a/library/ic-ledger-types/Cargo.toml b/library/ic-ledger-types/Cargo.toml index 2f4d483a0..18c9fc6eb 100644 --- a/library/ic-ledger-types/Cargo.toml +++ b/library/ic-ledger-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-ledger-types" -version = "0.13.0" +version = "0.14.0" authors.workspace = true edition.workspace = true license.workspace = true From b3090c343ba571baf0bb7d0bd503123650a67e2a Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Wed, 4 Dec 2024 13:36:09 -0500 Subject: [PATCH 232/234] feat: support subnet_info (#532) * feat: support subnet_info * changelog * use ubuntu-24.04 in CI * clippy * fix(e2e): create canister requires more cycles * rust 1.78.0 --- .github/workflows/ci.yml | 12 +- .github/workflows/conventional-commits.yml | 2 +- .github/workflows/examples.yml | 6 +- .../workflows/release-candid-extractor.yml | 4 +- Cargo.lock | 1618 +++++++++++------ Cargo.toml | 2 +- e2e-tests/Cargo.toml | 2 +- e2e-tests/canisters/chunk.rs | 2 +- e2e-tests/canisters/management_caller.rs | 8 + e2e-tests/tests/e2e.rs | 3 + library/ic-certified-map/src/rbtree.rs | 1 + rust-toolchain.toml | 2 +- scripts/download_pocket_ic.sh | 2 +- src/ic-cdk-timers/src/lib.rs | 2 +- src/ic-cdk/CHANGELOG.md | 5 + .../src/api/management_canister/main/mod.rs | 7 + .../src/api/management_canister/main/types.rs | 18 + 17 files changed, 1084 insertions(+), 612 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a5341580..1b6bdcb8c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ concurrency: jobs: build: name: cargo build - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v4 @@ -43,7 +43,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-13-large] + os: [ubuntu-24.04, macos-13-large] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -71,7 +71,7 @@ jobs: fmt: name: cargo fmt - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v4 @@ -94,7 +94,7 @@ jobs: clippy: name: cargo clippy - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v4 @@ -117,7 +117,7 @@ jobs: doc: name: cargo doc - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v4 @@ -142,7 +142,7 @@ jobs: name: ci:required if: ${{ always() }} needs: [build, test, fmt, clippy, doc] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: check build result if: ${{ needs.build.result != 'success' }} diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml index 0d9e0330d..304bee83a 100644 --- a/.github/workflows/conventional-commits.yml +++ b/.github/workflows/conventional-commits.yml @@ -15,7 +15,7 @@ concurrency: jobs: check: name: conventional-pr-title:required - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: # Conventional commit patterns: # verb: description diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index bb9dce1b4..807da5464 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -17,7 +17,7 @@ env: jobs: build-candid-extractor: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v4 @@ -45,7 +45,7 @@ jobs: path: target/release/candid-extractor test: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: build-candid-extractor strategy: fail-fast: false @@ -125,7 +125,7 @@ jobs: name: examples:required if: ${{ always() }} needs: test - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Check step result directly if: ${{ needs.test.result != 'success' }} diff --git a/.github/workflows/release-candid-extractor.yml b/.github/workflows/release-candid-extractor.yml index fdf73b069..621a263f5 100644 --- a/.github/workflows/release-candid-extractor.yml +++ b/.github/workflows/release-candid-extractor.yml @@ -11,9 +11,7 @@ jobs: fail-fast: false matrix: include: - # The indirect dependency `zstd-safe` (introduced by `wasmtime`) needs higher version of GLIBC. - # using ubuntu-20.04 will fail to compile - - os: ubuntu-22.04 + - os: ubuntu-24.04 binstall_pkg: candid-extractor-x86_64-unknown-linux-gnu.tar.gz - os: macos-12 binstall_pkg: candid-extractor-x86_64-apple-darwin.tar.gz diff --git a/Cargo.lock b/Cargo.lock index 39b838b65..91d53be33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,14 +8,23 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "gimli", + "gimli 0.28.1", ] [[package]] -name = "adler" -version = "1.0.2" +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli 0.31.1", +] + +[[package]] +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" @@ -40,9 +49,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -55,49 +64,49 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" [[package]] name = "arrayvec" @@ -116,13 +125,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] @@ -133,23 +142,34 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backoff" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +dependencies = [ + "getrandom", + "instant", + "rand", +] [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ - "addr2line", - "cc", + "addr2line 0.24.2", "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.36.5", "rustc-demangle", + "windows-targets", ] [[package]] @@ -225,9 +245,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -252,24 +272,24 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "camino" -version = "1.1.6" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] [[package]] name = "candid" -version = "0.10.8" +version = "0.10.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5902d37352dffd8bd9177a2daa6444ce3cd0279c91763fb0171c053aa04335" +checksum = "6c30ee7f886f296b6422c0ff017e89dd4f831521dfdcc76f3f71aae1ce817222" dependencies = [ "anyhow", "binread", @@ -285,7 +305,7 @@ dependencies = [ "serde", "serde_bytes", "stacker", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -295,7 +315,7 @@ dependencies = [ "anyhow", "clap", "quote", - "syn 2.0.61", + "syn 2.0.90", "wasmtime", ] @@ -308,7 +328,7 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] @@ -327,14 +347,14 @@ dependencies = [ "logos", "num-bigint", "pretty", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -350,18 +370,18 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cc" -version = "1.0.97" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -370,11 +390,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "clap" -version = "4.5.4" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" dependencies = [ "clap_builder", "clap_derive", @@ -382,9 +408,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" dependencies = [ "anstream", "anstyle", @@ -394,21 +420,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "codespan-reporting" @@ -417,14 +443,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" dependencies = [ "termcolor", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "convert_case" @@ -437,9 +463,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.4" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" dependencies = [ "core-foundation-sys", "libc", @@ -447,24 +473,24 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpp_demangle" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" +checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" dependencies = [ "cfg-if", ] [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -491,7 +517,7 @@ dependencies = [ "cranelift-control", "cranelift-entity", "cranelift-isle", - "gimli", + "gimli 0.28.1", "hashbrown 0.14.5", "log", "regalloc2", @@ -574,15 +600,15 @@ dependencies = [ "itertools 0.12.1", "log", "smallvec", - "wasmparser", + "wasmparser 0.201.0", "wasmtime-types", ] [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -617,9 +643,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -702,6 +728,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "dyn-clone" version = "1.0.17" @@ -710,9 +747,9 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "either" -version = "1.11.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "ena" @@ -725,9 +762,9 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -738,21 +775,30 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "erased-serde" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" +dependencies = [ + "serde", +] + [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "escargot" -version = "0.5.10" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f474c6844cbd04e783d0f25757583db4f491770ca618bedf2fb01815fc79939" +checksum = "05a3ac187a16b5382fef8c69fd1bad123c67b7cf3932240a2d43dcdd32cded88" dependencies = [ "log", "once_cell", @@ -789,9 +835,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -804,9 +850,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -814,15 +860,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -831,38 +877,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -915,8 +961,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -930,6 +978,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "glob" version = "0.3.1" @@ -938,9 +992,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ "atomic-waker", "bytes", @@ -979,6 +1033,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "heck" version = "0.4.1" @@ -991,12 +1051,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "hex" version = "0.4.3" @@ -1008,9 +1062,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -1019,9 +1073,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", @@ -1029,12 +1083,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http", "http-body", "pin-project-lite", @@ -1042,15 +1096,15 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "hyper" -version = "1.3.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", @@ -1068,26 +1122,28 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.26.0" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http", "hyper", "hyper-util", "rustls", + "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", + "webpki-roots", ] [[package]] name = "hyper-util" -version = "0.1.4" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d8d52be92d09acc2e01dddb7fde3ad983fc6489c7db4837e605bc3fca4cb63e" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", @@ -1098,32 +1154,18 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] -[[package]] -name = "ic-cdk" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8859bc2b863a77750acf199e1fb7e3fc403e1b475855ba13f59cb4e4036d238" -dependencies = [ - "candid", - "ic-cdk-macros 0.13.2", - "ic0 0.21.1", - "serde", - "serde_bytes", -] - [[package]] name = "ic-cdk" version = "0.17.0" dependencies = [ "anyhow", "candid", - "ic-cdk-macros 0.17.0", - "ic0 0.23.0", + "ic-cdk-macros", + "ic0", "rstest", "serde", "serde_bytes", @@ -1150,7 +1192,7 @@ dependencies = [ "escargot", "futures", "hex", - "ic-cdk 0.17.0", + "ic-cdk", "ic-cdk-timers", "lazy_static", "pocket-ic", @@ -1158,20 +1200,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "ic-cdk-macros" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45800053d80a6df839a71aaea5797e723188c0b992618208ca3b941350c7355" -dependencies = [ - "candid", - "proc-macro2", - "quote", - "serde", - "serde_tokenstream 0.1.7", - "syn 1.0.109", -] - [[package]] name = "ic-cdk-macros" version = "0.17.0" @@ -1180,8 +1208,8 @@ dependencies = [ "proc-macro2", "quote", "serde", - "serde_tokenstream 0.2.0", - "syn 2.0.61", + "serde_tokenstream", + "syn 2.0.90", ] [[package]] @@ -1189,13 +1217,25 @@ name = "ic-cdk-timers" version = "0.11.0" dependencies = [ "futures", - "ic-cdk 0.17.0", - "ic0 0.23.0", + "ic-cdk", + "ic0", "serde", "serde_bytes", "slotmap", ] +[[package]] +name = "ic-certification" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64ee3d8b6e81b51f245716d3e0badb63c283c00f3c9fb5d5219afc30b5bf821" +dependencies = [ + "hex", + "serde", + "serde_bytes", + "sha2", +] + [[package]] name = "ic-certified-map" version = "0.4.0" @@ -1203,7 +1243,7 @@ dependencies = [ "bincode", "candid", "hex", - "ic-cdk 0.17.0", + "ic-cdk", "serde", "serde_bytes", "serde_cbor", @@ -1217,24 +1257,35 @@ dependencies = [ "candid", "crc32fast", "hex", - "ic-cdk 0.17.0", + "ic-cdk", "serde", "serde_bytes", "sha2", ] [[package]] -name = "ic0" -version = "0.21.1" +name = "ic-transport-types" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a54b5297861c651551676e8c43df805dad175cc33bc97dbd992edbbb85dcbcdf" +checksum = "875dc4704780383112e8e8b5063a1b98de114321d0c7d3e7f635dcf360a57fba" +dependencies = [ + "candid", + "hex", + "ic-certification", + "leb128", + "serde", + "serde_bytes", + "serde_repr", + "sha2", + "thiserror 1.0.69", +] [[package]] name = "ic0" version = "0.23.0" dependencies = [ "quote", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] @@ -1248,7 +1299,125 @@ dependencies = [ "data-encoding", "serde", "sha2", - "thiserror", + "thiserror 1.0.69", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -1259,36 +1428,56 @@ checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] [[package]] name = "indexmap" -version = "2.2.6" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.2", "serde", ] +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -1310,9 +1499,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "ittapi" @@ -1336,19 +1525,20 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1366,7 +1556,7 @@ dependencies = [ "petgraph", "pico-args", "regex", - "regex-syntax 0.8.3", + "regex-syntax 0.8.5", "string_cache", "term", "tiny-keccak", @@ -1380,14 +1570,14 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata 0.4.6", + "regex-automata 0.4.9", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "leb128" @@ -1397,9 +1587,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libredox" @@ -1413,9 +1603,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" @@ -1429,9 +1625,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "logos" @@ -1453,7 +1649,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.6.29", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] @@ -1485,9 +1681,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memfd" @@ -1525,20 +1721,19 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi", "libc", "wasi", "windows-sys 0.52.0", @@ -1562,9 +1757,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -1607,11 +1802,20 @@ dependencies = [ "memchr", ] +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl-probe" @@ -1627,9 +1831,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1645,7 +1849,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets", ] [[package]] @@ -1685,31 +1889,11 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.61", -] - [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -1719,30 +1903,37 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "pocket-ic" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629f46b7ab8a8d2fee02220ef8e99ae552c7e220117efa1ce0882ff09c8fb038" +version = "6.0.0" +source = "git+https://github.com/dfinity/ic?tag=release-2024-11-28_03-15-base#2d8611eb4efa8e69c4dd567546c1c353a545e0a6" dependencies = [ + "backoff", "base64 0.13.1", "candid", "hex", - "ic-cdk 0.13.2", + "ic-certification", + "ic-transport-types", "reqwest", "schemars", "serde", "serde_bytes", + "serde_cbor", "serde_json", "sha2", + "slog", + "strum", + "strum_macros", + "thiserror 2.0.4", "tokio", "tracing", "tracing-appender", "tracing-subscriber", + "wslpath", ] [[package]] @@ -1751,6 +1942,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "precomputed-hash" version = "0.1.1" @@ -1765,41 +1965,123 @@ checksum = "b55c4d17d994b637e2f4daf6e5dc5d660d209d5642377d675d7a1c3ab69fa579" dependencies = [ "arrayvec", "typed-arena", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.21" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" dependencies = [ "cc", ] [[package]] -name = "quote" -version = "1.0.36" +name = "quinn" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ - "proc-macro2", + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.0", + "rustls", + "socket2", + "thiserror 2.0.4", + "tokio", + "tracing", ] [[package]] -name = "rayon" -version = "1.10.0" +name = "quinn-proto" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom", + "rand", + "ring", + "rustc-hash 2.1.0", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.4", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -1817,22 +2099,22 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1843,21 +2125,21 @@ checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" dependencies = [ "hashbrown 0.13.2", "log", - "rustc-hash", + "rustc-hash 1.1.0", "slice-group-by", "smallvec", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -1871,13 +2153,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax 0.8.5", ] [[package]] @@ -1888,15 +2170,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.4" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", @@ -1918,6 +2200,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "quinn", "rustls", "rustls-native-certs", "rustls-pemfile", @@ -1937,7 +2220,7 @@ dependencies = [ "wasm-streams", "web-sys", "webpki-roots", - "winreg", + "windows-registry", ] [[package]] @@ -1980,20 +2263,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags", "errno", @@ -2004,11 +2293,11 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.4" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ - "log", + "once_cell", "ring", "rustls-pki-types", "rustls-webpki", @@ -2018,12 +2307,11 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" dependencies = [ "openssl-probe", - "rustls-pemfile", "rustls-pki-types", "schannel", "security-framework", @@ -2031,25 +2319,27 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +dependencies = [ + "web-time", +] [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -2058,9 +2348,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -2079,11 +2369,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2107,7 +2397,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] @@ -2118,9 +2408,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.11.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "e1415a607e92bec364ea2cf9264646dcce0f91e6d65281bd6f2819cca3bf39c8" dependencies = [ "bitflags", "core-foundation", @@ -2131,9 +2421,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -2150,18 +2440,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.204" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] @@ -2178,13 +2468,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] @@ -2195,50 +2485,51 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] -name = "serde_spanned" -version = "0.6.5" +name = "serde_repr" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ - "serde", + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] -name = "serde_tokenstream" -version = "0.1.7" +name = "serde_spanned" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "797ba1d80299b264f3aac68ab5d12e5825a561749db4df7cd7c8083900c5d4e9" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ - "proc-macro2", "serde", - "syn 1.0.109", ] [[package]] name = "serde_tokenstream" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a00ffd23fd882d096f09fcaae2a9de8329a328628e86027e049ee051dc1621f" +checksum = "64060d864397305347a78851c51588fd283767e7e7589829e8121d65512340f1" dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] @@ -2273,6 +2564,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -2303,6 +2600,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" +[[package]] +name = "slog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" +dependencies = [ + "erased-serde", +] + [[package]] name = "slotmap" version = "1.0.7" @@ -2320,9 +2626,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -2348,15 +2654,15 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "stacker" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b" dependencies = [ "cc", "cfg-if", "libc", "psm", - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -2378,11 +2684,33 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.90", +] + [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2397,9 +2725,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.61" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -2408,15 +2736,35 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.2" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] [[package]] name = "target-lexicon" -version = "0.12.14" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "target-triple" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" [[package]] name = "term" @@ -2440,22 +2788,42 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" +dependencies = [ + "thiserror-impl 2.0.4", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] @@ -2470,9 +2838,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -2491,9 +2859,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -2508,11 +2876,21 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -2525,9 +2903,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -2549,14 +2927,14 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] name = "tokio-rustls" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ "rustls", "rustls-pki-types", @@ -2565,21 +2943,21 @@ dependencies = [ [[package]] name = "tokio-socks" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" +checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" dependencies = [ "either", "futures-util", - "thiserror", + "thiserror 1.0.69", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -2590,9 +2968,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", @@ -2602,18 +2980,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.12" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", @@ -2622,38 +3000,17 @@ dependencies = [ "winnow", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -2667,27 +3024,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" dependencies = [ "crossbeam-channel", - "thiserror", + "thiserror 1.0.69", "time", "tracing-subscriber", ] [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -2706,9 +3063,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" dependencies = [ "serde", "tracing-core", @@ -2716,9 +3073,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -2729,6 +3086,7 @@ dependencies = [ "sharded-slab", "smallvec", "thread_local", + "time", "tracing", "tracing-core", "tracing-log", @@ -2743,14 +3101,15 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddb747392ea12569d501a5bbca08852e4c8cd88b92566074b2243b8846f09e6" +checksum = "8dcd332a5496c026f1e14b7f3d2b7bd98e509660c04239c58b0ba38a12daded4" dependencies = [ "glob", "serde", "serde_derive", "serde_json", + "target-triple", "termcolor", "toml", ] @@ -2769,51 +3128,39 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] -name = "unicode-normalization" -version = "0.1.23" +name = "unicode-segmentation" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] -name = "unicode-segmentation" -version = "1.11.0" +name = "unicode-width" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -2823,26 +3170,38 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.8.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" [[package]] name = "valuable" @@ -2852,9 +3211,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -2883,46 +3242,48 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2930,22 +3291,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "wasm-encoder" @@ -2958,18 +3319,19 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.207.0" +version = "0.221.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d996306fb3aeaee0d9157adbe2f670df0236caf19f6728b221e92d0f27b3fe17" +checksum = "c17a3bd88f2155da63a1f2fcb8a56377a24f0b6dfed12733bb5f544e86f690c5" dependencies = [ "leb128", + "wasmparser 0.221.2", ] [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -2989,6 +3351,17 @@ dependencies = [ "semver", ] +[[package]] +name = "wasmparser" +version = "0.221.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9845c470a2e10b61dd42c385839cdd6496363ed63b5c9e420b5488b77bd22083" +dependencies = [ + "bitflags", + "indexmap", + "semver", +] + [[package]] name = "wasmprinter" version = "0.201.0" @@ -2996,7 +3369,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a67e66da702706ba08729a78e3c0079085f6bfcb1a62e4799e97bbf728c2c265" dependencies = [ "anyhow", - "wasmparser", + "wasmparser 0.201.0", ] [[package]] @@ -3005,7 +3378,7 @@ version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e300c0e3f19dc9064e3b17ce661088646c70dbdde36aab46470ed68ba58db7d" dependencies = [ - "addr2line", + "addr2line 0.21.0", "anyhow", "async-trait", "bincode", @@ -3013,12 +3386,12 @@ dependencies = [ "cfg-if", "encoding_rs", "fxprof-processed-profile", - "gimli", + "gimli 0.28.1", "indexmap", "ittapi", "libc", "log", - "object", + "object 0.32.2", "once_cell", "paste", "rayon", @@ -3029,7 +3402,7 @@ dependencies = [ "serde_json", "target-lexicon", "wasm-encoder 0.201.0", - "wasmparser", + "wasmparser 0.201.0", "wasmtime-cache", "wasmtime-component-macro", "wasmtime-component-util", @@ -3083,7 +3456,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser", @@ -3109,12 +3482,12 @@ dependencies = [ "cranelift-frontend", "cranelift-native", "cranelift-wasm", - "gimli", + "gimli 0.28.1", "log", - "object", + "object 0.32.2", "target-lexicon", - "thiserror", - "wasmparser", + "thiserror 1.0.69", + "wasmparser 0.201.0", "wasmtime-cranelift-shared", "wasmtime-environ", "wasmtime-versioned-export-macros", @@ -3130,8 +3503,8 @@ dependencies = [ "cranelift-codegen", "cranelift-control", "cranelift-native", - "gimli", - "object", + "gimli 0.28.1", + "object 0.32.2", "target-lexicon", "wasmtime-environ", ] @@ -3146,17 +3519,17 @@ dependencies = [ "bincode", "cpp_demangle", "cranelift-entity", - "gimli", + "gimli 0.28.1", "indexmap", "log", - "object", + "object 0.32.2", "rustc-demangle", "serde", "serde_derive", "target-lexicon", - "thiserror", + "thiserror 1.0.69", "wasm-encoder 0.201.0", - "wasmparser", + "wasmparser 0.201.0", "wasmprinter", "wasmtime-component-util", "wasmtime-types", @@ -3183,7 +3556,7 @@ version = "19.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92de34217bf7f0464262adf391a9950eba440f9dfc7d3b0e3209302875c6f65f" dependencies = [ - "object", + "object 0.32.2", "once_cell", "rustix", "wasmtime-versioned-export-macros", @@ -3245,8 +3618,8 @@ dependencies = [ "cranelift-entity", "serde", "serde_derive", - "thiserror", - "wasmparser", + "thiserror 1.0.69", + "wasmparser 0.201.0", ] [[package]] @@ -3257,7 +3630,7 @@ checksum = "ffaafa5c12355b1a9ee068e9295d50c4ca0a400c721950cdae4f5b54391a2da5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", ] [[package]] @@ -3268,10 +3641,10 @@ checksum = "d618b4e90d3f259b1b77411ce573c9f74aade561957102132e169918aabdc863" dependencies = [ "anyhow", "cranelift-codegen", - "gimli", - "object", + "gimli 0.28.1", + "object 0.32.2", "target-lexicon", - "wasmparser", + "wasmparser 0.201.0", "wasmtime-cranelift-shared", "wasmtime-environ", "winch-codegen", @@ -3297,31 +3670,41 @@ checksum = "c9a8c62e9df8322b2166d2a6f096fbec195ddb093748fd74170dcf25ef596769" [[package]] name = "wast" -version = "207.0.0" +version = "221.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e40be9fd494bfa501309487d2dc0b3f229be6842464ecbdc54eac2679c84c93" +checksum = "fcc4470b9de917ba199157d1f0ae104f2ae362be728c43e68c571c7715bd629e" dependencies = [ "bumpalo", "leb128", "memchr", - "unicode-width", - "wasm-encoder 0.207.0", + "unicode-width 0.2.0", + "wasm-encoder 0.221.2", ] [[package]] name = "wat" -version = "1.207.0" +version = "1.221.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb2b15e2d5f300f5e1209e7dc237f2549edbd4203655b6c6cab5cf180561ee7" +checksum = "6b1f3c6d82af47286494c6caea1d332037f5cbeeac82bbf5ef59cb8c201c466e" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -3329,9 +3712,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.1" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] @@ -3354,11 +3737,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3375,172 +3758,135 @@ checksum = "2d15869abc9e3bb29c017c003dbe007a08e9910e8ff9023a962aa13c1b2ee6af" dependencies = [ "anyhow", "cranelift-codegen", - "gimli", + "gimli 0.28.1", "regalloc2", "smallvec", "target-lexicon", - "wasmparser", + "wasmparser 0.201.0", "wasmtime-environ", ] [[package]] -name = "windows-sys" -version = "0.48.0" +name = "windows-registry" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-targets 0.48.5", + "windows-result", + "windows-strings", + "windows-targets", ] [[package]] -name = "windows-sys" -version = "0.52.0" +name = "windows-result" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets 0.52.5", + "windows-targets", ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-strings" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-result", + "windows-targets", ] [[package]] -name = "windows-targets" -version = "0.52.5" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows-targets", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" +name = "windows-targets" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] [[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +name = "windows_aarch64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "wit-parser" version = "0.201.0" @@ -3556,58 +3902,144 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser", + "wasmparser 0.201.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "wslpath" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04a2ecdf2cc4d33a6a93d71bcfbc00bb1f635cdb8029a2cc0709204a045ec7a3" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.90", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] [[package]] name = "zstd" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.1.0" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.10+zstd.1.5.6" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index a5b3262fe..2a83af579 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/dfinity/cdk-rs" # MSRV # Avoid updating this field unless we use new Rust features # Sync with rust-toolchain.toml -rust-version = "1.75.0" +rust-version = "1.78.0" license = "Apache-2.0" [profile.canister-release] diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index ac646bb3b..481978daa 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -53,4 +53,4 @@ path = "canisters/chunk.rs" [dev-dependencies] hex.workspace = true -pocket-ic = "4" +pocket-ic = { git = "https://github.com/dfinity/ic", tag = "release-2024-11-28_03-15-base" } diff --git a/e2e-tests/canisters/chunk.rs b/e2e-tests/canisters/chunk.rs index 8eb977cdf..9f387a6bd 100644 --- a/e2e-tests/canisters/chunk.rs +++ b/e2e-tests/canisters/chunk.rs @@ -10,7 +10,7 @@ use ic_cdk::update; async fn call_create_canister() -> Principal { let arg = CreateCanisterArgument::default(); - create_canister(arg, 200_000_000_000u128) + create_canister(arg, 1_000_000_000_000u128) .await .unwrap() .0 diff --git a/e2e-tests/canisters/management_caller.rs b/e2e-tests/canisters/management_caller.rs index 6c9ee51ba..ed7b87206 100644 --- a/e2e-tests/canisters/management_caller.rs +++ b/e2e-tests/canisters/management_caller.rs @@ -5,6 +5,7 @@ use ic_cdk::*; /// - chunk.rs mod main { use super::*; + use candid::Principal; use ic_cdk::api::management_canister::main::*; #[update] async fn execute_main_methods() { @@ -73,6 +74,13 @@ mod main { let response = raw_rand().await.unwrap().0; assert_eq!(response.len(), 32); } + + #[update] + async fn execute_subnet_info(subnet_id: Principal) { + let arg = SubnetInfoArgs { subnet_id }; + let response = subnet_info(arg).await.unwrap().0; + assert!(!response.replica_version.is_empty()); + } } mod provisional { diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 57268ae5f..bccfe9fa5 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -547,6 +547,9 @@ fn test_call_management() { let canister_id = pic.create_canister(); pic.add_cycles(canister_id, 300_000_000_000_000_000_000_000_000u128); pic.install_canister(canister_id, wasm, vec![], None); + let subnet_id = pic.topology().get_app_subnets()[0]; + let () = call_candid(&pic, canister_id, "execute_subnet_info", (subnet_id,)) + .expect("Error calling execute_subnet_info"); let () = call_candid(&pic, canister_id, "execute_main_methods", ()) .expect("Error calling execute_main_methods"); let () = call_candid(&pic, canister_id, "execute_provisional_methods", ()) diff --git a/library/ic-certified-map/src/rbtree.rs b/library/ic-certified-map/src/rbtree.rs index cccbd9668..5fcb2feab 100644 --- a/library/ic-certified-map/src/rbtree.rs +++ b/library/ic-certified-map/src/rbtree.rs @@ -1077,6 +1077,7 @@ fn is_balanced(root: &NodeRef) -> bool { go(root, num_black) } +#[allow(dead_code)] struct DebugView<'a, K, V>(&'a NodeRef); impl<'a, K: AsRef<[u8]>, V> fmt::Debug for DebugView<'a, K, V> { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 954f9d75d..1e64dc740 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.75.0" # sync with rust-version in root Cargo.toml +channel = "1.78.0" # sync with rust-version in root Cargo.toml targets = ["wasm32-unknown-unknown"] components = ["rustfmt", "clippy"] diff --git a/scripts/download_pocket_ic.sh b/scripts/download_pocket_ic.sh index b0191645c..6e2e9f589 100755 --- a/scripts/download_pocket_ic.sh +++ b/scripts/download_pocket_ic.sh @@ -9,7 +9,7 @@ cd "$SCRIPTS_DIR/../e2e-tests" uname_sys=$(uname -s | tr '[:upper:]' '[:lower:]') echo "uname_sys: $uname_sys" -tag="release-2024-08-02_01-30-base" +tag="release-2024-11-28_03-15-base" curl -sL "https://github.com/dfinity/ic/releases/download/$tag/pocket-ic-x86_64-$uname_sys.gz" --output pocket-ic.gz gzip -df pocket-ic.gz diff --git a/src/ic-cdk-timers/src/lib.rs b/src/ic-cdk-timers/src/lib.rs index 845958d40..b025f9f6a 100644 --- a/src/ic-cdk-timers/src/lib.rs +++ b/src/ic-cdk-timers/src/lib.rs @@ -38,7 +38,7 @@ use ic_cdk::api::call::RejectionCode; thread_local! { static TASKS: RefCell> = RefCell::default(); static TIMERS: RefCell> = RefCell::default(); - static MOST_RECENT: Cell> = Cell::new(None); + static MOST_RECENT: Cell> = const { Cell::new(None) }; } enum Task { diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 139f53f5d..de7a3dfe2 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +### Added + +- Support management canister method: `subnet_info`. (#532) + - Add types: `SubnetInfoArgs` and `SubnetInfoResult`. + ## [0.17.0] - 2024-11-04 ### Changed diff --git a/src/ic-cdk/src/api/management_canister/main/mod.rs b/src/ic-cdk/src/api/management_canister/main/mod.rs index 9f686c4f8..283608686 100644 --- a/src/ic-cdk/src/api/management_canister/main/mod.rs +++ b/src/ic-cdk/src/api/management_canister/main/mod.rs @@ -239,3 +239,10 @@ pub async fn delete_canister_snapshot(arg: DeleteCanisterSnapshotArgs) -> CallRe ) .await } + +/// Get subnet metadata. +/// +/// See [IC method `subnet_info`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-subnet-info). +pub async fn subnet_info(arg: SubnetInfoArgs) -> CallResult<(SubnetInfoResult,)> { + call(Principal::management_canister(), "subnet_info", (arg,)).await +} diff --git a/src/ic-cdk/src/api/management_canister/main/types.rs b/src/ic-cdk/src/api/management_canister/main/types.rs index 9eea37e81..3b9c701c9 100644 --- a/src/ic-cdk/src/api/management_canister/main/types.rs +++ b/src/ic-cdk/src/api/management_canister/main/types.rs @@ -628,3 +628,21 @@ pub struct DeleteCanisterSnapshotArgs { /// ID of the snapshot to be deleted. pub snapshot_id: SnapshotId, } + +/// Argument type of [subnet_info](super::subnet_info). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct SubnetInfoArgs { + /// Principal of the subnet. + pub subnet_id: Principal, +} + +/// Result type of [subnet_info](super::subnet_info). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, +)] +pub struct SubnetInfoResult { + /// Replica version of the subnet. + pub replica_version: String, +} From f6b9749d8f734ed6a3b1ece3236d4b7e2156a7f3 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Mon, 16 Dec 2024 10:04:45 -0800 Subject: [PATCH 233/234] Add bitcoin_get_block_headers (#537) --- src/ic-cdk/CHANGELOG.md | 1 + .../api/management_canister/bitcoin/mod.rs | 25 +++++++ .../api/management_canister/bitcoin/types.rs | 69 ++++++++++++++----- 3 files changed, 78 insertions(+), 17 deletions(-) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index de7a3dfe2..dd3515d8e 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Add method `bitcoin_get_block_headers`. - Support management canister method: `subnet_info`. (#532) - Add types: `SubnetInfoArgs` and `SubnetInfoResult`. diff --git a/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs b/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs index 4769f17ee..4571431ec 100644 --- a/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs +++ b/src/ic-cdk/src/api/management_canister/bitcoin/mod.rs @@ -23,6 +23,9 @@ const SEND_TRANSACTION_SUBMISSION_TESTNET: u128 = 2_000_000_000; const SEND_TRANSACTION_PAYLOAD_MAINNET: u128 = 20_000_000; const SEND_TRANSACTION_PAYLOAD_TESTNET: u128 = 8_000_000; +const GET_BLOCK_HEADERS_MAINNET: u128 = 4_000_000_000; +const GET_BLOCK_HEADERS_TESTNET: u128 = 4_000_000_000; + /// See [IC method `bitcoin_get_balance`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_get_balance). /// /// This call requires cycles payment. @@ -115,3 +118,25 @@ pub async fn bitcoin_get_current_fee_percentiles( ) .await } + +/// See [IC method `bitcoin_get_block_headers`](https://internetcomputer.org/docs/current/references/ic-interface-spec#ic-bitcoin_get_block_headers). +/// +/// This call requires cycles payment. +/// This method handles the cycles cost under the hood. +/// Check [API fees & Pricing](https://internetcomputer.org/docs/current/developer-docs/integrations/bitcoin/bitcoin-how-it-works/#api-fees--pricing) for more details. +pub async fn bitcoin_get_block_headers( + arg: GetBlockHeadersRequest, +) -> CallResult<(GetBlockHeadersResponse,)> { + let cycles = match arg.network { + BitcoinNetwork::Mainnet => GET_BLOCK_HEADERS_MAINNET, + BitcoinNetwork::Testnet => GET_BLOCK_HEADERS_TESTNET, + BitcoinNetwork::Regtest => 0, + }; + call_with_payment128( + Principal::management_canister(), + "bitcoin_get_block_headers", + (arg,), + cycles, + ) + .await +} diff --git a/src/ic-cdk/src/api/management_canister/bitcoin/types.rs b/src/ic-cdk/src/api/management_canister/bitcoin/types.rs index 776b45f16..6f84013ba 100644 --- a/src/ic-cdk/src/api/management_canister/bitcoin/types.rs +++ b/src/ic-cdk/src/api/management_canister/bitcoin/types.rs @@ -34,10 +34,10 @@ pub type BitcoinAddress = String; /// Block Hash. pub type BlockHash = Vec; -/// Element in the Response of [bitcoin_get_current_fee_percentiles](super::bitcoin_get_current_fee_percentiles). +/// Element in the Response of [`bitcoin_get_current_fee_percentiles`](super::bitcoin_get_current_fee_percentiles). pub type MillisatoshiPerByte = u64; -/// Identifier of [Utxo]. +/// Identifier of [`Utxo`]. #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, )] @@ -53,7 +53,7 @@ pub struct Outpoint { CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, )] pub struct Utxo { - /// See [Outpoint]. + /// See [`Outpoint`]. pub outpoint: Outpoint, /// Value in the units of satoshi. pub value: Satoshi, @@ -72,38 +72,38 @@ pub enum UtxoFilter { /// Page reference. /// /// DON'T construct it from scratch. - /// Only get it from the `next_page` field of [GetUtxosResponse]. + /// Only get it from the `next_page` field of [`GetUtxosResponse`]. #[serde(rename = "page")] Page(Vec), } -/// Argument type of [bitcoin_get_balance](super::bitcoin_get_balance). +/// Argument type of [`bitcoin_get_balance`](super::bitcoin_get_balance). #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, )] pub struct GetBalanceRequest { - /// See [BitcoinAddress]. + /// See [`BitcoinAddress`]. pub address: BitcoinAddress, - /// See [BitcoinNetwork]. + /// See [`BitcoinNetwork`]. pub network: BitcoinNetwork, /// Minimum number of confirmations. There is an upper bound of 144. Typically set to a value around 6 in practice. pub min_confirmations: Option, } -/// Argument type of [bitcoin_get_utxos](super::bitcoin_get_utxos). +/// Argument type of [`bitcoin_get_utxos`](super::bitcoin_get_utxos). #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, )] pub struct GetUtxosRequest { - /// See [BitcoinAddress]. + /// See [`BitcoinAddress`]. pub address: BitcoinAddress, - /// See [BitcoinNetwork]. + /// See [`BitcoinNetwork`]. pub network: BitcoinNetwork, - /// See [UtxoFilter]. + /// See [`UtxoFilter`]. pub filter: Option, } -/// Response type of [bitcoin_get_utxos](super::bitcoin_get_utxos). +/// Response type of [`bitcoin_get_utxos`](super::bitcoin_get_utxos). #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, )] @@ -116,11 +116,11 @@ pub struct GetUtxosResponse { pub tip_height: u32, /// Page reference when the response needs to be paginated. /// - /// To be used in [UtxoFilter::Page]. + /// To be used in [`UtxoFilter::Page`]. pub next_page: Option>, } -/// Argument type of [bitcoin_send_transaction](super::bitcoin_send_transaction). +/// Argument type of [`bitcoin_send_transaction`](super::bitcoin_send_transaction). #[derive( CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, )] @@ -130,11 +130,11 @@ pub struct SendTransactionRequest { /// Several checks are performed. /// See [IC method `bitcoin_send_transaction`](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-bitcoin_send_transaction). pub transaction: Vec, - /// See [BitcoinNetwork]. + /// See [`BitcoinNetwork`]. pub network: BitcoinNetwork, } -/// Argument type of [bitcoin_get_current_fee_percentiles](super::bitcoin_get_current_fee_percentiles). +/// Argument type of [`bitcoin_get_current_fee_percentiles`](super::bitcoin_get_current_fee_percentiles). #[derive( CandidType, Serialize, @@ -150,6 +150,41 @@ pub struct SendTransactionRequest { Default, )] pub struct GetCurrentFeePercentilesRequest { - /// See [BitcoinNetwork]. + /// See [`BitcoinNetwork`]. pub network: BitcoinNetwork, } + +/// Argument type of [`bitcoin_get_block_headers`](super::bitcoin_get_block_headers). +#[derive( + CandidType, + Serialize, + Deserialize, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Clone, + Copy, + Default, +)] +pub struct GetBlockHeadersRequest { + /// The starting block height for the request. + pub start_height: u32, + /// The ending block height for the request, or `None` for the current tip. + pub end_height: Option, + /// See [`BitcoinNetwork`]. + pub network: BitcoinNetwork, +} + +/// Response type of [`bitcoin_get_block_headers`](super::bitcoin_get_block_headers). +#[derive( + CandidType, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, +)] +pub struct GetBlockHeadersResponse { + /// The tip of the blockchain when this request was filled. + pub tip_height: u32, + /// The requested block headers. + pub block_headers: Vec>, +} From 929fd0b31e9ec69aad7cf6285df0394f25fe1815 Mon Sep 17 00:00:00 2001 From: Linwei Shang Date: Thu, 19 Dec 2024 13:36:20 -0500 Subject: [PATCH 234/234] chore: release ic-cdk v0.17.1 (#541) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- src/ic-cdk-macros/Cargo.toml | 2 +- src/ic-cdk/CHANGELOG.md | 2 ++ src/ic-cdk/Cargo.toml | 4 ++-- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 91d53be33..6dcb36591 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "ic-cdk" -version = "0.17.0" +version = "0.17.1" dependencies = [ "anyhow", "candid", @@ -1202,7 +1202,7 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.17.0" +version = "0.17.1" dependencies = [ "candid", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 2a83af579..b62810485 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ opt-level = 'z' [workspace.dependencies] ic0 = { path = "src/ic0", version = "0.23.0" } -ic-cdk = { path = "src/ic-cdk", version = "0.17.0" } +ic-cdk = { path = "src/ic-cdk", version = "0.17.1" } ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.11.0" } candid = "0.10.4" diff --git a/src/ic-cdk-macros/Cargo.toml b/src/ic-cdk-macros/Cargo.toml index c0723e860..b164000ac 100644 --- a/src/ic-cdk-macros/Cargo.toml +++ b/src/ic-cdk-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk-macros" -version = "0.17.0" # sync with ic-cdk +version = "0.17.1" # sync with ic-cdk authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index dd3515d8e..3e0525b3a 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.17.1] - 2024-12-19 + ### Added - Add method `bitcoin_get_block_headers`. diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 49397ec3d..d933df6b9 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.17.0" # sync with ic-cdk-macros +version = "0.17.1" # sync with ic-cdk-macros authors.workspace = true edition.workspace = true license.workspace = true @@ -27,7 +27,7 @@ ic0.workspace = true # Dependents won't accidentaly upgrading ic-cdk-macros only but not ic-cdk. # ic-cdk-macros is a hidden dependency, re-exported by ic-cdk. # It should not be included by users direcly. -ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.17.0" } +ic-cdk-macros = { path = "../ic-cdk-macros", version = "=0.17.1" } serde.workspace = true serde_bytes.workspace = true slotmap = { workspace = true, optional = true }