跳转至

对象与燃气

介绍

在单笔交易中,可以创建的对象数量上限为2048,如果一笔交易尝试创建超过2048个对象,则该笔交易将被拒绝。

在单笔交易中,可以发出的事件数量上限为1024,如果一笔交易尝试发出超过1024个事件,则该笔交易将被拒绝。

每一笔交易都可以通过--gas-budget来设置交易费预算,如果当前交易超过了该预算,则该笔交易将被拒绝。

--gas-budget并非一个必须的参数,如果不手动设置,则会有一个默认的上限。

例题

接下来,考虑这么一个问题:

module obj_gas::obj_gas;

use std::string::String;
use sui::event;
use sui::random::Random;

public struct FailureMark has key {
    id: UID
}

public struct Flag has copy, drop {
    owner: address,
    mark: String
}

entry fun get_flag(random: &Random, ctx: &mut TxContext) {
    let mut generator = random.new_generator(ctx);
    if (generator.generate_u8_in_range(1, 3) == generator.generate_u8_in_range(1, 3)) {
        event::emit(Flag {
            owner: ctx.sender(),
            mark: b"success".to_string()
        });
    } else {
        let failure_mark = FailureMark {
            id: object::new(ctx)
        };
        let mark = 'mark: {
            10u64.do!(|i| {
                object::id(&failure_mark).to_bytes()
                .map!(|byte| (generator.generate_u64() % ((byte as u64) + 1)) as u8)
                .try_to_string().do!(|str| if (i > 5) return 'mark str);
            });
            b"fail".to_string()
        };
        event::emit(Flag {
            owner: ctx.sender(),
            mark
        });
        let FailureMark { id } = failure_mark;
        id.delete();
    }
}

重复调用,总有一次成功!!!但是,如果成功概率没这么高呢?或者合约限制了尝试次数呢?

可以发现,失败的逻辑明显比成功的逻辑复杂,消耗的计算资源更大,将导致交易的gas费也相应提高,那么,就可以通过--gas-budget将预算设置为成功与失败之间,使得每一笔上链的交易都是能够得到success标记的。

另一个解决办法就是利用2048这个限制,因为失败的逻辑中会额外创建一个对象,虽然该对象最终被销毁,但是只需要在创建时超过了阈值,这笔交易就会失败。也就是说,我们需要另写一个合约,创建很多很多个对象,再组合get_flag为一个PTB,以此来达到目的。

拓展

更多限制约束

相关限制和约束旨在防止滥用,并确保网络保持稳定高效,更多详情可以点击查看。

Random

sui::random模块提供的生成安全随机性的功能,与Clock一样,都是由官方提供的系统对象,地址为0x8

以下为Random在源码中的定义:

/// Singleton shared object which stores the global randomness state.
/// The actual state is stored in a versioned inner field.
public struct Random has key {
    id: UID,
    // The inner object must never be accessed outside this module as it could be used for accessing global
    // randomness via deserialization of RandomInner.
    inner: Versioned,
}

Macro

宏函数是一种定义函数的方式,它不像普通函数那样被立即求值,而是用表达式进行替换。在本文中,10u64.do!vector<u8>.map!等均为宏函数调用。

在move-book提供的Code Quality Checklist中明确表明,用宏来代替部分循环或者Option的用法是更被推荐的。