From 22f350031107b5456d8a33c6e54a83cf473cad40 Mon Sep 17 00:00:00 2001 From: Josh Ford Date: Thu, 21 Nov 2024 17:37:55 -0800 Subject: [PATCH 01/11] feat: add to devtools project workflow --- .github/workflows/add-to-devtools.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/add-to-devtools.yml diff --git a/.github/workflows/add-to-devtools.yml b/.github/workflows/add-to-devtools.yml new file mode 100644 index 000000000..35bd989f8 --- /dev/null +++ b/.github/workflows/add-to-devtools.yml @@ -0,0 +1,22 @@ +name: 'Add to DevTools Project' + +on: + issues: + types: + - opened + - reopened + pull_request: + types: + - opened + - reopened + +jobs: + add-to-project: + name: Add issue/PR to project + runs-on: ubuntu-latest + steps: + - uses: actions/add-to-project@v1.0.0 + with: + # add to DevTools Project #156 + project-url: https://github.com/orgs/near/projects/156 + github-token: ${{ secrets.GH_TOKEN }} From e0a9b54ba0a6507218be8f00ad7b6a1eaf9f89e6 Mon Sep 17 00:00:00 2001 From: Den <41162202+denbite@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:00:41 +0100 Subject: [PATCH 02/11] doc: examples for Near-related host functions (#1259) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: add examples for Near-related host functions * docs: resolve compilation errors in doctests * docs: add use case description to Storage API host functions along with reference to implementation repo example --------- Co-authored-by: dj8yf0μl <26653921+dj8yfo@users.noreply.github.com> --- near-sdk/src/environment/env.rs | 836 +++++++++++++++++++++++++++++++- 1 file changed, 831 insertions(+), 5 deletions(-) diff --git a/near-sdk/src/environment/env.rs b/near-sdk/src/environment/env.rs index e439318d4..462250df9 100644 --- a/near-sdk/src/environment/env.rs +++ b/near-sdk/src/environment/env.rs @@ -152,23 +152,59 @@ pub fn register_len(register_id: u64) -> Option { // # Context API # // ############### /// The id of the account that owns the current contract. +/// +/// # Examples +/// ``` +/// use near_sdk::env::current_account_id; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// assert_eq!(current_account_id(), AccountId::from_str("alice.near").unwrap()); +/// ``` pub fn current_account_id() -> AccountId { assert_valid_account_id(method_into_register!(current_account_id)) } /// The id of the account that either signed the original transaction or issued the initial /// cross-contract call. +/// +/// # Examples +/// ``` +/// use near_sdk::env::signer_account_id; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// assert_eq!(signer_account_id(), AccountId::from_str("bob.near").unwrap()); +/// ``` pub fn signer_account_id() -> AccountId { assert_valid_account_id(method_into_register!(signer_account_id)) } /// The public key of the account that did the signing. +/// +/// # Examples +/// ``` +/// use near_sdk::env::signer_account_pk; +/// use near_sdk::{PublicKey, CurveType}; +/// +/// let pk = PublicKey::from_parts(near_sdk::CurveType::ED25519, vec![0; 32]).unwrap(); +/// assert_eq!(signer_account_pk(), pk); +/// ``` pub fn signer_account_pk() -> PublicKey { PublicKey::try_from(method_into_register!(signer_account_pk)).unwrap_or_else(|_| abort()) } /// The id of the account that was the previous contract in the chain of cross-contract calls. /// If this is the first contract, it is equal to `signer_account_id`. +/// +/// # Examples +/// ``` +/// use near_sdk::env::predecessor_account_id; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// assert_eq!(predecessor_account_id(), AccountId::from_str("bob.near").unwrap()); +/// ``` pub fn predecessor_account_id() -> AccountId { assert_valid_account_id(method_into_register!(predecessor_account_id)) } @@ -182,37 +218,86 @@ fn assert_valid_account_id(bytes: Vec) -> AccountId { } /// The input to the contract call serialized as bytes. If input is not provided returns `None`. +/// +/// # Examples +/// ``` +/// use near_sdk::env::input; +/// +/// assert_eq!(input(), Some(Vec::new())); +/// ``` pub fn input() -> Option> { try_method_into_register!(input) } /// Current block index. +/// +/// # Examples +/// ``` +/// use near_sdk::env::block_index; +/// +/// assert_eq!(block_index(), 0); +/// ``` #[deprecated(since = "4.0.0", note = "Use block_height instead")] pub fn block_index() -> BlockHeight { block_height() } /// Returns the height of the block the transaction is being executed in. +/// +/// # Examples +/// ``` +/// use near_sdk::env::block_height; +/// +/// assert_eq!(block_height(), 0); +/// ``` pub fn block_height() -> BlockHeight { unsafe { sys::block_height() } } /// Current block timestamp, i.e, number of non-leap-nanoseconds since January 1, 1970 0:00:00 UTC. +/// +/// # Examples +/// ``` +/// use near_sdk::env::block_timestamp; +/// +/// assert_eq!(block_timestamp(), 0); +/// ``` pub fn block_timestamp() -> u64 { unsafe { sys::block_timestamp() } } /// Current block timestamp, i.e, number of non-leap-milliseconds since January 1, 1970 0:00:00 UTC. +/// +/// # Examples +/// ``` +/// use near_sdk::env::block_timestamp_ms; +/// +/// assert_eq!(block_timestamp_ms(), 0); +/// ``` pub fn block_timestamp_ms() -> u64 { block_timestamp() / 1_000_000 } /// Current epoch height. +/// +/// # Examples +/// ``` +/// use near_sdk::env::epoch_height; +/// +/// assert_eq!(epoch_height(), 0); +/// ``` pub fn epoch_height() -> u64 { unsafe { sys::epoch_height() } } /// Current total storage usage of this smart contract that this account would be paying for. +/// +/// # Examples +/// ``` +/// use near_sdk::env::storage_usage; +/// +/// assert_eq!(storage_usage(), 307200); +/// ``` pub fn storage_usage() -> StorageUsage { unsafe { sys::storage_usage() } } @@ -222,6 +307,14 @@ pub fn storage_usage() -> StorageUsage { // ################# /// The balance attached to the given account. This includes the attached_deposit that was /// attached to the transaction +/// +/// # Examples +/// ``` +/// use near_sdk::env::account_balance; +/// use near_sdk::NearToken; +/// +/// assert_eq!(account_balance(), NearToken::from_near(100)); +/// ``` pub fn account_balance() -> NearToken { let data = [0u8; size_of::()]; unsafe { sys::account_balance(data.as_ptr() as u64) }; @@ -229,6 +322,14 @@ pub fn account_balance() -> NearToken { } /// The balance locked for potential validator staking. +/// +/// # Examples +/// ``` +/// use near_sdk::env::account_locked_balance; +/// use near_sdk::NearToken; +/// +/// assert_eq!(account_locked_balance(), NearToken::from_yoctonear(0)); +/// ``` pub fn account_locked_balance() -> NearToken { let data = [0u8; size_of::()]; unsafe { sys::account_locked_balance(data.as_ptr() as u64) }; @@ -237,6 +338,14 @@ pub fn account_locked_balance() -> NearToken { /// The balance that was attached to the call that will be immediately deposited before the /// contract execution starts +/// +/// # Examples +/// ``` +/// use near_sdk::env::attached_deposit; +/// use near_sdk::NearToken; +/// +/// assert_eq!(attached_deposit(), NearToken::from_yoctonear(0)); +/// ``` pub fn attached_deposit() -> NearToken { let data = [0u8; size_of::()]; unsafe { sys::attached_deposit(data.as_ptr() as u64) }; @@ -244,11 +353,27 @@ pub fn attached_deposit() -> NearToken { } /// The amount of gas attached to the call that can be used to pay for the gas fees. +/// +/// # Examples +/// ``` +/// use near_sdk::env::prepaid_gas; +/// use near_sdk::Gas; +/// +/// assert_eq!(prepaid_gas(), Gas::from_tgas(300)); +/// ``` pub fn prepaid_gas() -> Gas { Gas::from_gas(unsafe { sys::prepaid_gas() }) } /// The gas that was already burnt during the contract execution (cannot exceed `prepaid_gas`) +/// +/// # Examples +/// ``` +/// use near_sdk::env::used_gas; +/// use near_sdk::Gas; +/// +/// assert_eq!(used_gas(), Gas::from_gas(264768111)); +/// ``` pub fn used_gas() -> Gas { Gas::from_gas(unsafe { sys::used_gas() }) } @@ -260,6 +385,13 @@ pub fn used_gas() -> Gas { /// Returns the random seed from the current block. This 32 byte hash is based on the VRF value from /// the block. This value is not modified in any way each time this function is called within the /// same method/block. +/// +/// # Examples +/// ``` +/// use near_sdk::env::random_seed; +/// +/// assert_eq!(random_seed(), vec![0; 32]); +/// ``` pub fn random_seed() -> Vec { random_seed_array().to_vec() } @@ -326,7 +458,6 @@ pub fn random_seed_array() -> [u8; 32] { /// Hashes the random sequence of bytes using sha256. /// /// # Examples -/// /// ``` /// use near_sdk::env::sha256; /// use hex; @@ -341,11 +472,35 @@ pub fn sha256(value: &[u8]) -> Vec { } /// Hashes the random sequence of bytes using keccak256. +/// +/// # Examples +/// ``` +/// use near_sdk::env::keccak256; +/// use hex; +/// +/// assert_eq!( +/// keccak256(b"The phrase that will be hashed"), +/// hex::decode("b244af9dd4aada2eda59130bbcff112f29b427d924b654aaeb5a0384fa9afed4") +/// .expect("Decoding failed") +/// ); +/// ``` pub fn keccak256(value: &[u8]) -> Vec { keccak256_array(value).to_vec() } /// Hashes the random sequence of bytes using keccak512. +/// +/// # Examples +/// ``` +/// use near_sdk::env::keccak512; +/// use hex; +/// +/// assert_eq!( +/// keccak512(b"The phrase that will be hashed"), +/// hex::decode("29a7df7b889a443fdfbd769adb57ef7e98e6159187b582baba778c06e8b41a75f61367257e8c525a95b3f13ddf432f115d1df128a910c8fc93221db136d92b31") +/// .expect("Decoding failed") +/// ); +/// ``` pub fn keccak512(value: &[u8]) -> Vec { keccak512_array(value).to_vec() } @@ -353,7 +508,6 @@ pub fn keccak512(value: &[u8]) -> Vec { /// Hashes the bytes using the SHA-256 hash function. This returns a 32 byte hash. /// /// # Examples -/// /// ``` /// use near_sdk::env::sha256_array; /// use hex; @@ -376,6 +530,19 @@ pub fn sha256_array(value: &[u8]) -> [u8; 32] { } /// Hashes the bytes using the Keccak-256 hash function. This returns a 32 byte hash. +/// +/// # Examples +/// ``` +/// use near_sdk::env::keccak256_array; +/// use hex; +/// +/// assert_eq!( +/// &keccak256_array(b"The phrase that will be hashed"), +/// hex::decode("b244af9dd4aada2eda59130bbcff112f29b427d924b654aaeb5a0384fa9afed4") +/// .expect("Decoding failed") +/// .as_slice() +/// ); +/// ``` pub fn keccak256_array(value: &[u8]) -> [u8; 32] { //* SAFETY: keccak256 syscall will always generate 32 bytes inside of the atomic op register //* so the read will have a sufficient buffer of 32, and can transmute from uninit @@ -387,6 +554,19 @@ pub fn keccak256_array(value: &[u8]) -> [u8; 32] { } /// Hashes the bytes using the Keccak-512 hash function. This returns a 64 byte hash. +/// +/// # Examples +/// ``` +/// use near_sdk::env::keccak512_array; +/// use hex; +/// +/// assert_eq!( +/// &keccak512_array(b"The phrase that will be hashed"), +/// hex::decode("29a7df7b889a443fdfbd769adb57ef7e98e6159187b582baba778c06e8b41a75f61367257e8c525a95b3f13ddf432f115d1df128a910c8fc93221db136d92b31") +/// .expect("Decoding failed") +/// .as_slice() +/// ); +/// ``` pub fn keccak512_array(value: &[u8]) -> [u8; 64] { //* SAFETY: keccak512 syscall will always generate 64 bytes inside of the atomic op register //* so the read will have a sufficient buffer of 64, and can transmute from uninit @@ -398,6 +578,19 @@ pub fn keccak512_array(value: &[u8]) -> [u8; 64] { } /// Hashes the bytes using the RIPEMD-160 hash function. This returns a 20 byte hash. +/// +/// # Examples +/// ``` +/// use near_sdk::env::ripemd160_array; +/// use hex; +/// +/// assert_eq!( +/// &ripemd160_array(b"The phrase that will be hashed"), +/// hex::decode("9a48b9195fcb14cfe6051c0a1be7882efcadaed8") +/// .expect("Decoding failed") +/// .as_slice() +/// ); +/// ``` pub fn ripemd160_array(value: &[u8]) -> [u8; 20] { //* SAFETY: ripemd160 syscall will always generate 20 bytes inside of the atomic op register //* so the read will have a sufficient buffer of 20, and can transmute from uninit @@ -441,6 +634,46 @@ pub fn ecrecover( } /// Verifies signature of message using provided ED25519 Public Key +/// +/// # Examples +/// ``` +/// use near_sdk::env::ed25519_verify; +/// use hex; +/// +/// assert_eq!( +/// ed25519_verify( +/// hex::decode("41C44494DAB13009BE73D2CCBD3A49677DDC1F26AD2823CE72833CE4B9603F77CA70A9E179272D92D28E8B2AE7006747C87AB1890362A50347EFF553F5EC4008") +/// .expect("Decoding failed") +/// .as_slice() +/// .try_into() +/// .unwrap(), +/// b"Hello world!", +/// hex::decode("9C16937BF04CCE709FED52344C43634F1E7A05FC29DD41F48844C3588C7FE663") +/// .expect("Decoding failed") +/// .as_slice() +/// .try_into() +/// .unwrap(), +/// ), +/// true +/// ); +/// +/// assert_eq!( +/// ed25519_verify( +/// hex::decode("41C44494DAB13009BE73D2CCBD3A49677DDC1F26AD2823CE72833CE4B9603F77CA70A9E179272D92D28E8B2AE7006747C87AB1890362A50347EFF553F5EC4008") +/// .expect("Decoding failed") +/// .as_slice() +/// .try_into() +/// .unwrap(), +/// b"Modified message!", +/// hex::decode("9C16937BF04CCE709FED52344C43634F1E7A05FC29DD41F48844C3588C7FE663") +/// .expect("Decoding failed") +/// .as_slice() +/// .try_into() +/// .unwrap(), +/// ), +/// false +/// ); +/// ``` pub fn ed25519_verify(signature: &[u8; 64], message: &[u8], public_key: &[u8; 32]) -> bool { unsafe { sys::ed25519_verify( @@ -500,6 +733,24 @@ pub fn alt_bn128_pairing_check(value: &[u8]) -> bool { // ################ /// Creates a promise that will execute a method on account with given arguments and attaches /// the given amount and gas. +/// +/// # Examples +/// ``` +/// use near_sdk::env::promise_create; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas}; +/// use std::str::FromStr; +/// +/// let promise = promise_create( +/// AccountId::from_str("counter.near").unwrap(), +/// "increment", +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30) +/// ); +/// ``` pub fn promise_create( account_id: AccountId, function_name: &str, @@ -523,6 +774,35 @@ pub fn promise_create( } /// Attaches the callback that is executed after promise pointed by `promise_idx` is complete. +/// +/// # Examples +/// ``` +/// use near_sdk::env::{promise_create, promise_then}; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas}; +/// use std::str::FromStr; +/// +/// let promise = promise_create( +/// AccountId::from_str("counter.near").unwrap(), +/// "increment", +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30) +/// ); +/// +/// let chained_promise = promise_then( +/// promise, +/// AccountId::from_str("greetings.near").unwrap(), +/// "set_greeting", +/// serde_json::json!({ +/// "text": "Hello World" +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(4000000000000), +/// Gas::from_tgas(30) +/// ); +/// ``` pub fn promise_then( promise_idx: PromiseIndex, account_id: AccountId, @@ -548,6 +828,36 @@ pub fn promise_then( } /// Creates a new promise which completes when time all promises passed as arguments complete. +/// +/// # Examples +/// ``` +/// use near_sdk::env::{promise_create, promise_and}; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas}; +/// use std::str::FromStr; +/// +/// let promise1 = promise_create( +/// AccountId::from_str("counter.near").unwrap(), +/// "increment", +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30) +/// ); +/// +/// let promise2 = promise_create( +/// AccountId::from_str("greetings.near").unwrap(), +/// "set_greeting", +/// serde_json::json!({ +/// "text": "Hello World" +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(4000000000000), +/// Gas::from_tgas(30) +/// ); +/// +/// let chained_promise = promise_and(&[promise1, promise2]); +/// ``` pub fn promise_and(promise_indices: &[PromiseIndex]) -> PromiseIndex { let mut data = vec![0u8; size_of_val(promise_indices)]; for i in 0..promise_indices.len() { @@ -557,6 +867,16 @@ pub fn promise_and(promise_indices: &[PromiseIndex]) -> PromiseIndex { unsafe { PromiseIndex(sys::promise_and(data.as_ptr() as _, promise_indices.len() as _)) } } +/// # Examples +/// ``` +/// use near_sdk::env::promise_batch_create; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// ``` pub fn promise_batch_create(account_id: &AccountId) -> PromiseIndex { let account_id: &str = account_id.as_ref(); unsafe { @@ -564,6 +884,28 @@ pub fn promise_batch_create(account_id: &AccountId) -> PromiseIndex { } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_then, promise_create}; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas}; +/// use std::str::FromStr; +/// +/// let promise = promise_create( +/// AccountId::from_str("counter.near").unwrap(), +/// "increment", +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30) +/// ); +/// +/// let new_promise = promise_batch_then( +/// promise, +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// ``` pub fn promise_batch_then(promise_index: PromiseIndex, account_id: &AccountId) -> PromiseIndex { let account_id: &str = account_id.as_ref(); unsafe { @@ -575,10 +917,35 @@ pub fn promise_batch_then(promise_index: PromiseIndex, account_id: &AccountId) - } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_create_account, promise_batch_create}; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("new_account.near").unwrap() +/// ); +/// +/// promise_batch_action_create_account(promise); +/// ``` pub fn promise_batch_action_create_account(promise_index: PromiseIndex) { unsafe { sys::promise_batch_action_create_account(promise_index.0) } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_deploy_contract, promise_batch_create}; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("contract.near").unwrap() +/// ); +/// +/// let code = [0; 1487]; +/// promise_batch_action_deploy_contract(promise, &code); +/// ``` pub fn promise_batch_action_deploy_contract(promise_index: PromiseIndex, code: &[u8]) { unsafe { sys::promise_batch_action_deploy_contract( @@ -589,6 +956,25 @@ pub fn promise_batch_action_deploy_contract(promise_index: PromiseIndex, code: & } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_function_call, promise_batch_create}; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("counter.near").unwrap() +/// ); +/// +/// promise_batch_action_function_call( +/// promise, +/// "increase", +/// serde_json::json!({ "value": 5 }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30) +/// ); +/// ``` pub fn promise_batch_action_function_call( promise_index: PromiseIndex, function_name: &str, @@ -609,6 +995,26 @@ pub fn promise_batch_action_function_call( } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_function_call_weight, promise_batch_create}; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas, GasWeight}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("counter.near").unwrap() +/// ); +/// +/// promise_batch_action_function_call_weight( +/// promise, +/// "increase", +/// serde_json::json!({ "value": 5 }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30), +/// GasWeight(1) +/// ); +/// ``` pub fn promise_batch_action_function_call_weight( promise_index: PromiseIndex, function_name: &str, @@ -631,6 +1037,21 @@ pub fn promise_batch_action_function_call_weight( } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_transfer, promise_batch_create}; +/// use near_sdk::{NearToken, AccountId}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// promise_batch_action_transfer( +/// promise, +/// NearToken::from_near(1), +/// ); +/// ``` pub fn promise_batch_action_transfer(promise_index: PromiseIndex, amount: NearToken) { unsafe { sys::promise_batch_action_transfer( @@ -640,6 +1061,23 @@ pub fn promise_batch_action_transfer(promise_index: PromiseIndex, amount: NearTo } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_stake, promise_batch_create}; +/// use near_sdk::{NearToken, PublicKey, AccountId}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// let pk: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj".parse().unwrap(); +/// promise_batch_action_stake( +/// promise, +/// NearToken::from_near(1), +/// &pk +/// ); +/// ``` pub fn promise_batch_action_stake( promise_index: PromiseIndex, amount: NearToken, @@ -654,6 +1092,25 @@ pub fn promise_batch_action_stake( ) } } + +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_add_key_with_full_access, promise_batch_create}; +/// use near_sdk::{PublicKey, AccountId}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// let pk: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj".parse().unwrap(); +/// let nonce = 55; +/// promise_batch_action_add_key_with_full_access( +/// promise, +/// &pk, +/// nonce +/// ); +/// ``` pub fn promise_batch_action_add_key_with_full_access( promise_index: PromiseIndex, public_key: &PublicKey, @@ -674,6 +1131,27 @@ pub(crate) fn migrate_to_allowance(allowance: NearToken) -> Allowance { Allowance::limited(allowance).unwrap_or(Allowance::Unlimited) } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_add_key_with_function_call, promise_batch_create}; +/// use near_sdk::{PublicKey, AccountId, NearToken}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// let pk: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj".parse().unwrap(); +/// let nonce = 55; +/// promise_batch_action_add_key_with_function_call( +/// promise, +/// &pk, +/// nonce, +/// NearToken::from_near(1), +/// &AccountId::from_str("counter.near").unwrap(), +/// "increase,decrease" +/// ); +/// ``` #[deprecated(since = "5.0.0", note = "Use add_access_key_allowance instead")] pub fn promise_batch_action_add_key_with_function_call( promise_index: PromiseIndex, @@ -694,6 +1172,50 @@ pub fn promise_batch_action_add_key_with_function_call( ) } +/// # Examples +/// Unlimited allowance +/// ``` +/// use near_sdk::env::{promise_batch_action_add_key_allowance_with_function_call, promise_batch_create}; +/// use near_sdk::{PublicKey, AccountId, Allowance}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// let pk: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj".parse().unwrap(); +/// let nonce = 55; +/// promise_batch_action_add_key_allowance_with_function_call( +/// promise, +/// &pk, +/// nonce, +/// Allowance::unlimited(), +/// &AccountId::from_str("counter.near").unwrap(), +/// "increase,decrease" +/// ); +/// ``` +/// +/// Limited allowance (1 NEAR) +/// ``` +/// use near_sdk::env::{promise_batch_action_add_key_allowance_with_function_call, promise_batch_create}; +/// use near_sdk::{PublicKey, AccountId, Allowance, NearToken}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// let pk: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj".parse().unwrap(); +/// let nonce = 55; +/// promise_batch_action_add_key_allowance_with_function_call( +/// promise, +/// &pk, +/// nonce, +/// Allowance::limited(NearToken::from_near(1)).unwrap(), +/// &AccountId::from_str("counter.near").unwrap(), +/// "increase,decrease" +/// ); +/// ``` pub fn promise_batch_action_add_key_allowance_with_function_call( promise_index: PromiseIndex, public_key: &PublicKey, @@ -721,6 +1243,23 @@ pub fn promise_batch_action_add_key_allowance_with_function_call( ) } } + +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_delete_key, promise_batch_create}; +/// use near_sdk::{PublicKey, AccountId}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// let pk: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj".parse().unwrap(); +/// promise_batch_action_delete_key( +/// promise, +/// &pk +/// ); +/// ``` pub fn promise_batch_action_delete_key(promise_index: PromiseIndex, public_key: &PublicKey) { unsafe { sys::promise_batch_action_delete_key( @@ -731,6 +1270,21 @@ pub fn promise_batch_action_delete_key(promise_index: PromiseIndex, public_key: } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_delete_account, promise_batch_create}; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// promise_batch_action_delete_account( +/// promise, +/// &AccountId::from_str("beneficiary.near").unwrap() +/// ); +/// ``` pub fn promise_batch_action_delete_account( promise_index: PromiseIndex, beneficiary_id: &AccountId, @@ -748,11 +1302,41 @@ pub fn promise_batch_action_delete_account( /// If the current function is invoked by a callback we can access the execution results of the /// promises that caused the callback. This function returns the number of complete and /// incomplete callbacks. +/// +/// # Examples +/// ``` +/// use near_sdk::env::promise_results_count; +/// +/// assert_eq!(promise_results_count(), 0); +/// ``` pub fn promise_results_count() -> u64 { unsafe { sys::promise_results_count() } } /// If the current function is invoked by a callback we can access the execution results of the /// promises that caused the callback. +/// +/// # Examples +/// ```no_run +/// use near_sdk::env::{promise_result, promise_results_count, log_str}; +/// use near_sdk::PromiseResult; +/// +/// assert!(promise_results_count() > 0); +/// +/// // The promise_index will be in the range [0, n) +/// // where n is the number of promises triggering this callback, +/// // retrieved from promise_results_count() +/// let promise_index = 0; +/// let result = promise_result(promise_index); +/// +/// match result { +/// PromiseResult::Successful(data) => { +/// log_str(format!("Result as Vec: {:?}", data).as_str()); +/// } +/// PromiseResult::Failed => { +/// log_str("Promise failed!"); +/// } +/// }; +/// ``` pub fn promise_result(result_idx: u64) -> PromiseResult { match promise_result_internal(result_idx) { Ok(()) => { @@ -770,8 +1354,29 @@ pub(crate) fn promise_result_internal(result_idx: u64) -> Result<(), PromiseErro _ => abort(), } } + /// Consider the execution result of promise under `promise_idx` as execution result of this /// function. +/// +/// # Examples +/// ``` +/// use near_sdk::env::{promise_create, promise_return}; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas}; +/// use std::str::FromStr; +/// +/// let promise = promise_create( +/// AccountId::from_str("counter.near").unwrap(), +/// "increment", +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30) +/// ); +/// +/// promise_return(promise); +/// ``` pub fn promise_return(promise_idx: PromiseIndex) { unsafe { sys::promise_return(promise_idx.0) } } @@ -786,6 +1391,42 @@ pub fn promise_return(promise_idx: PromiseIndex) { /// /// Resumption tokens are specific to the local account; promise_yield_resume must be called from /// a method of the same contract. +/// +/// # Examples +/// ```no_run +/// use near_sdk::env::{promise_yield_create, promise_yield_resume, read_register}; +/// use near_sdk::serde_json; +/// use near_sdk::{Gas, GasWeight, CryptoHash}; +/// +/// let DATA_ID_REGISTER = 0; +/// // Create yield promise +/// let promise = promise_yield_create( +/// "increment", +/// // passed as arguments +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// Gas::from_tgas(10), +/// GasWeight(0), +/// DATA_ID_REGISTER +/// ); +/// +/// // Retrieve `data_id` for further resume +/// let data_id: CryptoHash = read_register(DATA_ID_REGISTER) +/// .expect("read_register failed") +/// .try_into() +/// .expect("conversion to CryptoHash failed"); +/// +/// // Resume execution using previously retrieved `data_id` +/// promise_yield_resume( +/// &data_id, +/// // passed as callback_result +/// serde_json::json!({ +/// "key": "value", +/// "description": "some text" +/// }).to_string().into_bytes().as_slice() +/// ); +/// ``` pub fn promise_yield_create( function_name: &str, arguments: &[u8], @@ -814,6 +1455,42 @@ pub fn promise_yield_create( /// If promise_yield_resume is called multiple times with the same `data_id`, it is possible to get /// back multiple 'true' results. The payload from the first successful call is passed to the /// callback. +/// +/// # Examples +/// ```no_run +/// use near_sdk::env::{promise_yield_create, promise_yield_resume, read_register}; +/// use near_sdk::serde_json; +/// use near_sdk::{Gas, GasWeight, CryptoHash}; +/// +/// let DATA_ID_REGISTER = 0; +/// // Create yield promise +/// let promise = promise_yield_create( +/// "increment", +/// // passed as arguments +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// Gas::from_tgas(10), +/// GasWeight(0), +/// DATA_ID_REGISTER +/// ); +/// +/// // Retrieve `data_id` for further resume +/// let data_id: CryptoHash = read_register(DATA_ID_REGISTER) +/// .expect("read_register failed") +/// .try_into() +/// .expect("conversion to CryptoHash failed"); +/// +/// // Resume execution using previously retrieved `data_id` +/// promise_yield_resume( +/// &data_id, +/// // passed as callback_result +/// serde_json::json!({ +/// "key": "value", +/// "description": "some text" +/// }).to_string().into_bytes().as_slice() +/// ); +/// ``` pub fn promise_yield_resume(data_id: &CryptoHash, data: &[u8]) -> bool { unsafe { sys::promise_yield_resume( @@ -830,6 +1507,18 @@ pub fn promise_yield_resume(data_id: &CryptoHash, data: &[u8]) -> bool { // ############### /// For a given account return its current stake. If the account is not a validator, returns 0. +/// +/// # Examples +/// ``` +/// use near_sdk::env::validator_stake; +/// use near_sdk::{AccountId, NearToken}; +/// use std::str::FromStr; +/// +/// assert_eq!( +/// validator_stake(&AccountId::from_str("bob.near").unwrap()), +/// NearToken::from_yoctonear(0) +/// ); +/// ``` pub fn validator_stake(account_id: &AccountId) -> NearToken { let account_id: &str = account_id.as_ref(); let data = [0u8; size_of::()]; @@ -840,6 +1529,17 @@ pub fn validator_stake(account_id: &AccountId) -> NearToken { } /// Returns the total stake of validators in the current epoch. +/// +/// # Examples +/// ``` +/// use near_sdk::env::validator_total_stake; +/// use near_sdk::NearToken; +/// +/// assert_eq!( +/// validator_total_stake(), +/// NearToken::from_yoctonear(0) +/// ); +/// ``` pub fn validator_total_stake() -> NearToken { let data = [0u8; size_of::()]; unsafe { sys::validator_total_stake(data.as_ptr() as u64) }; @@ -850,23 +1550,70 @@ pub fn validator_total_stake() -> NearToken { // # Miscellaneous API # // ##################### /// Sets the blob of data as the return value of the contract. +/// +/// # Examples +/// ``` +/// use near_sdk::env::value_return; +/// +/// value_return(b"String data"); +/// ``` +/// ``` +/// use near_sdk::env::value_return; +/// use near_sdk::serde_json; +/// +/// value_return( +/// serde_json::json!({ +/// "account": "test.near", +/// "value": 5 +/// }).to_string().into_bytes().as_slice() +/// ); +/// ``` pub fn value_return(value: &[u8]) { unsafe { sys::value_return(value.len() as _, value.as_ptr() as _) } } /// Terminates the execution of the program with the UTF-8 encoded message. /// [`panic_str`] should be used as the bytes are required to be UTF-8 +/// +/// # Examples +/// ```should_panic +/// use near_sdk::env::panic; +/// +/// panic(b"Unexpected error"); +/// ``` #[deprecated(since = "4.0.0", note = "Use env::panic_str to panic with a message.")] pub fn panic(message: &[u8]) -> ! { unsafe { sys::panic_utf8(message.len() as _, message.as_ptr() as _) } } /// Terminates the execution of the program with the UTF-8 encoded message. +/// +/// # Examples +/// ```should_panic +/// use near_sdk::env::panic_str; +/// +/// panic_str("Unexpected error"); +/// ``` +/// ```should_panic +/// use near_sdk::env::panic_str; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// let account = AccountId::from_str("bob.near").unwrap(); +/// panic_str(format!("Unexpected error happened for account {}", account).as_str()); +/// ``` pub fn panic_str(message: &str) -> ! { unsafe { sys::panic_utf8(message.len() as _, message.as_ptr() as _) } } /// Aborts the current contract execution without a custom message. /// To include a message, use [`panic_str`]. +/// +/// # Examples +/// ```should_panic +/// use near_sdk::env::abort; +/// +/// abort(); +/// ``` pub fn abort() -> ! { // Use wasm32 unreachable call to avoid including the `panic` external function in Wasm. #[cfg(target_arch = "wasm32")] @@ -882,6 +1629,19 @@ pub fn abort() -> ! { } /// Logs the string message message. This message is stored on chain. +/// +/// # Examples +/// ``` +/// use near_sdk::env::log_str; +/// +/// log_str("Some text"); +/// ``` +/// ``` +/// use near_sdk::env::log_str; +/// +/// let number = 5; +/// log_str(format!("Number: {}", number).as_str()); +/// ``` pub fn log_str(message: &str) { #[cfg(all(debug_assertions, not(target_arch = "wasm32")))] eprintln!("{}", message); @@ -890,6 +1650,13 @@ pub fn log_str(message: &str) { } /// Log the UTF-8 encodable message. +/// +/// # Examples +/// ``` +/// use near_sdk::env::log; +/// +/// log(b"Text"); +/// ``` #[deprecated(since = "4.0.0", note = "Use env::log_str for logging messages.")] pub fn log(message: &[u8]) { #[cfg(all(debug_assertions, not(target_arch = "wasm32")))] @@ -904,8 +1671,11 @@ pub fn log(message: &[u8]) { /// Writes key-value into storage. /// If another key-value existed in the storage with the same key it returns `true`, otherwise `false`. /// -/// # Examples +/// # Use cases +/// Storage functions are typically used to upgrade/migrate a contract state, preventing errors like `Cannot deserialize the contract state` after rolling out the breaking changes to the network. +/// For practical examples, see different implementations in [this repository](https://github.com/near-examples/update-migrate-rust). /// +/// # Examples /// ``` /// use near_sdk::env::{storage_write, storage_read}; /// @@ -930,8 +1700,11 @@ pub fn storage_write(key: &[u8], value: &[u8]) -> bool { } /// Reads the value stored under the given key. /// -/// # Examples +/// # Use cases +/// Storage functions are typically used to upgrade/migrate a contract state, preventing errors like `Cannot deserialize the contract state` after rolling out the breaking changes to the network. +/// For practical examples, see different implementations in [this repository](https://github.com/near-examples/update-migrate-rust). /// +/// # Examples /// ``` /// use near_sdk::env::{storage_write, storage_read}; /// @@ -948,6 +1721,19 @@ pub fn storage_read(key: &[u8]) -> Option> { } /// Removes the value stored under the given key. /// If key-value existed returns `true`, otherwise `false`. +/// +/// # Use cases +/// Storage functions are typically used to upgrade/migrate a contract state, preventing errors like `Cannot deserialize the contract state` after rolling out the breaking changes to the network. +/// For practical examples, see different implementations in [this repository](https://github.com/near-examples/update-migrate-rust). +/// +/// # Examples +/// ``` +/// use near_sdk::env::{storage_write, storage_remove}; +/// +/// assert_eq!(storage_remove(b"key"), false); +/// storage_write(b"key", b"value"); +/// assert_eq!(storage_remove(b"key"), true); +/// ``` pub fn storage_remove(key: &[u8]) -> bool { match unsafe { sys::storage_remove(key.len() as _, key.as_ptr() as _, EVICTED_REGISTER) } { 0 => false, @@ -956,10 +1742,34 @@ pub fn storage_remove(key: &[u8]) -> bool { } } /// Reads the most recent value that was evicted with `storage_write` or `storage_remove` command. +/// +/// # Use cases +/// Storage functions are typically used to upgrade/migrate a contract state, preventing errors like `Cannot deserialize the contract state` after rolling out the breaking changes to the network. +/// For practical examples, see different implementations in [this repository](https://github.com/near-examples/update-migrate-rust). +/// +/// # Examples +/// ``` +/// use near_sdk::env::{storage_write, storage_remove, storage_get_evicted}; +/// +/// assert_eq!(storage_get_evicted(), None); +/// ``` pub fn storage_get_evicted() -> Option> { read_register(EVICTED_REGISTER) } /// Checks if there is a key-value in the storage. +/// +/// # Use cases +/// Storage functions are typically used to upgrade/migrate a contract state, preventing errors like `Cannot deserialize the contract state` after rolling out the breaking changes to the network. +/// For practical examples, see different implementations in [this repository](https://github.com/near-examples/update-migrate-rust). +/// +/// # Examples +/// ``` +/// use near_sdk::env::{storage_write, storage_has_key}; +/// +/// assert_eq!(storage_has_key(b"key"), false); +/// storage_write(b"key", b"value"); +/// assert_eq!(storage_has_key(b"key"), true); +/// ``` pub fn storage_has_key(key: &[u8]) -> bool { match unsafe { sys::storage_has_key(key.len() as _, key.as_ptr() as _) } { 0 => false, @@ -996,7 +1806,14 @@ pub fn state_exists() -> bool { /// Price per 1 byte of storage from mainnet genesis config. /// TODO: will be using the host function when it will be available. - +/// +/// # Examples +/// ``` +/// use near_sdk::env::storage_byte_cost; +/// use near_sdk::NearToken; +/// +/// assert_eq!(storage_byte_cost(), NearToken::from_yoctonear(10000000000000000000)); +/// ``` pub fn storage_byte_cost() -> NearToken { NearToken::from_yoctonear(10_000_000_000_000_000_000u128) } @@ -1006,6 +1823,15 @@ pub fn storage_byte_cost() -> NearToken { // ################## /// Returns `true` if the given account ID is valid and `false` otherwise. +/// +/// # Examples +/// +/// ``` +/// use near_sdk::env::is_valid_account_id; +/// +/// assert_eq!(is_valid_account_id(b"test.near"), true); +/// assert_eq!(is_valid_account_id(b"test!.%.near"), false); +/// ``` pub fn is_valid_account_id(account_id: &[u8]) -> bool { if (account_id.len() as u64) < MIN_ACCOUNT_ID_LEN || (account_id.len() as u64) > MAX_ACCOUNT_ID_LEN From d7c16c84893fda00e4d34ba94b43f503050ca9e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dj8yf0=CE=BCl?= <26653921+dj8yfo@users.noreply.github.com> Date: Thu, 28 Nov 2024 19:57:37 +0200 Subject: [PATCH 03/11] ci: allow clippy::needless_lifetimes (1.83 more suggestions) (#1267) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: dj8yf0μl --- near-contract-standards/src/lib.rs | 1 + near-sdk/src/lib.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/near-contract-standards/src/lib.rs b/near-contract-standards/src/lib.rs index d6e548041..3a3b86d73 100644 --- a/near-contract-standards/src/lib.rs +++ b/near-contract-standards/src/lib.rs @@ -1,5 +1,6 @@ // We want to enable all clippy lints, but some of them generate false positives. #![allow(clippy::missing_const_for_fn, clippy::redundant_pub_crate)] +#![allow(clippy::needless_lifetimes)] /// Fungible tokens as described in [by the spec](https://nomicon.io/Standards/FungibleToken/README.html). pub mod fungible_token; diff --git a/near-sdk/src/lib.rs b/near-sdk/src/lib.rs index 85da47a82..b4ae14f57 100644 --- a/near-sdk/src/lib.rs +++ b/near-sdk/src/lib.rs @@ -4,6 +4,7 @@ // We want to enable all clippy lints, but some of them generate false positives. #![allow(clippy::missing_const_for_fn, clippy::redundant_pub_crate)] #![allow(clippy::multiple_bound_locations)] +#![allow(clippy::needless_lifetimes)] #[cfg(test)] extern crate quickcheck; From da3f1f4ec9785b541ef2860666970b10101717b5 Mon Sep 17 00:00:00 2001 From: Viraj Bhartiya Date: Mon, 2 Dec 2024 18:30:50 +0530 Subject: [PATCH 04/11] chore: remove `cargo-near-build` as separate import in `[dev-dependencies]` (examples) (#1263) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: remove dep * chore: update cargo_near_build dependency * revert: `factory-contract` from master --------- Co-authored-by: dj8yf0μl <26653921+dj8yfo@users.noreply.github.com> Co-authored-by: dj8yf0μl --- examples/fungible-token/Cargo.toml | 1 - examples/fungible-token/tests/workspaces.rs | 1 + examples/lockable-fungible-token/Cargo.toml | 1 - examples/lockable-fungible-token/tests/workspaces.rs | 1 + examples/non-fungible-token/Cargo.toml | 1 - examples/non-fungible-token/tests/workspaces/utils.rs | 2 +- 6 files changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/fungible-token/Cargo.toml b/examples/fungible-token/Cargo.toml index 535e8f49b..b62008b0f 100644 --- a/examples/fungible-token/Cargo.toml +++ b/examples/fungible-token/Cargo.toml @@ -9,7 +9,6 @@ anyhow = "1.0" near-sdk = { path = "../../near-sdk", features = ["unit-testing"] } tokio = { version = "1.14", features = ["full"] } near-workspaces = { version = "0.15", features = ["unstable"] } -cargo-near-build = "0.3.1" rstest = "0.23.0" [profile.release] diff --git a/examples/fungible-token/tests/workspaces.rs b/examples/fungible-token/tests/workspaces.rs index e8f19d673..c3731540f 100644 --- a/examples/fungible-token/tests/workspaces.rs +++ b/examples/fungible-token/tests/workspaces.rs @@ -5,6 +5,7 @@ use near_workspaces::operations::Function; use near_workspaces::result::ValueOrReceiptId; use near_workspaces::{types::NearToken, Account, AccountId, Contract}; use rstest::{fixture, rstest}; +use near_workspaces::cargo_near_build; const ONE_YOCTO: NearToken = NearToken::from_yoctonear(1); diff --git a/examples/lockable-fungible-token/Cargo.toml b/examples/lockable-fungible-token/Cargo.toml index 4163aa549..73f688670 100644 --- a/examples/lockable-fungible-token/Cargo.toml +++ b/examples/lockable-fungible-token/Cargo.toml @@ -15,7 +15,6 @@ anyhow = "1.0" tokio = { version = "1.14", features = ["full"] } near-sdk = { path = "../../near-sdk", features = ["unit-testing"] } near-workspaces = { version = "0.15", features = ["unstable"] } -cargo-near-build = "0.3.1" rstest = "0.23.0" [profile.release] diff --git a/examples/lockable-fungible-token/tests/workspaces.rs b/examples/lockable-fungible-token/tests/workspaces.rs index a48e95aaf..c3ef06f6d 100644 --- a/examples/lockable-fungible-token/tests/workspaces.rs +++ b/examples/lockable-fungible-token/tests/workspaces.rs @@ -3,6 +3,7 @@ use std::str::FromStr; use near_sdk::json_types::U128; use near_workspaces::{types::NearToken, Account, Contract}; use rstest::{fixture, rstest}; +use near_workspaces::cargo_near_build; #[fixture] fn initial_balance() -> U128 { diff --git a/examples/non-fungible-token/Cargo.toml b/examples/non-fungible-token/Cargo.toml index 27754d781..151fd9501 100644 --- a/examples/non-fungible-token/Cargo.toml +++ b/examples/non-fungible-token/Cargo.toml @@ -11,7 +11,6 @@ near-sdk = { path = "../../near-sdk", features = ["unit-testing"] } tokio = { version = "1.14", features = ["full"] } near-workspaces = { version = "0.15", features = ["unstable"] } rstest = "0.23.0" -cargo-near-build = "0.3.1" [profile.release] codegen-units = 1 diff --git a/examples/non-fungible-token/tests/workspaces/utils.rs b/examples/non-fungible-token/tests/workspaces/utils.rs index accb4861e..5b926c735 100644 --- a/examples/non-fungible-token/tests/workspaces/utils.rs +++ b/examples/non-fungible-token/tests/workspaces/utils.rs @@ -6,7 +6,7 @@ use near_contract_standards::non_fungible_token::TokenId; use near_workspaces::types::NearToken; use near_workspaces::{Account, Contract}; use rstest::fixture; - +use near_workspaces::cargo_near_build; pub const TOKEN_ID: &str = "0"; pub async fn helper_mint( From 5a4c595125364ffe8d7866aa0418a3c92b1c3a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dj8yf0=CE=BCl?= <26653921+dj8yfo@users.noreply.github.com> Date: Tue, 3 Dec 2024 12:45:01 +0200 Subject: [PATCH 05/11] ci: add a `cargo doc` job (#1269) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci: add a `cargo doc` job * doc: fix doc generation warnings + couple nomicon.io broken links --------- Co-authored-by: dj8yf0μl --- .github/workflows/coverage.yml | 2 +- .github/workflows/release-plz.yml | 2 +- .github/workflows/test.yml | 32 ++++++++++++++++--- .github/workflows/test_examples.yml | 2 +- .github/workflows/test_examples_small.yml | 2 +- .github/workflows/typo.yml | 2 +- .../src/fungible_token/mod.rs | 2 ++ near-contract-standards/src/lib.rs | 6 ++-- near-sdk/src/store/mod.rs | 6 ++-- near-sdk/src/test_utils/context.rs | 2 +- near-sdk/src/test_utils/mod.rs | 4 +-- near-sdk/src/test_utils/test_env.rs | 2 +- 12 files changed, 45 insertions(+), 19 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index ecfd50dc7..489343d1d 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -16,7 +16,7 @@ jobs: platform: [macos-latest] toolchain: [stable] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Homebrew run: | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" diff --git a/.github/workflows/release-plz.yml b/.github/workflows/release-plz.yml index 22141ea19..21c7e358e 100644 --- a/.github/workflows/release-plz.yml +++ b/.github/workflows/release-plz.yml @@ -15,7 +15,7 @@ jobs: if: github.ref == 'refs/heads/master' steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.CUSTOM_GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a13726c93..3ea29e1ac 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: rs: stable features: ['', '--features unstable,legacy,__abi-generate'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: "${{ matrix.platform.rs }} with rustfmt, and wasm32" uses: actions-rs/toolchain@v1 with: @@ -45,7 +45,7 @@ jobs: name: Clippy and fmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: @@ -61,7 +61,7 @@ jobs: name: Compilation tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: @@ -75,7 +75,7 @@ jobs: name: Windows runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: "Setup Windows toolchain" uses: actions-rs/toolchain@v1 with: @@ -93,7 +93,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Sources - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Toolchain uses: actions-rs/toolchain@v1 with: @@ -105,3 +105,25 @@ jobs: run: cargo install cargo-audit - name: Run Audit run: cargo audit + # there're sometimes warnings, which signal, that the generated doc + # won't look as expected, when rendered, and sometimes errors, which will prevent doc from being + # generated at release time altogether. + cargo-doc: + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v4 + - name: Install Toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + default: true + - name: run cargo doc + env: + RUSTDOCFLAGS: -D warnings + run: | + cargo doc -p near-sdk --features unstable,legacy,unit-testing,__macro-docs + cargo doc -p near-sdk-macros + cargo doc -p near-contract-standards --no-deps + cargo doc -p near-sys diff --git a/.github/workflows/test_examples.yml b/.github/workflows/test_examples.yml index d8790f7c8..278b8a904 100644 --- a/.github/workflows/test_examples.yml +++ b/.github/workflows/test_examples.yml @@ -25,7 +25,7 @@ jobs: factory-contract ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: "${{ matrix.toolchain }} with rustfmt, and wasm32" uses: actions-rs/toolchain@v1 with: diff --git a/.github/workflows/test_examples_small.yml b/.github/workflows/test_examples_small.yml index fde99636e..9c3f41e9a 100644 --- a/.github/workflows/test_examples_small.yml +++ b/.github/workflows/test_examples_small.yml @@ -22,7 +22,7 @@ jobs: test-contract, ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: "${{ matrix.toolchain }} with rustfmt, clippy, and wasm32" uses: actions-rs/toolchain@v1 with: diff --git a/.github/workflows/typo.yml b/.github/workflows/typo.yml index 021c55fd4..6bbce31c0 100644 --- a/.github/workflows/typo.yml +++ b/.github/workflows/typo.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Actions Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Check spelling of the entire repository uses: crate-ci/typos@v1.11.1 diff --git a/near-contract-standards/src/fungible_token/mod.rs b/near-contract-standards/src/fungible_token/mod.rs index eb0698fca..1210748ab 100644 --- a/near-contract-standards/src/fungible_token/mod.rs +++ b/near-contract-standards/src/fungible_token/mod.rs @@ -1,3 +1,5 @@ +//! Fungible tokens as described in [by the spec](https://nomicon.io/Standards/Tokens/FungibleToken). +//! //! This module represents a Fungible Token standard. //! //! # Examples diff --git a/near-contract-standards/src/lib.rs b/near-contract-standards/src/lib.rs index 3a3b86d73..edd387d12 100644 --- a/near-contract-standards/src/lib.rs +++ b/near-contract-standards/src/lib.rs @@ -2,12 +2,14 @@ #![allow(clippy::missing_const_for_fn, clippy::redundant_pub_crate)] #![allow(clippy::needless_lifetimes)] -/// Fungible tokens as described in [by the spec](https://nomicon.io/Standards/FungibleToken/README.html). pub mod fungible_token; -/// Non-fungible tokens as described in [by the spec](https://nomicon.io/Standards/NonFungibleToken/README.html). + +/// Non-fungible tokens as described in [by the spec](https://nomicon.io/Standards/Tokens/NonFungibleToken). pub mod non_fungible_token; + /// Storage management deals with handling [state storage](https://docs.near.org/docs/concepts/storage-staking) on NEAR. This follows the [storage management standard](https://nomicon.io/Standards/StorageManagement.html). pub mod storage_management; + /// This upgrade standard is a use case where a staging area exists for a WASM /// blob, allowing it to be stored for a period of time before deployed. #[deprecated( diff --git a/near-sdk/src/store/mod.rs b/near-sdk/src/store/mod.rs index ec724474a..ad1f3c5f7 100644 --- a/near-sdk/src/store/mod.rs +++ b/near-sdk/src/store/mod.rs @@ -20,8 +20,8 @@ //! If your collection has up to 100 entries, it's acceptable to use the native collection, as it might be simpler //! since you don't have to manage prefixes as we do with near collections. //! However, if your collection has 1,000 or more entries, it's better to use a near collection. The investigation -//! mentioned above shows that running the contains method on a native HashSet consumes 41% more gas -//! compared to a near IterableSet. +//! mentioned above shows that running the contains method on a native [`std::collections::HashSet`] consumes 41% more gas +//! compared to a near [`crate::store::IterableSet`]. //! //! It's also a bad practice to have a native collection properties as a top level properties of your contract. //! The contract will load all the properties before the contract method invocation. That means that all your native @@ -52,7 +52,7 @@ //! - [`UnorderedMap`]: Storage version of [`std::collections::HashMap`]. No ordering //! guarantees. //! -//! - [`TreeMap`](TreeMap) (`unstable`): Storage version of [`std::collections::BTreeMap`]. Ordered by key, +//! - [`TreeMap`] (`unstable`): Storage version of [`std::collections::BTreeMap`]. Ordered by key, //! which comes at the cost of more expensive lookups and iteration. //! //! Sets: diff --git a/near-sdk/src/test_utils/context.rs b/near-sdk/src/test_utils/context.rs index 07766d6f4..45823aa69 100644 --- a/near-sdk/src/test_utils/context.rs +++ b/near-sdk/src/test_utils/context.rs @@ -65,7 +65,7 @@ pub struct VMContext { pub random_seed: [u8; 32], /// If Some, it means that execution is made in a view mode and defines its configuration. /// View mode means that only read-only operations are allowed. - /// See for more details. + /// See for more details. pub view_config: Option, /// How many `DataReceipt`'s should receive this execution result. This should be empty if /// this function call is a part of a batch and it is not the last action. diff --git a/near-sdk/src/test_utils/mod.rs b/near-sdk/src/test_utils/mod.rs index 02f2fea2b..b305c0c98 100644 --- a/near-sdk/src/test_utils/mod.rs +++ b/near-sdk/src/test_utils/mod.rs @@ -19,7 +19,7 @@ pub use context::{accounts, testing_env_with_promise_results, VMContextBuilder}; /// about the VM to configure parameters not directly related to the transaction being executed. /// - `fee_config`(optional): [`RuntimeFeesConfig`] which configures the /// fees for execution and storage of transactions. -/// - `validators`(optional): a [`HashMap`]<[`AccountId`], [`Balance`]> mocking the +/// - `validators`(optional): a [`HashMap`]<[`AccountId`], [`NearToken`]> mocking the /// current validators of the blockchain. /// - `promise_results`(optional): a [`Vec`] of [`PromiseResult`] which mocks the results /// of callback calls during the execution. @@ -57,7 +57,7 @@ pub use context::{accounts, testing_env_with_promise_results, VMContextBuilder}; /// [`vm::Config`]: near_parameters::vm::Config /// [`RuntimeFeesConfig`]: near_parameters::RuntimeFeesConfig /// [`AccountId`]: crate::AccountId -/// [`Balance`]: crate::Balance +/// [`NearToken`]: crate::NearToken /// [`PromiseResult`]: crate::PromiseResult /// [`HashMap`]: std::collections::HashMap #[macro_export] diff --git a/near-sdk/src/test_utils/test_env.rs b/near-sdk/src/test_utils/test_env.rs index 15b789fcd..670b40029 100644 --- a/near-sdk/src/test_utils/test_env.rs +++ b/near-sdk/src/test_utils/test_env.rs @@ -32,7 +32,7 @@ pub fn setup() { } /// free == effectively unlimited gas -/// Sets up the blockchain interface with a [`VMConfig`] which sets the gas costs to zero. +/// Sets up the blockchain interface with a [`near_parameters::vm::Config`] which sets the gas costs to zero. pub fn setup_free() { let mut config = test_vm_config(); config.make_free(); From 7bfd3155e1cb8caf82ba876c42143d090d651a38 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Thu, 5 Dec 2024 14:06:37 +0100 Subject: [PATCH 06/11] chore: tests for Lazy and moving out of unstable (#1268) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: tests for Lazy and moving out of unstable * re-enable os-based testing * fix import * address comments * fix clippy * tune for linux * more tuning * tune * tune * tune * tune * tuning * override * fix * fix * fix * more tuning --------- Co-authored-by: dj8yf0μl <26653921+dj8yfo@users.noreply.github.com> --- near-sdk/src/store/mod.rs | 4 - near-sdk/tests/store_performance_tests.rs | 117 +++++++++++++++--- near-sdk/tests/test-contracts/lazy/Cargo.toml | 12 ++ near-sdk/tests/test-contracts/lazy/src/lib.rs | 96 ++++++++++++++ 4 files changed, 206 insertions(+), 23 deletions(-) create mode 100644 near-sdk/tests/test-contracts/lazy/Cargo.toml create mode 100644 near-sdk/tests/test-contracts/lazy/src/lib.rs diff --git a/near-sdk/src/store/mod.rs b/near-sdk/src/store/mod.rs index ad1f3c5f7..3dbbd1e8f 100644 --- a/near-sdk/src/store/mod.rs +++ b/near-sdk/src/store/mod.rs @@ -71,14 +71,10 @@ //! place of a type [`Option`](Option). Will only be loaded when interacted with and will //! persist on [`Drop`]. -#[cfg(feature = "unstable")] mod lazy; -#[cfg(feature = "unstable")] pub use lazy::Lazy; -#[cfg(feature = "unstable")] mod lazy_option; -#[cfg(feature = "unstable")] pub use lazy_option::LazyOption; pub mod vec; diff --git a/near-sdk/tests/store_performance_tests.rs b/near-sdk/tests/store_performance_tests.rs index cb2a7e573..ff6d210de 100644 --- a/near-sdk/tests/store_performance_tests.rs +++ b/near-sdk/tests/store_performance_tests.rs @@ -9,6 +9,7 @@ use near_workspaces::types::{KeyType, SecretKey}; use near_workspaces::{Account, Worker}; use rand::Rng; use serde::{Deserialize, Serialize}; +use std::fmt::Display; use std::sync::Arc; use strum_macros::Display; @@ -27,6 +28,11 @@ pub enum Collection { Vector, } +pub enum Contract { + StoreContract, + LazyContract, +} + fn random_account_id(collection: Collection, seed: &str) -> AccountId { let mut rng = rand::thread_rng(); let random_num = rng.gen_range(10000000000000usize..99999999999999); @@ -53,16 +59,20 @@ async fn dev_generate( Ok((account.into_result()?, collection)) } -async fn setup_worker() -> anyhow::Result<(Arc>, AccountId)> { +async fn setup_worker(contract: Contract) -> anyhow::Result<(Arc>, AccountId)> { + let contract_path = match contract { + Contract::StoreContract => "./tests/test-contracts/store", + Contract::LazyContract => "./tests/test-contracts/lazy", + }; let worker = Arc::new(near_workspaces::sandbox().await?); - let wasm = near_workspaces::compile_project("./tests/test-contracts/store").await?; + let wasm = near_workspaces::compile_project(contract_path).await?; let contract = worker.dev_deploy(&wasm).await?; let res = contract.call("new").max_gas().transact().await?; assert!(res.is_success()); Ok((worker, contract.id().clone())) } -fn perform_asserts(total_gas: u64, col: &Collection) { +fn perform_asserts(total_gas: u64, col: impl Display, override_min_gas: Option) { // Constraints a bit relaxed to account for binary differences due to on-demand compilation. assert!( total_gas < NearGas::from_tgas(110).as_gas(), @@ -71,7 +81,7 @@ fn perform_asserts(total_gas: u64, col: &Collection) { NearGas::from_gas(total_gas) ); assert!( - total_gas > NearGas::from_tgas(90).as_gas(), + total_gas > NearGas::from_tgas(override_min_gas.unwrap_or(90)).as_gas(), "not enough gas consumed {}: {}, adjust the number of iterations to spot regressions", col, NearGas::from_gas(total_gas) @@ -80,7 +90,7 @@ fn perform_asserts(total_gas: u64, col: &Collection) { #[allow(unused)] async fn setup_several(num: usize) -> anyhow::Result<(Vec, AccountId)> { - let (worker, contract_id) = setup_worker().await?; + let (worker, contract_id) = setup_worker(Contract::StoreContract).await?; let mut accounts = Vec::new(); for acc_seed in 0..num { @@ -92,8 +102,8 @@ async fn setup_several(num: usize) -> anyhow::Result<(Vec, AccountId)> Ok((accounts, contract_id)) } -async fn setup() -> anyhow::Result<(Account, AccountId)> { - let (worker, contract_id) = setup_worker().await?; +async fn setup(contract: Contract) -> anyhow::Result<(Account, AccountId)> { + let (worker, contract_id) = setup_worker(contract).await?; let (account, _) = dev_generate(worker.clone(), Collection::IterableSet, "seed".to_string()).await?; @@ -114,7 +124,7 @@ async fn insert_and_remove() -> anyhow::Result<()> { Collection::Vector, ]; - let (account, contract_id) = setup().await?; + let (account, contract_id) = setup(Contract::StoreContract).await?; // insert test, max_iterations here is the number of elements to insert. It's used to measure // relative performance. for (col, max_iterations) in collection_types.map(|col| match col { @@ -137,7 +147,7 @@ async fn insert_and_remove() -> anyhow::Result<()> { .total_gas_burnt .as_gas(); - perform_asserts(total_gas, &col); + perform_asserts(total_gas, col, None); } // remove test, max_iterations here is the number of elements to remove. It's used to measure @@ -162,7 +172,7 @@ async fn insert_and_remove() -> anyhow::Result<()> { .total_gas_burnt .as_gas(); - perform_asserts(total_gas, &col); + perform_asserts(total_gas, col, None); } Ok(()) @@ -181,7 +191,7 @@ async fn iter() -> anyhow::Result<()> { ]; let element_number = 100; - let (account, contract_id) = setup().await?; + let (account, contract_id) = setup(Contract::StoreContract).await?; // pre-populate for col in collection_types { @@ -215,7 +225,7 @@ async fn iter() -> anyhow::Result<()> { .total_gas_burnt .as_gas(); - perform_asserts(total_gas, &col); + perform_asserts(total_gas, col, None); } Ok(()) @@ -234,7 +244,7 @@ async fn random_access() -> anyhow::Result<()> { Collection::Vector, ]; let element_number = 100; - let (account, contract_id) = setup().await?; + let (account, contract_id) = setup(Contract::StoreContract).await?; // pre-populate for col in collection_types { @@ -277,7 +287,7 @@ async fn random_access() -> anyhow::Result<()> { .total_gas_burnt .as_gas(); - perform_asserts(total_gas, &col); + perform_asserts(total_gas, col, None); } Ok(()) @@ -297,7 +307,7 @@ async fn contains() -> anyhow::Result<()> { ]; // Each collection gets the same number of elements. let element_number = 100; - let (account, contract_id) = setup().await?; + let (account, contract_id) = setup(Contract::StoreContract).await?; // prepopulate for col in collection_types { @@ -332,7 +342,7 @@ async fn contains() -> anyhow::Result<()> { .total_gas_burnt .as_gas(); - perform_asserts(total_gas, &col); + perform_asserts(total_gas, col, None); } Ok(()) @@ -344,7 +354,7 @@ async fn contains() -> anyhow::Result<()> { async fn iterable_vs_unordered() -> anyhow::Result<()> { let element_number = 300; let deleted_element_number = 299; - let (account, contract_id) = setup().await?; + let (account, contract_id) = setup(Contract::StoreContract).await?; // We only care about Unordered* and Iterable* collections. let collection_types = &[ @@ -395,7 +405,7 @@ async fn iterable_vs_unordered() -> anyhow::Result<()> { .total_gas_burnt .as_gas(); - perform_asserts(total_gas, &col); + perform_asserts(total_gas, col, None); } // random access, repeat here is the number of times we try to access an element in the @@ -417,8 +427,77 @@ async fn iterable_vs_unordered() -> anyhow::Result<()> { .total_gas_burnt .as_gas(); - perform_asserts(total_gas, col); + perform_asserts(total_gas, col, None); } Ok(()) } + +#[tokio::test] +async fn test_lazy() -> anyhow::Result<()> { + let (account, contract_id) = setup(Contract::LazyContract).await?; + + let res = account + .call(&contract_id, "insert_delete") + .args_json((700,)) + .max_gas() + .transact() + .await? + .unwrap(); + + perform_asserts(res.total_gas_burnt.as_gas(), "lazy:insert_delete", None); + + let res = account + .call(&contract_id, "insert_delete_flush_once") + .args_json((1700,)) + .max_gas() + .transact() + .await? + .unwrap(); + + perform_asserts(res.total_gas_burnt.as_gas(), "lazy:insert_delete_flush_once", None); + + let res = account + .call(&contract_id, "flush") + .args_json((2350000,)) + .max_gas() + .transact() + .await? + .unwrap(); + + // Override min gas to avoid constant tuning, it's pretty clear this is performant. Somehow + // this is pretty flaky. + perform_asserts(res.total_gas_burnt.as_gas(), "lazy:flush", Some(60)); + + let res = account + .call(&contract_id, "get") + .args_json((2400000,)) + .max_gas() + .transact() + .await? + .unwrap(); + + // Override min gas to avoid constant tuning, it's pretty clear this is performant. + perform_asserts(res.total_gas_burnt.as_gas(), "lazy:get", Some(70)); + + let res = account + .call(&contract_id, "insert_flush") + .args_json((1200,)) + .max_gas() + .transact() + .await? + .unwrap(); + + perform_asserts(res.total_gas_burnt.as_gas(), "lazy:insert_flush", None); + + let res = account + .call(&contract_id, "insert_take") + .args_json((700,)) + .max_gas() + .transact() + .await? + .unwrap(); + + perform_asserts(res.total_gas_burnt.as_gas(), "lazy:insert_take", None); + Ok(()) +} diff --git a/near-sdk/tests/test-contracts/lazy/Cargo.toml b/near-sdk/tests/test-contracts/lazy/Cargo.toml new file mode 100644 index 000000000..42591aedc --- /dev/null +++ b/near-sdk/tests/test-contracts/lazy/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "lazy" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +near-sdk = { path = "../../../../near-sdk", features = ["default", "unstable"] } + +[workspace] diff --git a/near-sdk/tests/test-contracts/lazy/src/lib.rs b/near-sdk/tests/test-contracts/lazy/src/lib.rs new file mode 100644 index 000000000..6d2ac49a7 --- /dev/null +++ b/near-sdk/tests/test-contracts/lazy/src/lib.rs @@ -0,0 +1,96 @@ +use near_sdk::borsh::{BorshDeserialize, BorshSerialize}; +use near_sdk::{near, store::LazyOption, PanicOnDefault}; + +#[derive(BorshSerialize, BorshDeserialize, Ord, PartialOrd, Eq, PartialEq, Clone)] +#[borsh(crate = "near_sdk::borsh")] +pub struct Insertable { + pub index: u32, + pub data: String, + pub is_valid: bool, +} + +#[near(contract_state)] +#[derive(PanicOnDefault)] +pub struct LazyContract { + pub lazy_opt: LazyOption, +} + +#[near] +impl LazyContract { + #[init] + pub fn new() -> Self { + let lazy_opt = LazyOption::new(b"a", None); + Self { lazy_opt } + } + + fn insertable(&self) -> Insertable { + Insertable { index: 0, data: "scatter cinnamon wheel useless please rough situate iron eager noise try evolve runway neglect onion".to_string(), is_valid: true } + } + + /// This should only write to the underlying storage once. + #[payable] + pub fn flush(&mut self, iterations: usize) { + let insertable = self.insertable(); + self.lazy_opt.set(Some(insertable)); + + for _ in 0..=iterations { + self.lazy_opt.flush(); + } + } + + #[payable] + pub fn get(&mut self, iterations: u32) { + let insertable = self.insertable(); + self.lazy_opt.set(Some(insertable)); + for _ in 0..=iterations { + self.lazy_opt.get(); + } + } + + /// This should write on each iteration. + #[payable] + pub fn insert_flush(&mut self, iterations: u32) { + let mut insertable = self.insertable(); + for idx in 0..=iterations { + insertable.index = idx as u32; + self.lazy_opt.set(Some(insertable.clone())); + self.lazy_opt.flush(); + } + } + + /// This should write twice on each iteration. + #[payable] + pub fn insert_take(&mut self, iterations: u32) { + let mut insertable = self.insertable(); + for idx in 0..=iterations { + insertable.index = idx as u32; + self.lazy_opt.set(Some(insertable.clone())); + self.lazy_opt.flush(); + self.lazy_opt.take(); + self.lazy_opt.flush(); + } + } + + /// This should write and delete on each iteration. + #[payable] + pub fn insert_delete(&mut self, iterations: u32) { + let insertable = self.insertable(); + for _ in 0..=iterations { + self.lazy_opt.set(Some(insertable.clone())); + self.lazy_opt.flush(); + self.lazy_opt.set(None); + self.lazy_opt.flush(); + } + } + + /// This should write once on each iteration. + #[payable] + pub fn insert_delete_flush_once(&mut self, iterations: u32) { + let insertable = self.insertable(); + for _ in 0..=iterations { + self.lazy_opt.set(Some(insertable.clone())); + self.lazy_opt.set(None); + self.lazy_opt.flush(); + } + } +} From 0e2c144fd3044e9cbe245ed6e8862e7e6439a30d Mon Sep 17 00:00:00 2001 From: Artur Yurii Korchynskyi <42449190+akorchyn@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:23:24 +0200 Subject: [PATCH 07/11] chore: updates near-* dependencies to 0.28 release (#1272) --- .github/workflows/test.yml | 4 ++-- near-sdk/Cargo.toml | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3ea29e1ac..06bda06c8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,11 +15,11 @@ jobs: matrix: platform: - os: ubuntu-latest - rs: 1.80.0 + rs: 1.82.0 - os: ubuntu-latest rs: stable - os: macos-latest - rs: 1.80.0 + rs: 1.82.0 - os: macos-latest rs: stable features: ['', '--features unstable,legacy,__abi-generate'] diff --git a/near-sdk/Cargo.toml b/near-sdk/Cargo.toml index 6e7750f55..6e46206fc 100644 --- a/near-sdk/Cargo.toml +++ b/near-sdk/Cargo.toml @@ -42,11 +42,11 @@ schemars = { version = "0.8.8", optional = true } near-abi = { version = "0.4.0", features = [ "__chunked-entries", ], optional = true } -near-vm-runner = { version = "0.27", optional = true } -near-primitives-core = { version = "0.27", optional = true } -near-primitives = { version = "0.27", optional = true } -near-crypto = { version = "0.27", default-features = false, optional = true } -near-parameters = { version = "0.27", optional = true } +near-vm-runner = { version = "0.28", optional = true } +near-primitives-core = { version = "0.28", optional = true } +near-primitives = { version = "0.28", optional = true } +near-crypto = { version = "0.28", default-features = false, optional = true } +near-parameters = { version = "0.28", optional = true } [dev-dependencies] near-sdk = { path = ".", features = ["legacy", "unit-testing"] } From 21db1324aad9a75ae4b4fb5330436e33dc604706 Mon Sep 17 00:00:00 2001 From: Artur Yurii Korchynskyi <42449190+akorchyn@users.noreply.github.com> Date: Fri, 13 Dec 2024 18:09:21 +0200 Subject: [PATCH 08/11] chore: updates readme badges to rust version 1.82 (#1273) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ff2e36d0c..be5022f74 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@

Reference Documentation - MSRV + MSRV Crates.io version Download Join the community on Discord @@ -321,7 +321,7 @@ State breaking changes (low-level serialization format of any data type) will be ### MSRV -The minimum supported Rust version is currently `1.80`. There are no guarantees that this will be upheld if a security patch release needs to come in that requires a Rust toolchain increase. +The minimum supported Rust version is currently `1.82`. There are no guarantees that this will be upheld if a security patch release needs to come in that requires a Rust toolchain increase. ## Contributing From 88a0fe16a54adbf0a3068918aa29af625b4a4f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dj8yf0=CE=BCl?= <26653921+dj8yfo@users.noreply.github.com> Date: Fri, 13 Dec 2024 19:26:46 +0200 Subject: [PATCH 09/11] chore: update CODEOWNERS (#1274) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: dj8yf0μl --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 3144a1fea..ab35564a2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @frol @dj8yfo @ruseinov @akorchyn +* @frol @dj8yfo @ruseinov @akorchyn @PolyProgrammist From ea5fe8ab67c630d5afeda1437057b11e39fe69c4 Mon Sep 17 00:00:00 2001 From: Vlad Frolov Date: Mon, 16 Dec 2024 15:40:33 +0100 Subject: [PATCH 10/11] chore: release v5.7.0 (#1276) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🤖 New release * `near-sdk`: 5.6.0 -> 5.7.0 (✓ API compatible changes) * `near-sdk-macros`: 5.6.0 -> 5.7.0 * `near-contract-standards`: 5.6.0 -> 5.7.0 (✓ API compatible changes)

Changelog

## `near-sdk`

## [5.7.0](https://github.com/near/near-sdk-rs/compare/near-sdk-v5.6.0...near-sdk-v5.7.0) - 2024-12-13 ### Other - updates near-* dependencies to 0.28 release (#1272) - tests for Lazy and moving out of unstable (#1268) - add a `cargo doc` job (#1269) - allow clippy::needless_lifetimes (1.83 more suggestions) (#1267) - examples for Near-related host functions (#1259) - updates near-workspaces to 0.15 version (#1260)
## `near-contract-standards`
## [5.7.0](https://github.com/near/near-sdk-rs/compare/near-contract-standards-v5.6.0...near-contract-standards-v5.7.0) - 2024-12-13 ### Other - add a `cargo doc` job (#1269) - allow clippy::needless_lifetimes (1.83 more suggestions) (#1267)

--- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). --- CHANGELOG.md | 11 +++++++++++ Cargo.toml | 2 +- near-contract-standards/CHANGELOG.md | 7 +++++++ near-contract-standards/Cargo.toml | 2 +- near-sdk/Cargo.toml | 2 +- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ecacd790..3326b8283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ ## [Unreleased] +## [5.7.0](https://github.com/near/near-sdk-rs/compare/near-sdk-v5.6.0...near-sdk-v5.7.0) - 2024-12-13 + +### Other + +- updates near-* dependencies to 0.28 release (#1272) +- tests for Lazy and moving out of unstable (#1268) +- add a `cargo doc` job (#1269) +- allow clippy::needless_lifetimes (1.83 more suggestions) (#1267) +- examples for Near-related host functions (#1259) +- updates near-workspaces to 0.15 version (#1260) + ## [5.6.0](https://github.com/near/near-sdk-rs/compare/near-sdk-v5.5.0...near-sdk-v5.6.0) - 2024-11-14 ### Other diff --git a/Cargo.toml b/Cargo.toml index c2d3824b4..1d2f5397f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ members = ["near-sdk", "near-sdk-macros", "near-contract-standards", "near-sys"] exclude = ["examples/"] [workspace.package] -version = "5.6.0" +version = "5.7.0" # Special triple # comment for ci. [patch.crates-io] diff --git a/near-contract-standards/CHANGELOG.md b/near-contract-standards/CHANGELOG.md index f512e5ceb..b202003e4 100644 --- a/near-contract-standards/CHANGELOG.md +++ b/near-contract-standards/CHANGELOG.md @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [5.7.0](https://github.com/near/near-sdk-rs/compare/near-contract-standards-v5.6.0...near-contract-standards-v5.7.0) - 2024-12-13 + +### Other + +- add a `cargo doc` job (#1269) +- allow clippy::needless_lifetimes (1.83 more suggestions) (#1267) + ## [5.5.0](https://github.com/near/near-sdk-rs/compare/near-contract-standards-v5.4.0...near-contract-standards-v5.5.0) - 2024-09-11 ### Other diff --git a/near-contract-standards/Cargo.toml b/near-contract-standards/Cargo.toml index 03ff3cdab..e4ab1dfe9 100644 --- a/near-contract-standards/Cargo.toml +++ b/near-contract-standards/Cargo.toml @@ -13,7 +13,7 @@ NEAR smart contracts standard library. """ [dependencies] -near-sdk = { path = "../near-sdk", version = "~5.6.0", default-features = false, features = [ +near-sdk = { path = "../near-sdk", version = "~5.7.0", default-features = false, features = [ "legacy", ] } diff --git a/near-sdk/Cargo.toml b/near-sdk/Cargo.toml index 6e46206fc..853cc17a0 100644 --- a/near-sdk/Cargo.toml +++ b/near-sdk/Cargo.toml @@ -21,7 +21,7 @@ required-features = ["abi", "unstable"] # Provide near_bidgen macros. serde = { version = "1", features = ["derive"] } serde_json = "1" -near-sdk-macros = { path = "../near-sdk-macros", version = "~5.6.0" } +near-sdk-macros = { path = "../near-sdk-macros", version = "~5.7.0" } near-sys = { path = "../near-sys", version = "0.2.2" } base64 = "0.22" borsh = { version = "1.0.0", features = ["derive"] } From e78c08b0151b73e296ed1549d71a884dc78ece7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dj8yf0=CE=BCl?= <26653921+dj8yfo@users.noreply.github.com> Date: Thu, 19 Dec 2024 11:37:44 +0200 Subject: [PATCH 11/11] chore: impaired PublicKey with missing BorshSchema (#1281) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: dj8yf0μl --- near-sdk/src/types/public_key.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/near-sdk/src/types/public_key.rs b/near-sdk/src/types/public_key.rs index c66640765..8ce9f2f14 100644 --- a/near-sdk/src/types/public_key.rs +++ b/near-sdk/src/types/public_key.rs @@ -97,6 +97,7 @@ impl TryFrom for near_crypto::PublicKey { /// .unwrap(); /// ``` #[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, BorshSerialize, Hash)] +#[cfg_attr(feature = "abi", derive(borsh::BorshSchema))] pub struct PublicKey { data: Vec, }