Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: #[near(contract_state)] in-depth pass #1307

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ impl StatusMessage {
}
```

## Github Codespaces template
## Github Codespaces template + [an online ide](https://docs.github.com/en/codespaces/reference/using-the-vs-code-command-palette-in-codespaces)

* Quick start your project with the [template repository](https://github.com/near/cargo-near-new-project-template) generated by `cargo near new` command
* The associated [template repository](https://github.com/near/cargo-near-new-project-template)'s README contains a `Code > Codespaces > Create codespace on main` screenshot.
* Clicking the button will result in using [Github Codespaces devcontainer](https://docs.github.com/en/codespaces). The containers allow you to start building without the need to install any dependencies on your machine and provide the actual version.
Expand Down Expand Up @@ -281,6 +282,14 @@ cargo near build

Builds a NEAR smart contract along with its [ABI](https://github.com/near/abi) (while in the directory containing contract's Cargo.toml).

If you have problems/errors with schema/ABI during build that you cannot figure out quick, you can skip/circumvent them with:

```sh
cargo near build non-reproducible-wasm --no-abi
```

And return to figuring how to resolve problems with generating ABI of your contract later.

```sh
cargo near create-dev-account
```
Expand Down
11 changes: 11 additions & 0 deletions near-sdk/src/collections/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! ## General description
//!
//! Collections that offer an alternative to standard containers from `std::collections::*` by
//! utilizing the underlying blockchain trie storage more efficiently.
//!
Expand Down Expand Up @@ -33,6 +35,15 @@
//!
//! The efficiency of `LookupMap` comes at the cost, since it has fewer methods than `HashMap` and is not
//! that seamlessly integrated with the rest of the Rust standard library.
//!
//! ## Calls to **host functions**, used in implementation:
//!
//! * [`near_sdk::env::storage_write`](crate::env::storage_write)
//! * [`near_sdk::env::storage_read`](crate::env::storage_read)
//! * [`near_sdk::env::storage_remove`](crate::env::storage_remove)
//! * [`near_sdk::env::storage_get_evicted`](crate::env::storage_get_evicted)
//! * [`near_sdk::env::storage_has_key`](crate::env::storage_has_key)
//!

mod legacy_tree_map;
#[allow(deprecated)]
Expand Down
185 changes: 174 additions & 11 deletions near-sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
//! near-sdk = "5.6.0"
//! ```
//!
//! ### Example: Counter Smart Contract. For more information, see the [near] documentation.
//! ### Example: Counter Smart Contract. For more information, see the [**near** macro](near) documentation.
//!
//! Below is an example of a simple counter contract that increments and retrieves a value:
//!
Expand Down Expand Up @@ -54,17 +54,27 @@
//!
//! ### Compiling to WASM
//!
//! Install cargo near in case if you don't have it:
//! Install `cargo-near` in case if you don't have it:
//! ```bash
//! cargo install --locked cargo-near
//! ```
//!
//! Build your contract for the NEAR blockchain:
//! More installation methods on [cargo-near](https://github.com/near/cargo-near)
//!
//! Builds a NEAR smart contract along with its [ABI](https://github.com/near/abi) (while in the directory containing contract's Cargo.toml):
//!
//! ```bash
//! cargo near build
//! ```
//!
//! If you have problems/errors with schema/ABI during build that you cannot figure out quick, you can skip/circumvent them with:
//!
//! ```bash
//! cargo near build non-reproducible-wasm --no-abi
//! ```
//!
//! And return to figuring how to resolve problems with generating ABI of your contract later.
//!
//! ### Running Unit Tests
//!
//! Use the following testing setup:
Expand Down Expand Up @@ -102,31 +112,182 @@ extern crate quickcheck;
/// to generate the necessary code to expose `pub` methods from the contract as well
/// as generating the glue code to be a valid NEAR contract.
///
/// The macro is a syntactic sugar for [near_bindgen] and expands to the [near_bindgen] macro invocations.
/// Both of them share the same attributes, except for those that are explicitly marked as specific to the [near] macro. ([1](near#nearserializers-annotates-structsenums), [2](near#nearcontract_state-annotates-structsenums))
/// The macro is a syntactic sugar for [**near_bindgen**](near_bindgen) and expands to the [**near_bindgen**](near_bindgen) macro invocations.
/// Both of them share the same attributes, except for those that are explicitly marked as specific to the [**near**](near) macro. ([1](near#nearcontract_state-annotates-structsenums), [2](near#nearserializers-annotates-structsenums))
///
/// # Attributes
///
/// ## `#[near(contract_state)]` (annotates structs/enums)
///
/// The attribute prepares a struct/enum to be a contract state. Only one contract state is allowed per crate.
///
/// A contract type is usually acompanied by an `impl` block, annotated with [`#[near]`](near#near-annotates-impl-blocks).
///
/// This attribute is also required to make the [`#[near(contract_metadata(...))]`](near#nearcontract_metadata-annotates-structsenums) attribute work.
/// **The attribute specific to the [near] macro only.**
///
/// `contract_state` is specific to the [near] macro only, not available for [near_bindgen].
///
/// ### Basic example
/// ```rust
/// use near_sdk::near;
///
/// #[near(contract_state)]
/// pub struct Contract {
/// data: i8,
/// greeting: String,
/// }
/// ```
/// which usually comes paired with at least one **impl** block for the contract type,
/// annotated with a plain `#[near]` attribute:
///
/// ### Using SDK collections for storage
///
/// If contract state becomes large, collections from following modules can be used:
///
/// #### [`store`] module:
///
/// ```rust
/// # use near_sdk_macros::near;
/// use near_sdk::store::IterableMap;
///
/// #[near(contract_state)]
/// pub struct StatusMessage {
/// records: IterableMap<String, String>,
/// }
/// ```
///
/// * list of [**host functions**](store#calls-to-host-functions-used-in-implementation) used for [`store`] implementation
/// * **FAQ**: mutating state of collections from [`store`] module is only finally persisted on running [`Drop`/`flush`](store#faq-collections-of-this-module-only-persist-on-drop-and-flush)
///
/// #### [`collections`] module:
///
/// ```rust
/// # use near_sdk_macros::near;
/// use near_sdk::collections::LookupMap;
///
/// #[near(contract_state)]
/// pub struct StatusMessage {
/// records: LookupMap<String, String>,
/// }
/// ```
///
/// * list of [**host functions**](collections#calls-to-host-functions-used-in-implementation) used for [`collections`] implementation
///
/// ### Implementation details of `#[near(contract_state)]` macro and **host functions** calls used
///
/// If the details of [ABI](https://github.com/near/abi) generation layer are put aside, then the macro performs roughly the following:
///
/// ```rust
/// # use near_sdk::near;
/// #[near(contract_state)]
/// pub struct Contract { /* .. */ }
/// ```
///
/// 1. Macro adds derived implementations of [`borsh::BorshSerialize`]/[`borsh::BorshSerialize`] for `Contract` type
/// 2. Macro defines a global `CONTRACT_SOURCE_METADATA` variable, which is a string of json serialization of [`near_contract_standards::contract_metadata::ContractSourceMetadata`](https://docs.rs/near-contract-standards/latest/near_contract_standards/contract_metadata/struct.ContractSourceMetadata.html).
/// 3. Macro defines `contract_source_metadata` function:
/// ```rust,no_run
/// #[no_mangle]
/// pub extern "C" fn contract_source_metadata() { /* .. */ }
/// ```
/// which
/// * calls [`env::setup_panic_hook`] host function
/// * calls [`env::value_return`] host function with bytes of `CONTRACT_SOURCE_METADATA` from step 2.
///
/// ##### using [cargo-expand](https://crates.io/crates/cargo-expand) to view actual macro results
///
/// The above is an approximate description of what macro performs.
///
/// Running the following in a contract's crate is a way to introspect more details of its operation:
///
/// ```bash,ignore
/// cargo expand --lib --target wasm32-unknown-unknown
/// # this has additional code generated for ABI layer
/// cargo expand --lib --features near-sdk/__abi-generate
/// ```
/// ---
///
/// ## `#[near]` (annotates impl blocks)
///
/// This macro is used to define the code for view-only and mutating methods for contract types,
/// annotated by [`#[near(contract_state)]`](near#nearcontract_state-annotates-structsenums).
///
/// ### Basic example
/// ```rust
/// use near_sdk::{near, log};
///
/// # #[near(contract_state)]
/// # pub struct Contract {
/// # greeting: String,
/// # }
/// #[near]
/// impl Contract {
/// // view method
/// pub fn get_greeting(&self) -> String {
/// self.greeting.clone()
/// }
///
/// // mutating method
/// pub fn set_greeting(&mut self, greeting: String) {
/// log!("Saving greeting: {greeting}");
/// self.greeting = greeting;
/// }
/// }
/// ```
///
/// ### Implementation details of `#[near]` macro and **host functions** calls used
///
/// ```rust
/// # use near_sdk::near;
/// # #[near(contract_state)]
/// # pub struct Contract { /* .. */ }
/// #[near]
/// impl Contract {
/// pub fn view_method(&self) -> String { todo!("method body") }
///
/// pub fn mutating_method(&mut self, argument: String) { /* .. */ }
/// }
/// ```
///
/// ##### for above **view** method macro defines the following function:
///
/// ```rust,no_run
/// #[no_mangle]
/// pub extern "C" fn view_method() { /* .. */ }
/// ```
/// which
///
/// 1. calls [`env::setup_panic_hook`] host function
/// 2. calls [`env::state_read`] host function to load `Contract` into a `state` variable
/// 3. calls original `Contract::view_method(&state)` as defined in `#[near]` annotated [impl block](near#implementation-details-of-near-macro-and-host-functions-calls-used) and saves
/// the returned value into a `result` variable
/// 4. calls [`serde_json::to_vec`] on obtained `result` and saves returned value to `serialized_result` variable
/// * `json` format can be changed to serializing with [`borsh::to_vec`] by using [`#[result_serializer(...)]`](`near#result_serializer-annotates-methods-of-a-type-in-its-impl-block`)
/// 5. if the `serialized_result` is an [`Result::Err`] error, then [`env::panic_str`] host function is called to signal result serialization error
/// 6. otherwise, if the `serialized_result` is a [`Result::Ok`], then [`env::value_return`] host function is called with unwrapped `serialized_result`
///
/// ##### for above **mutating** method macro defines the following function:
/// ```rust,no_run
/// #[no_mangle]
/// pub extern "C" fn mutating_method() { /* ..*/ }
/// ```
/// which
///
/// 1. calls [`env::setup_panic_hook`] host function
/// 2. calls [`env::input`] host function and saves it to `input` variable
/// 3. deserializes `Contract::mutating_method` arguments by calling [`serde_json::from_slice`] on `input` variable and saves it to `deserialized_input` variable
/// * `json` format can be changed to deserializing with [`borsh::from_slice`] by using [`#[serializer(...)]`](`near#serializer-annotates-function-arguments`)
/// 4. if the `deserialized_input` is an [`Result::Err`] error, then [`env::panic_str`] host function is called to signal input deserialization error
/// 5. otherwise, if the `deserialized_input` is a [`Result::Ok`], `deserialized_input` is unwrapped and saved to `deserialized_input_success` variable
/// 6. calls [`env::state_read`] host function to load `Contract` into a `state` variable
/// 7. calls original `Contract::mutating_method(&mut state, deserialized_input_success.argument)` as defined in `#[near]` annotated [impl block](near#implementation-details-of-near-macro-and-host-functions-calls-used)
/// 8. calls [`env::state_write`] with `&state` as argument.
/// ---
///
/// ## `#[near(serializers=[...])` (annotates structs/enums)
///
/// The attribute makes the struct or enum serializable with either json or borsh. By default, borsh is used.
/// **The attribute specific to the [near] macro only.**
///
/// `serializers` is specific to the [near] macro only, not available for [near_bindgen].
///
/// ### Make struct/enum serializable with borsh
///
Expand Down Expand Up @@ -176,8 +337,10 @@ extern crate quickcheck;
///
/// ## `#[serializer(...)]` (annotates function arguments)
///
/// The attribute makes the function argument serializable with either json or borsh. By default, json is used.
/// Please, note that all the arguments of the function should be using the same serializer.
/// The attribute makes the function argument deserializable from [`Vec`]<[`u8`]> with either json or borsh. By default, json is used.
/// Please, note that all the arguments of the function should be using the same deserializer.
///
/// NOTE: a more correct name for the attribute would be `argument_deserializer`, but it's `serializer` for historic reasons.
///
/// ### Basic example
///
Expand Down Expand Up @@ -418,7 +581,7 @@ extern crate quickcheck;
/// All fields(version, link) are optional and will be populated with defaults from the Cargo.toml file if not specified.
/// The `standard` will be populated with `nep330` by default.
///
/// Any additional standards can be added and should be specified using the `standard` attribute.
/// **Any additional standards can be added and should be specified using the `standard` attribute.**
///
/// The `contract_source_metadata()` view function will be added and can be used to retrieve the source metadata.
/// Also, the source metadata will be stored as a constant, `CONTRACT_SOURCE_METADATA`, in the contract code.
Expand Down
Loading
Loading