Rust smart contract development diary (8)
BlockSec
2022-04-01 11:38
本文约2449字,阅读全文需要约10分钟
This article will specifically introduce the related issues of authority control in Rust smart contracts from the following two perspectives.

    This article will specifically introduce the related issues of authority control in Rust smart contracts from the following two perspectives:

    Visibility of contract method (function) access/call;

    secondary title

    1. Contract function (method) visibility

    When writing smart contracts, we can control what functions can be called by whom by specifying the visibility of contract functions. This allows us to easily protect certain critical parts of the contract from accidental access or manipulation.

    In order to reflect the importance of correctly setting the visibility of contract functions, this article will take the Bancor Network exchange as an example. As early as June 18, 2020, a contract asset security incident occurred in the exchange due to the incorrect setting of access control permissions for key functions of the contract. The contract is written in Solidity language. In this language, the visibility of contract functions is roughly divided into public/external and private/internal. The former allows contract functions to be called by external callers, which can be regarded as part of the contract interface.

    However, when the Bancor Network exchange modified a certain security hole, due to negligence, it mistakenly set some key transfer functions in the contract as public attributes (as shown below):

    Based on this, anyone, including ordinary users, can call these functions from outside the contract to perform corresponding transfer operations for themselves or others.

    The existence of this critical vulnerability puts its users' assets of $590,000 at serious risk.


    Similarly, in Rust smart contracts, attention must also be paid to the visibility control of contract functions.

    In this series of smart contracts to develop a diaryRust smart contract development diary (1), we have introduced the macros defined by the NEAR SDK: #[near_bindgen]:

    #[near_bindgen] is defined by the near_bindgen function in the near-sdk-macros-version package, which is where macros are used to automatically generate injection code (Macros-Auto-Generated Injected Code, MAGIC for short)

    By consulting the official description document provided by NEAR, we can see that there are several different visible attributes in the Rust smart contract function defined by the #[near_bindgen] macro:

    • pub fn: Indicates that the contract method is public and is part of the contract interface, which means that anyone can call it from outside the contract.

    • fn: If the method function of the contract does not explicitly specify pub, it means that the function cannot be called directly from outside the contract, and can only be called internally by other functions in the contract.

    • pub(crate) fn: equivalent to pub(in crate), similar to fn, this visibility modifier can limit specific contract methods to be called within the scope of the crate.

    Another way to set the method of the contract as internal is to define a separate impl Contract code block in the contract.

    But it should be noted that the implementation is not modified by #[near_bindgen]:

    Access control for callback (Callbacks) functions:

    The definition of the callback function in the contract must be set as a public attribute, so that it can be called by function call.

    When we define a callback function in a contract, we also need to ensure that the callback function cannot be called by others at will. That is, the caller of the callback function env::current_account_id() must be the contract's own env::current_account_id().

    The NEAR SDK defines an equivalent Rust macro #[private] for us. Using this macro, the callback function of the contract can achieve the same function as that implemented in lines 4-5 of the above code.

    By default, everything in the Rust language is private. For example, the function fn that does not set the public attribute above has a default visibility of private.

    What solidity needs to distinguish here is that in some old versions of solidty compilers: if no modifier is added to the definition of the contract function, it will be regarded as public by default.

    But in the Rust language, there are two exceptions:

    • The sub-items in pub Trait are public by default;

    • Enum variables in pub Enum are also public by default;


    2. Access control of privileged functions (white list mechanism)

    When writing a Rust smart contract, in addition to knowing the specific function visibility, we also need to think deeply from the semantic level of the contract, that is, to establish a complete access control whitelist mechanism.

    Similar to the contracts/access/Ownable.sol contract defined and used in the Solidity smart contract library openzeppelin-contracts, some functions are privileged functions, such as contract initialization, contract opening/pause, unified transfer, etc... ...can only be called by the owner of the contract. These functions are also usually called only owner functions.

    But the owner is essentially an external caller of the contract. To call, these key functions must be set as public properties. So, since these functions are public attributes, does it mean that all other ordinary users can also come and call them?

    The answer is yes, but ordinary users who are not owners will soon find out that they can adjust, but not completely.

    This is because in smart contracts, some access control rules can be defined for contract functions, and the corresponding rules must be satisfied to be completely authorized to execute. For example, there are the following commonly used modifiers in solidity contracts:

    When the contract function modified by this modifier is called, it will first check whether the caller msg.sender of this transaction is the owner set when the contract is initialized. If it does not match, the subsequent execution of the function will abort or revert, Thereby preventing unauthorized users from accessing and executing.

    Similarly, in the smart contract of NEAR Rust, we can also implement a custom Trait similar to the following:

    Using this trait can also implement access control to certain privileged functions in the contract, that is, the caller env::predecessor_account_id() of the contract in this transaction needs to be equal to the owner of the contract.

    Above we have established a simple whitelist example only for ownable privileged functions. Based on this principle, we can set multiple users in the whitelist by customizing more complex modifiers or traits, or set multiple whitelists to achieve good and fine-grained group access control effects.

    3. More Access Control Methods

    Methods for access control in other Rust smart contracts such as:

    • Contract call timing control

    • Multi-signature call mechanism of contract function, implementation of governance (DAO)

    • ...

    Please pay attention to the follow-up push of this series of smart contract development diaries😊

    BlockSec
    作者文库