Skip to content

Commit

Permalink
Merge pull request #917 from multiversx/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
axenteoctavian committed Jun 10, 2024
2 parents e89549e + 91b873f commit 6cab1ca
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 178 deletions.
187 changes: 21 additions & 166 deletions docs/developers/meta/rust-nightly.md
Original file line number Diff line number Diff line change
@@ -1,189 +1,44 @@
---
id: rust-nightly
title: Nightly Rust
title: Stable vs. Nightly Rust
---

[comment]: # (mx-abstract)

## Why Nighly?
## Required Rust version

The Rust framework currently requires nightly Rust to run. This often causes issues with the inherent instability and frequent changes in the Rust compiler.
Starting with framework version [v0.50.0](https://crates.io/crates/multiversx-sc/0.50.0), MultiversX smart contracts can be built using stable Rust.

While it would be ideal to have our infrastructure running on stable Rust, there are a number of features that we currently require.

This page is intended to provide a list of all these features that we use, and explain what it would take to renounce them and move to stable.
Before this version, nightly Rust was required.

[comment]: # (mx-context-auto)

## Nightly features

<NightlyFeaturesTable />

export const NightlyFeaturesTable = () => (
<table>
<tr>
<th>Feature</th>
<th>Why we need it</th>
<th>What it would take to discard</th>
</tr>
<tr>
<td>
<code>never_type</code> and <code>exhaustive_patterns</code>
</td>
<td>
<p>
The codec is optimized to work within smart contracts, but also to be used outside them, in a standard environment. Encoding and decoding functions return <code>Result</code>, because we want to allow programs to recover from a failed encoding or decoding attempt. However, this feature is not needed in contracts, where we want failures to interrupt execution immediately.
</p>
<p>
Our solution relies heavily on the never type (<code>!</code>), to guide the compiler to discard any error recovery when compiling contracts.
</p>
<p>
Exhaustive patterns are a nice way to engage with code that is guaranteed at compile time to never return an error.
</p>
</td>
<td>
<p>
The <code>never_type</code> seems to be close to being stabilized.
</p>
<p>
Exhaustive patterns, if not stabilized soon, could be replaced with regular patterns with an unreacheable clause on the else.
</p>
</td>
</tr>
<tr>
<td>
<code>auto_traits</code> and <code>negative_impls</code>
</td>
<td>
<p>
We have a feature that allows safe conversions from one type to another via the codec. For instance, a smaller integer can be safely cast to a larger one. This feature is central to proxies and transaction syntax.
</p>
<p>
We are using auto-traits and negative implementations to overcome overlaps in the implementations of the <code>CodecFrom</code> trait.
</p>
</td>
<td>
<p>
Could be replaced by relying more heavily on proc-macros. We would need a way to generate the <code>CodecFrom&lt;Self&gt;</code> when deriving <code>TopEncode</code> and <code>TopDecode</code>.
</p>
<p>
Alternately, we could wait for an overlapping marker trait impls.
</p>
</td>
</tr>
<tr>
<td>
<code>try_trait_v2</code>
</td>
<td>
<p>
Used in the deprecated <code>SCResult</code> type.
</p>
</td>
<td>
<p>
Remove <code>SCResult</code>.
</p>
</td>
</tr>
<tr>
<td>
<code>maybe_uninit_uninit_array</code> and <code>maybe_uninit_array_assume_init</code>
</td>
<td>
<p>
Used in <code>ManagedVec</code> <code>to_array_of_refs</code>.
</p>
</td>
<td>
<p>
There are less elegant ways to write that method, without using these features.
</p>
</td>
</tr>
<tr>
<td>
<code>generic_const_exprs</code>
</td>
<td>
<p>
Used everywhere in working with the <code>ManagedVec</code> payload, without using the heap. They allow us to allocate variable sized byte arrays on the stack.
</p>
</td>
<td>
<p>
Using universal fixed-sized arrays on heap for handling payloads. Might hurt performance, and might also occasionally run into overflows.
</p>
</td>
</tr>
<tr>
<td>
<code>slice_partition_dedup</code>
</td>
<td>
<p>
Used in <code>ManagedVec</code> <code>dedup</code>.
</p>
</td>
<td>
<p>
We could probably replace that one with an in-house de-duplication function.
</p>
</td>
</tr>
<tr>
<td>
<code>is_sorted</code>
</td>
<td>
<p>
Used in <code>ManagedVec</code> <code>is_sorted</code>, <code>is_sorted_by</code>, and <code>is_sorted_by_key</code>. These methods are currently mostly used in tests.
</p>
</td>
<td>
<p>
We could probably replace them with in-house equivalent functions.
</p>
</td>
</tr>
<tr>
<td>
<code>panic_info_message</code>
</td>
<td>
<p>
Used in the wasm adapter to retrieve panic messages, for debugging purposes.
</p>
</td>
<td>
<p>
Figuring out a way to use the format function provided by the stable version of the library, without performing memory allocation.
</p>
</td>
</tr>
</table>
);
## Recommended compiler versions

[comment]: # (mx-context-auto)
For everything after v0.50.0 we recommend running the latest stable version of Rust. Older versions have had compatiblity issues with certain framework dependencies, on certain versions of the compiler.

## Deal breakers
Nightly Rust is still allowed, but not recommended. We will still be supporting nightly builds and running continuous integration on `nightly-2024-05-22`.

Some of the nightly features that we use could be easily replaced with something from stable. However, there are a few essential ones that we have yet no solution for:
Also, everything on versions older than v0.50.0 needs to run on nightly Rust.

[comment]: # (mx-context-auto)
So, to summarize:
- After `v0.50.2`: `stable`, Rust >= 1.78 required.
- After `v0.50.0`: `stable`.
- Before `v0.50.0`: `nightly-2023-12-11` and `nightly-2024-05-22` are both known to be running fine.

### `generic_const_exprs`

This one is very difficult to get rid of without compromising the `ManagedVec` functionality. We have also recently added a new `ManagedDecimal` component that makes use of this feature. This is the main deal breaker right now for switching to stable Rust.

[comment]: # (mx-context-auto)

### `never_type`
## Why Nighly for the older versions?

Our entire codec relies on the never type. There might be a workaround using void enums, not sure if it works. Fortunately, this feature is close to being stabilized.
There were several nightly features that the framework was using, which we had hoped to see stabilized sooner.

[comment]: # (mx-context-auto)
These are of little relevance to the average developer, but for the record, let's mention a few of them and how we managed to circumvent their usage:
- `never_type` - avoided by using slightly different syntax;
- `auto_traits` and `negative_impls` - avoided by redesigning the `CodecFrom`/`TypeAbiFrom` trait systems;
- `generic_const_exprs` - replaced with massive amounts of macros;
- `panic_info_message` - replaced by a different method to retrieve the panic message.

### `auto_traits` and `negative_impls`
If any of these get stabilized in the future, we might revert the changes enacted in v0.50.0.

This is not impossible to overcome, but would need a redesign of some of the codec traits.
It is in any case our commitment to keep the framework compatible with stable Rust from here on, no matter what.
2 changes: 1 addition & 1 deletion docs/developers/meta/sc-build-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ This is also the step where the meta crate parses and processes the `multicontra

[comment]: # (mx-context-auto)

### d. Meta crate: generating `wasm` crate code
### d. Meta crate: generating wasm crate code

Each contract must contain at least one `wasm` crate. This is separate from the contract crate because it has a different purpose: it only needs to be the basis for compiling wasm. Please take it as an intermediary step between the contract logic and the Rust to WASM compiler. This is also where the WASM compilation options are specified (e.g. the optimization level). These options can be seen in the `Cargo.toml` file of the `wasm` crate.

Expand Down
2 changes: 1 addition & 1 deletion docs/developers/meta/sc-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ An _external view contract_ has a behavior different from that of a regular cont
- `add-unlabelled`
- Specifies that all unlabelled endpoints should be added to this contract.
- _values_: `true` | `false`
- _default_: `false`
- _default_: `true`
- `add-labels`
- All endpoints labelled with at least one of these labels will be added to the contract.
- _values_: a list of string labels, e.g. `add-labels = ["label1", "label2"]`
Expand Down
28 changes: 19 additions & 9 deletions docs/developers/transactions/tx-payment.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,18 @@ The payment is a little more complex than the previous fields. The `.payment(...
```mermaid
graph LR
payment-unit["()"]
payment-unit -->|egld| egld-biguint["Egld(BigUint)"]
payment-unit -->|egld| egld-u64["Egld(u64)"]
payment-unit -->|egld| egld-num["Egld(NumExpr)"]
payment-unit -->|"payment<br />esdt"| EsdtTokenPayment
payment-unit -->|"payment<br />single_esdt"| EsdtTokenPaymentRefs
payment-unit --->|"&lt;proxy&gt;"| not-payable["NotPayable"]
payment-unit --->|egld| egld-biguint["Egld(BigUint)"]
payment-unit --->|egld| egld-u64["Egld(u64)"]
payment-unit --->|egld| egld-num["Egld(NumExpr)"]
payment-unit --->|"payment<br />esdt"| EsdtTokenPayment
payment-unit --->|"payment<br />single_esdt"| EsdtTokenPaymentRefs
EsdtTokenPayment -->|esdt| MultiEsdtPayment
MultiEsdtPayment -->|esdt| MultiEsdtPayment
payment-unit -->|"payment<br >multi_esdt"| MultiEsdtPayment
payment-unit -->|"payment"| EgldOrEsdtTokenPayment
payment-unit -->|"payment<br />egld_or_single_esdt"| EgldOrEsdtTokenPaymentRefs
payment-unit -->|"payment<br />egld_or_multi_esdt"| EgldOrMultiEsdtPayment
payment-unit --->|"payment<br >multi_esdt"| MultiEsdtPayment
payment-unit --->|"payment"| EgldOrEsdtTokenPayment
payment-unit --->|"payment<br />egld_or_single_esdt"| EgldOrEsdtTokenPaymentRefs
payment-unit --->|"payment<br />egld_or_multi_esdt"| EgldOrMultiEsdtPayment
```

[comment]: # (mx-context-auto)
Expand All @@ -47,6 +48,15 @@ When no payments are added, the `Payment` fields remain of type `()`. This makes
In this example, the transaction is a smart contract call to a non payable endpoint with no arguments.


[comment]: # (mx-context-auto)

### `NotPayable`

The `NotPayable` object is a variation of the no-payment indicator `()`. It acts the same way, with only one difference: no payment can be added on top of it.

[Proxies](tx-proxies#notpayable-protection) will add the `NotPayable` flag to transactions to non-payable endpoints, to provide an additional layer of security.


[comment]: # (mx-context-auto)

## EGLD payment
Expand Down
2 changes: 1 addition & 1 deletion docs/developers/transactions/tx-proxies.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,4 @@ Proxies additionally capture the return type originally defined within the smart

## NotPayable protection

All non-payment endpoints in the generated proxy have a safeguard to prevent accidental payments. This involves automatically setting the payment to **NotPayable**.
All non-payment endpoints in the generated proxy have a safeguard to prevent accidental payments. This involves automatically setting the payment to [**NotPayable**](tx-payment#notpayable).
2 changes: 2 additions & 0 deletions docs/sovereign/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ You can use any wallet of your choice, but for the purpose of this guide we are

## Step 3: Clone the ```mx-chain-go``` Repository

Before proceeding, ensure that a SSH key for GitHub is configured on your machine.

1. Clone the github repository:
```bash
git clone https://github.com/multiversx/mx-chain-go.git
Expand Down

0 comments on commit 6cab1ca

Please sign in to comment.