深入解读Starknet合约开发与部署:从Cairo编程到智能合约声明与部署随着区块链技术的发展,Starknet作为以太坊的Layer2解决方案,正吸引越来越多的开发者。它通过零知识证明(ZKP)大幅提高了交易效率和安全性。在Starknet中,Cairo作为智能合约的编程
随着区块链技术的发展,Starknet 作为以太坊的 Layer 2 解决方案,正吸引越来越多的开发者。它通过零知识证明(ZKP)大幅提高了交易效率和安全性。在 Starknet 中,Cairo 作为智能合约的编程语言,不仅提供了强大的功能,还保持了与 Rust 语言的相似性,方便开发者上手。本篇文章将深入探讨如何在 Starknet 上进行智能合约的开发、声明与部署,帮助你快速掌握这项技能。
本文从 Cairo 编程语言的基础出发,详细介绍了如何编写和部署 Starknet 智能合约。我们将通过具体的代码示例展示如何定义合约模块、实现存储、声明合约类并最终部署到 Starknet 网络上。文章还涵盖了合约声明和部署的区别,帮助读者理解如何利用 Cairo 和 Starknet 的元编程特性,高效构建和操作 Layer 2 合约。
mod
)。#[starknet::contract]
属性注解合约,这是通过元编程实现的。Storage
的结构体,需使用 #[storage]
属性进行标注。self
定义类型。在 Starknet 上,声明和部署是两个不同的操作:
声明:将智能合约代码注册到 Starknet 网络,仅需执行一次。声明后的代码称为合约类,由类哈希标识,作为智能合约实例的蓝图,但没有存储,不用于直接交易或交互。
部署:从合约类派生出实例,执行构造函数后生成具体的智能合约实例。实例有独立存储,并通过唯一的地址标识。可以通过同一个合约类部署多个实例,它们共享相同的代码,但各自的存储和地址是不同的。
Cairo 是一种可证明的编程语言,语法类似于 Rust。Cairo 并不会直接编译为字节码,而是通过 Sequencer 编译为 Sierra 代码。这种编译过程确保即便交易失败,系统也能与零知识证明兼容,避免潜在的拒绝服务攻击。Sierra 使得 Cairo 虚拟机(VM)与字节码的演变相互独立,因此可以对两端分别进行修改,而无需重构整个系统。
Cairo 程序首先编译为 Sierra (Cairo Program
→ Sierra
)。
Sierra 代码发送至 Sequencer (Send Sequencer
)。
Sequencer 将 Sierra 编译为 CASM (Sierra
→ CASM
)。
Cairo 虚拟机(VM)执行程序 (Run Cairo VM
)。
证明者(Prover)通过 SHARP 跟踪并生成有效性证明 (Prover RUN trace
)。
有效性证明被作为交易发送至以太坊,由验证者(Verifier)进行验证 (Validity proof → Ethereum Verifier
)。
最终,交易结果返回 Starknet 网络。
scarb new ownable
cd ownable
code .
ownable on main [?] via 🅒 base
➜ tree . -L 6 -I 'target'
.
├── Scarb.lock
├── Scarb.toml
├── src
│ └── lib.cairo
└── tests
└── test_contract.cairo
3 directories, 4 files
Scarb.toml
文件[package]
name = "ownable"
version = "0.1.0"
edition = "2023_11"
# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html
[dependencies]
starknet = "2.8.2"
[dev-dependencies]
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.30.0" }
[[target.starknet-contract]]
sierra = true
[scripts]
test = "snforge test"
lib.cairo
文件#[starknet::contract]
mod ownable {
use starknet::ContractAddress;
#[storage]
struct Storage {
owner: ContractAddress,
}
#[constructor]
fn constructor(ref self: ContractState, init_owner: ContractAddress) {
self.owner.write(init_owner);
}
#[external(v0)]
fn get_owner(self: @ContractState) -> ContractAddress {
self.owner.read()
}
}
运行如下命令:
scarb build
实操
ownable on main [?] via 🅒 base
➜ scarb build
Compiling snforge_scarb_plugin v0.1.0 (git+https://github.com/foundry-rs/starknet-foundry?tag=v0.30.0#196f06b251926697c3d66800f2a93ae595e76496)
Finished `release` profile [optimized] target(s) in 0.19s
Compiling ownable v0.1.0 (/Users/qiaopengjun/Code/starknet-code/hello_starknet/ownable/Scarb.toml)
Finished release target(s) in 4 seconds
在部署之前,我们需要声明合约。我们可以使用以下starkli declare
命令执行此操作!
第一步:检查 starkli
是否已经安装:
ownable on main [?] via 🅒 base took 4.3s
➜ starkli --version
0.3.4 (9f6ea67)
第二步:创建 .env
文件,内容如下:
STARKNET_RPC=https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/YLxxxxxxx
STARKNET_ACCOUNT="~/.starkli-wallets/deployer/account.json"
STARKNET_KEYSTORE="~/.starkli-wallets/deployer/keystore.json"
ACCOUNT_ADDRESS=0x077a47bd6896cc52cd980a402ac3937629bd0bf63xxxxxxxxxxxx
第三步:加载 .env
文件
ownable on main [?] via 🅒 base
➜ source .env
此命令会将 .env 文件中定义的环境变量加载到当前的 shell 会话中。确保 .env 文件在当前工作目录中,或者提供正确的文件路径。
验证环境变量是否加载成功:
运行以下命令可以输出环境变量 $STARKNET_RPC 的值:
ownable on main [?] via 🅒 base
➜ echo $STARKNET_RPC
https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/YLxxxxxxx
如果该变量已经在你的 .env 文件或系统中正确设置,该命令会显示其值。如果没有输出,可能是该变量尚未设置或未正确加载。
第四步:starkli declare 声明合约
ownable on main [?] via 🅒 base
➜ starkli declare target/dev/ownable_ownable.contract_class.json --account $STARKNET_ACCOUNT --rpc $STARKNET_RPC --keystore=$STARKNET_KEYSTORE
Enter keystore password:
Sierra compiler version not specified. Attempting to automatically decide version to use...
Network detected: sepolia. Using the default compiler version for this network: 2.7.1. Use the --compiler-version flag to choose a different version.
Declaring Cairo 1 class: 0x0238424dc7ec21465fc7b669a901adce95c3d4b7e3fcc13a4d4def68071d33b3
Compiling Sierra class to CASM with compiler version 2.7.1...
CASM class hash: 0x0371cf27992c80dc88d829fbacb41ae842531e64595520e998a2086e70ee1339
Contract declaration transaction: 0x06f3f6ebdc79e8c6f432f0e9cc4a2f9d8656ab8adc319db84259e7692ed7adb9
Class hash declared:
0x0238424dc7ec21465fc7b669a901adce95c3d4b7e3fcc13a4d4def68071d33b3
在使用 starknet deploy 部署合约时,如果合约的 constructor 具有参数,必须传递这些参数。Starknet 中的合约在部署时,构造函数负责初始化合约的状态,因此所有构造函数所要求的参数必须提供。
如果你省略构造函数参数,部署过程会失败,并提示你需要传递参数。
第一次部署没有传参,部署失败示例:
ownable on main [?] via 🅒 base
➜ starkli deploy 0x0238424dc7ec21465fc7b669a901adce95c3d4b7e3fcc13a4d4def68071d33b3 --account $STARKNET_ACCOUNT --rpc $STARKNET_RPC --keystore=$STARKNET_KEYSTORE
Enter keystore password:
Deploying class 0x0238424dc7ec21465fc7b669a901adce95c3d4b7e3fcc13a4d4def68071d33b3 with salt 0x0441b06f2d59bba3046ceede8a8890f45863423028cb6cd815f7a56806960d4e...
The contract will be deployed at address 0x04178f8af9f60b6d1cc31ee353e07167401982effc69c3899e858b58145f11f4
Error: TransactionExecutionError (tx index 0): Transaction execution has failed:
0: Error in the called contract (contract address: 0x077a47bd6896cc52cd980a402ac3937629bd0bf63da6c318ee0be3409cc2e129, class hash: 0x00816dd0297efc55dc1e7559020a3a825e81ef734b558f03c83325d4da7e6253, selector: 0x015d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad):
Error at pc=0:20259:
Cairo traceback (most recent call last):
Unknown location (pc=0:309)
Unknown location (pc=0:5819)
Unknown location (pc=0:11008)
1: Error in the called contract (contract address: 0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf, class hash: 0x07b3e05f48f0c69e4a65ce5e076a66271a527aff2c34ce1083ec6e1526997a69, selector: 0x01987cbd17808b9a23693d4de7e246a443cfe37e6e7fbaeabd7d7e6532b07c3d):
Error at pc=0:32:
Cairo traceback (most recent call last):
Unknown location (pc=0:174)
Unknown location (pc=0:127)
2: Error in the contract class constructor (contract address: 0x04178f8af9f60b6d1cc31ee353e07167401982effc69c3899e858b58145f11f4, class hash: 0x0238424dc7ec21465fc7b669a901adce95c3d4b7e3fcc13a4d4def68071d33b3, selector: 0x028ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194):
Execution failed. Failure reason: 0x4661696c656420746f20646573657269616c697a6520706172616d202331 ('Failed to deserialize param #1').
第二次部署,传参成功部署:
ownable on main [?] via 🅒 base took 7.0s
➜ source .env
ownable on main [?] via 🅒 base
➜ echo $STARKNET_RPC
https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/YLgbp9I-spejSR_9EHp_-UYDrIYdrwE1
ownable on main [?] via 🅒 base
➜ starkli deploy 0x0238424dc7ec21465fc7b669a901adce95c3d4b7e3fcc13a4d4def68071d33b3 $ACCOUNT_ADDRESS --account $STARKNET_ACCOUNT --rpc $STARKNET_RPC --keystore=$STARKNET_KEYSTORE
Enter keystore password:
Deploying class 0x0238424dc7ec21465fc7b669a901adce95c3d4b7e3fcc13a4d4def68071d33b3 with salt 0x002d3fd8fd6e8fbbd6fe21e7219ee0b336c65dca11676845ed6d51fac0f945c3...
The contract will be deployed at address 0x00691d3d0a1d664b0d9540b2568d150f04081004059188d2fe84aaf851cbb9a7
Contract deployment transaction: 0x0794d3ee93837aa104cd59293c78617523525d1e9429062287269845d26ac62d
Contract deployed:
0x00691d3d0a1d664b0d9540b2568d150f04081004059188d2fe84aaf851cbb9a7
get_owner
通过本篇文章的学习,你已经掌握了在 Starknet 上进行智能合约开发的核心流程。从 Cairo 语言的编写到智能合约的声明与部署,每一个步骤都至关重要。Starknet 提供了一个高效且安全的环境,让开发者能够快速迭代合约并进行性能优化。未来,随着 Starknet 和 Cairo 的不断发展,这些技能将帮助你在去中心化应用(dApp)开发中站稳脚跟。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!