可升级合约

在Starknet中,合约分为两个部分:合约类和合约实例。 这种划分遵循了面向对象编程语言中的类和实例的概念。 这样,我们区分了对象的定义和实现。

合约类是合约的定义:它指定了合约的行为方式。 合约类包含了关键信息,如Cairo字节码、提示信息、入口点名称等, 以及一切明确定义合约类语义的内容。

为了识别不同的合约类,Starknet为每个类分配一个唯一的标识符:类哈希。 合约实例是对应于特定合约类的已部署合约。 可以将其视为在诸如Java等语言中对象的一个实例。

每个类由其类哈希值标识,类似于面向对象编程语言中的类名。合约实例是对应于某个类的已部署合约。

当调用replace_class_syscall函数,你可以将已部署的合约升级到更新的版本。通过使用这个函数,你可以更新与已部署合约相关联的类哈希,从而有效地升级合约的实现。然而,这不会修改合约中的存储,因此合约中存储的所有数据将保持不变。

为了说明这个概念,让我们以两个合约为例:UpgradeableContract_V0UpgradeableContract_V1。 首先,部署UpgradeableContract_V0作为初始版本。接下来,发送一个调用upgrade函数的交易,将部署合约的类哈希升级为UpgradeableContract_V1的类哈希。然后,调用合约上的version方法,查看合约是否已升级到V1版本。

use starknet::class_hash::ClassHash;

#[starknet::interface]
trait IUpgradeableContract<TContractState> {
    fn upgrade(ref self: TContractState, impl_hash: ClassHash);
    fn version(self: @TContractState) -> u8;
}

#[starknet::contract]
mod UpgradeableContract_V0 {
    use starknet::class_hash::ClassHash;
    use starknet::SyscallResultTrait;

    #[storage]
    struct Storage {}


    #[event]
    #[derive(Drop, starknet::Event)]
    enum Event {
        Upgraded: Upgraded
    }

    #[derive(Drop, starknet::Event)]
    struct Upgraded {
        implementation: ClassHash
    }

    #[abi(embed_v0)]
    impl UpgradeableContract of super::IUpgradeableContract<ContractState> {
        fn upgrade(ref self: ContractState, impl_hash: ClassHash) {
            assert(!impl_hash.is_zero(), 'Class hash cannot be zero');
            starknet::replace_class_syscall(impl_hash).unwrap_syscall();
            self.emit(Event::Upgraded(Upgraded { implementation: impl_hash }))
        }

        fn version(self: @ContractState) -> u8 {
            0
        }
    }
}

Voyager 上访问合约或在 Remix中尝试它 。

use starknet::class_hash::ClassHash;

#[starknet::interface]
trait IUpgradeableContract<TContractState> {
    fn upgrade(ref self: TContractState, impl_hash: ClassHash);
    fn version(self: @TContractState) -> u8;
}

#[starknet::contract]
mod UpgradeableContract_V1 {
    use starknet::class_hash::ClassHash;
    use starknet::SyscallResultTrait;

    #[storage]
    struct Storage {}


    #[event]
    #[derive(Drop, starknet::Event)]
    enum Event {
        Upgraded: Upgraded
    }

    #[derive(Drop, starknet::Event)]
    struct Upgraded {
        implementation: ClassHash
    }

    #[abi(embed_v0)]
    impl UpgradeableContract of super::IUpgradeableContract<ContractState> {
        fn upgrade(ref self: ContractState, impl_hash: ClassHash) {
            assert(!impl_hash.is_zero(), 'Class hash cannot be zero');
            starknet::replace_class_syscall(impl_hash).unwrap_syscall();
            self.emit(Event::Upgraded(Upgraded { implementation: impl_hash }))
        }

        fn version(self: @ContractState) -> u8 {
            1
        }
    }
}

Voyager 上访问合约或在 Remix 中尝试它。

Last change: 2023-10-12, commit: 90aa7c0