5.6 访问控制 (Access Control)

Smart contracts require the ability to restrict access to and identify certain users or contracts. Unlike account-based blockchains, transactions in UTXO-based blockchains (i.e. Fuel) do not necessarily have a unique transaction sender. Additional logic is needed to handle this difference, and is provided by the standard library.

智能合约要求能够限制对某些用户或合约的访问及其识别。与基于账户的区块链不同,基于UTXO的区块链(即Fuel)中的交易不一定有一个唯一的交易发送者。需要额外的逻辑来处理这种差异,并由标准库提供。

msg_sender

To deliver an experience akin to the EVM's access control, the std library provides a msg_sender function, which identifies a unique caller based upon the call and/or transaction input data.

为了提供类似于EVM访问控制的体验,std库提供了一个msg_sender函数,它根据调用和/或交易输入数据识别一个独特的调用者。

contract;

use std::auth::msg_sender;

abi MyOwnedContract {
    fn receive(field_1: u64) -> bool;
}

const OWNER = Address::from(0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c);

impl MyOwnedContract for Contract {
    fn receive(field_1: u64) -> bool {
        let sender = msg_sender().unwrap();
        if let Identity::Address(addr) = sender {
            assert(addr == OWNER);
        } else {
            revert(0);
        }

        true
    }
}

The msg_sender function works as follows: msg_sender函数的工作原理如下:

  • If the caller is a contract, then Result::Ok(Sender) is returned with the ContractId sender variant. 如果调用者是一个合约,那么Result::Ok(Sender)将被返回,并带有ContractId的发送者变量。

  • If the caller is external (i.e. from a script), then all coin input owners in the transaction are checked. If all owners are the same, then Result::Ok(Sender) is returned with the Address sender variant. 如果调用者是外部的(即来自脚本),那么将检查交易中所有代币输入的所有者。如果所有所有者都是相同的,那么Result::Ok(Sender)将以Address发件人变量返回。

  • If the caller is external and coin input owners are different, then the caller cannot be determined and a Result::Err(AuthError) is returned. 如果调用者是外部的,而代币输入所有者是不同的,那么调用者就无法确定,并返回`Result::Err(AuthError)'。

合约所有权 (Contract Ownership)

Many contracts require some form of ownership for access control. To accomplish this, it is recommended that a storage variable of type Option<Identity> is used to keep track of the owner. This allows setting and revoking ownership using the variants Some(..) and None respectively. This is better, safer, and more readable than using the Identity type directly where revoking ownership has to be done using some magic value such as std::constants::ZERO_B256 or otherwise.

许多合约需要某种形式的所有权来进行访问控制。为了达到这个目的,建议使用一个Option<Identity>类型的存储变量来跟踪所有者。这允许使用变体Some(..)None分别设置和撤销所有权。这比直接使用Identity类型更好、更安全、更易读,在那里,撤销所有权必须使用一些“魔法”值,如std::constants::ZERO_B256或其他。

The following is an example of how to properly set ownership of a contract: 下面是一个如何正确设置合约所有权的例子:

    #[storage(write)]
    fn set_owner(identity: Identity) {
        storage.owner.write(Option::Some(identity));
    }

The following is an example of how to properly revoke ownership of a contract: 下面是一个如何正确撤销合约所有权的例子:

    #[storage(write)]
    fn revoke_ownership() {
        storage.owner.write(Option::None);
    }

Last updated