
Starknet 春季 DeFi 激励计划
原文:Starknet Foundation Introduces: The Start of DeFi Spring 翻译及校对:「Starknet 中文社区」 📑 转载请注明出处 🕹️精选速览「Starknet 春季 DeFi 激励计划」4000 万 STRK 奖励用户3 月 7 日开始领取激励生态任务获得专属 NFT引言2023 年 11 月 9 日,Starknet 基金会宣布 Starknet DeFi 委员会成立及其成员任命,该委员会的任务是促进 Starknet DeFi 增长。 经过两个月的内部和外部研究后,Starknet 基金会非常兴奋地宣布推出为实现这些目标而量身定做的计划。 Starknet 基金会与 OpenBlock Labs 的合作,推出「Starknet 春季 DeFi 激励计划」。本为期六到八个月的项目,在此期间将向参与 Starknet 上 DeFi 协议的参与者分发 4000 万 STRK。 这是 DeFi 委员会扩大 Starknet DeFi 规模系列举措的第一步。第一部分:STRK 分发DeFi 委员会计划在接下来的六到八个月内,D...

Starknet 中文社区 2023 年终汇总
🎀 概述关注回顾 Starknet 在 2023 年的里程碑事件以及「Starknet 中文社区」的丰硕成果。 在网络生态中,Starknet 实现了一系列重要版本和重要事件更新,不仅在技术上取得了显著进展,而且扩展了众多核心开源技术栈。在生态系统中,推进发展 Starknet 优秀项目,在 TVL 和用户量等数据方面实现了可观增长。 「Starknet 中文社区」在过去一年中同样达成令人瞩目的进步,输入内容包括博客翻译、原创文章和视频、组织各类活动、合作 Cairo 训练营等各类活动,这些重要内容显示出社区成员的积极贡献和创造力,以及中文社区的独特魅力,为中国用户提供更多全面了解 Starknet 区块链的方式。 StarkWare 和 Starknet 团队和生态合作伙伴的共同努力实现 Cairo 1.0 成功升级,而 Cairo 开发者数量在过去一年中取得了巨大增长,这一成就让更多区块链开发者看到了 Starknet 背后团队的技术实力,也从侧面反映出 Starknet 生态系统中合作伙伴的紧密协作。 总而言之,Starknet 和「Starknet 中文社区」在生态、技...

聚沙成塔:StarkWare 年度回顾
原文:From Milestones to Masterstrokes: StarkWare’s Year in Review 翻译及校对:「Starknet 中文社区」 📑 转载请注明出处 🕹️不论是现在还是将来,STARK 技术都被视为助力去中心化应用(dApps)在以太坊上实现扩展和繁荣的秘密武器。概要:Starknet 为复杂、高计算要求、创新型的 DeFi 平台、链上游戏、动态 NFT 等应用奠定了基础。Starknet 在所有 L2(以及一些 L1)中,持续拥有增长最快的开发者生态系统。StarkWare 在 2023 年开源了 Stone 证明器、Starknet 排序器和 Papyrus 全节点等关键元素。继续阅读,了解我们的亮点以及 2023 年 Starknet 生态系统的整体进展。去中心化和社区STARK 技术:达到新高度在以太坊上的创新开源时刻:为协议设定新标准Starknet 应用链社区参与和活动去中心化与社区扩展Starknet 上的游戏热潮由于 L1 在规模、用户体验和高成本等方面的限制,创建成功的链上游戏几乎是不可能实现的事情。但随着有效性 R...
「Starknet 中文」社区致力于 Starknet 在中文世界发展,提供最全生态资讯。

Starknet 春季 DeFi 激励计划
原文:Starknet Foundation Introduces: The Start of DeFi Spring 翻译及校对:「Starknet 中文社区」 📑 转载请注明出处 🕹️精选速览「Starknet 春季 DeFi 激励计划」4000 万 STRK 奖励用户3 月 7 日开始领取激励生态任务获得专属 NFT引言2023 年 11 月 9 日,Starknet 基金会宣布 Starknet DeFi 委员会成立及其成员任命,该委员会的任务是促进 Starknet DeFi 增长。 经过两个月的内部和外部研究后,Starknet 基金会非常兴奋地宣布推出为实现这些目标而量身定做的计划。 Starknet 基金会与 OpenBlock Labs 的合作,推出「Starknet 春季 DeFi 激励计划」。本为期六到八个月的项目,在此期间将向参与 Starknet 上 DeFi 协议的参与者分发 4000 万 STRK。 这是 DeFi 委员会扩大 Starknet DeFi 规模系列举措的第一步。第一部分:STRK 分发DeFi 委员会计划在接下来的六到八个月内,D...

Starknet 中文社区 2023 年终汇总
🎀 概述关注回顾 Starknet 在 2023 年的里程碑事件以及「Starknet 中文社区」的丰硕成果。 在网络生态中,Starknet 实现了一系列重要版本和重要事件更新,不仅在技术上取得了显著进展,而且扩展了众多核心开源技术栈。在生态系统中,推进发展 Starknet 优秀项目,在 TVL 和用户量等数据方面实现了可观增长。 「Starknet 中文社区」在过去一年中同样达成令人瞩目的进步,输入内容包括博客翻译、原创文章和视频、组织各类活动、合作 Cairo 训练营等各类活动,这些重要内容显示出社区成员的积极贡献和创造力,以及中文社区的独特魅力,为中国用户提供更多全面了解 Starknet 区块链的方式。 StarkWare 和 Starknet 团队和生态合作伙伴的共同努力实现 Cairo 1.0 成功升级,而 Cairo 开发者数量在过去一年中取得了巨大增长,这一成就让更多区块链开发者看到了 Starknet 背后团队的技术实力,也从侧面反映出 Starknet 生态系统中合作伙伴的紧密协作。 总而言之,Starknet 和「Starknet 中文社区」在生态、技...

聚沙成塔:StarkWare 年度回顾
原文:From Milestones to Masterstrokes: StarkWare’s Year in Review 翻译及校对:「Starknet 中文社区」 📑 转载请注明出处 🕹️不论是现在还是将来,STARK 技术都被视为助力去中心化应用(dApps)在以太坊上实现扩展和繁荣的秘密武器。概要:Starknet 为复杂、高计算要求、创新型的 DeFi 平台、链上游戏、动态 NFT 等应用奠定了基础。Starknet 在所有 L2(以及一些 L1)中,持续拥有增长最快的开发者生态系统。StarkWare 在 2023 年开源了 Stone 证明器、Starknet 排序器和 Papyrus 全节点等关键元素。继续阅读,了解我们的亮点以及 2023 年 Starknet 生态系统的整体进展。去中心化和社区STARK 技术:达到新高度在以太坊上的创新开源时刻:为协议设定新标准Starknet 应用链社区参与和活动去中心化与社区扩展Starknet 上的游戏热潮由于 L1 在规模、用户体验和高成本等方面的限制,创建成功的链上游戏几乎是不可能实现的事情。但随着有效性 R...
「Starknet 中文」社区致力于 Starknet 在中文世界发展,提供最全生态资讯。

Subscribe to Starknet 中文

Subscribe to Starknet 中文
Share Dialog
Share Dialog
<100 subscribers
<100 subscribers


作者:Darington Nnam 原文:Journey Through Cairo IX— Ultimate Guide To Testing Your Contracts With Protostar 翻译:Louis Wang 校对:「StarkNet 中文社区」
欢迎来到我们的系列文章「Cairo之旅」第九讲!上一讲我们开始部署 Starknet 合约,今天我们开始测试合约。
像往常一样,如果你是中途加入,建议从头开始看我们的文章。

单元测试不仅作为软件工程中广泛使用的术语,同样适用于智能合约开发中。因此在学习前,先通过几句话了解什么是单元测试。
单元测试是一种对软件的单个单元或组件进行测试。单元测试一般在软件应用的开发阶段进行,确保某个应用所有部分都按预期运行。它们通常用于软件开发的各个领域,但在编写智能合约时有更重要的作用。
当编写大量代码时,很有可能会存在现有功能错误,或者与预期执行不相符。经常会出现智能合约通过了编译但仍然存在代码错误的情况。
虽然大多数开发人员都不爱写测试,或者写覆盖面小的测试,但是制作测试有利于:
单元测试有助于在应用开发早期修复错误,避免日后被攻击造成亏损。
有助于开发人员理解测试代码库,以便做出修改。
高质量的单元测试可以作为项目(指南)文档。
作者:Darington Nnam 原文:Journey Through Cairo IX— Ultimate Guide To Testing Your Contracts With Protostar 翻译:Louis Wang 校对:「StarkNet 中文社区」
欢迎来到我们的系列文章「Cairo之旅」第九讲!上一讲我们开始部署 Starknet 合约,今天我们开始测试合约。
像往常一样,如果你是中途加入,建议从头开始看我们的文章。

单元测试不仅作为软件工程中广泛使用的术语,同样适用于智能合约开发中。因此在学习前,先通过几句话了解什么是单元测试。
单元测试是一种对软件的单个单元或组件进行测试。单元测试一般在软件应用的开发阶段进行,确保某个应用所有部分都按预期运行。它们通常用于软件开发的各个领域,但在编写智能合约时有更重要的作用。
当编写大量代码时,很有可能会存在现有功能错误,或者与预期执行不相符。经常会出现智能合约通过了编译但仍然存在代码错误的情况。
虽然大多数开发人员都不爱写测试,或者写覆盖面小的测试,但是制作测试有利于:
单元测试有助于在应用开发早期修复错误,避免日后被攻击造成亏损。
有助于开发人员理解测试代码库,以便做出修改。
高质量的单元测试可以作为项目(指南)文档。

明白了写测试的重要性后,让我们深入了解一下如何为 Cairo 合约写测试吧!
类似于 Foundry 让 Solidity 开发者在 Solidity 中编写单元测试,感谢 Protostar 团队的努力让 Cairo 开发者在 Cairo 中编写单元测试更容易!
Protostar 的测试实例:
@external
func test_increase_balance{syscall_ptr: felt*, range_check_ptr, pedersen_ptr: HashBuiltin*}() {
let (result_before) = balance.read();
assert result_before = 0;
increase_balance(42);
let (result_after) = balance.read();
assert result_after = 42;
return ();
}
如上述,有了 Protostar 就可以用 Cairo 写测试。从这段代码中,你可以发现关于编写单元测试:
所有的测试用例都是外部函数,并以 test_ 为前缀。
在这里没有给函数传递参数,因为我们手动提供了所有需要的测试参数。
可以使用 assert 关键字更容易进行比较。
注意:在 Cairo 中使用 assert 关键字,如果左边的变量还没有设置,就会自动把右边的变量分配给左边的变量,因此安全的做法是确保我们要比较的常数总是在左边。
为了进一步解释这个问题,假设我们有一个常数。
const NUMBER = 30;
我们想获得一个函数的返回值并检查它是否等于常数,首先确保常数在左边,如果函数返回一个空参数,我们不想让 Cairo 分配常数。
所以我们需要改写:
let (num) = get_number();
assert NUMBER = num;
在测试用例之前需要进行某些操作,比如部署一个合约并记录其地址,设置一些重要变量等。
类似于在 mocha 和 chai 中使用的 before 钩子 (Hook),我们可以在 protostar 中使用 setup 钩子预先在名叫 context 的存储变量中设置一些变量,并将它们从一个函数传递到另一个函数。
例如,我们可以使用设置钩子来部署我们在上一篇文章中的 starknet 合约,并将合约地址存储在上下文中,然后传递给其他测试案例:
@external
func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{context.address = deploy_contract("./src/starknet.cairo", [ids.NAME]).contract_address %}
return ();
}
在开始写测试时会进一步说明。
引用 protostar 官方文档中的话「大多数时候,不能只用断言来测试智能合约。一些测试案例需要操作区块链的状态,以及检查还原和事件。为此,Protostar 提供了一套作弊代码。」
还需要注意的是,这些作弊代码只能通过提示来访问,而不应该明确地写在你的 Cairo 合约中!
你可以在这里找到全部的,但为了控制篇幅,我们只介绍今天用到的四个:
deploy_contract
expect_revert
expect_events
start_prank
这个作弊代码部署一个合同,输入合同的相对路径和构造函数参数(如果有的话)。
要使用这个作弊代码,我们要传入合同代码的相对路径,以及构造函数的参数:
%{ deploy_contract("./src/starknet.cairo", [322918500091226412576622]) %}
由于部署合约的过程通常很慢,建议你在设置钩子中使用这个作弊代码,这样你只需要执行一次这个动作。deploy_contract 作弊代码还可以访问已部署合同的合同地址,可以访问并存储在一个上下文变量中,以便从测试案例中访问。
%{context.address = deploy_contract("./src/starknet.cairo", [[ids.NAME](http://ids.name/)]).contract_address %}
这个作弊代码是用来检查它下面的某个操作是否以指定的错误恢复,如果没有,则测试失败。换句话说,你可以用这个测试来确认合约回滚情况是否按预期工作。
例如,如果我们通过 main.cairo(由 protostar 初始化时创建的默认合约)的测试,我们会发现下面这段代码,它测试函数 increase_balance 会在输入为负数时回滚。
%{ expect_revert("TRANSACTION_FAILED", "Amount must be positive") %}
increase_balance(-42);
可以看到,expect_revert 执行了它下面的函数调用,并检查错误的类型是否为 "TRANSACTION_FAILED",以及是否符合 "Amount must be positive",如果不符合则测试失败。
这个作弊代码帮助你检查从你的 Starknet 合约中发出的事件是否与一些预期的事件相匹配。
与 expect_revert 不同,你可以在函数测试案例中的任何地方使用这个作弊代码,因为 Protostar 在测试案例完成后会检查发出的事件:
%{ expect_events({"name": "stored_name", "data" : [ids.CALLER, [ids.NAME](http://ids.name/)]}) %}
这个作弊代码在编写单元测试时是非常重要的。你可以用它在编写单元测试时将 caller_address 改为选定的任何地址。使用这个代码比相对麻烦,因为使用时必须初始化一个持有新地址的可调用程序(像一个状态),然后在完成后取消初始化它。
也可以初始化不止一个来进行不同地址的测试:
%{ stop_prank = start_prank(0x00A596deDe49d268d6aD089B5aBdD089BE92D089B191e48) %}
// Your test logic goes here.
%{ stop_prank() %}
我们使用 start_prank 开始一个 prank,并同时初始化一个可调用的 stop_prank。我们可以通过调用 stop_prank() 来结束 prank,在 start_prank 和 stop_prank() 之间的任何函数调用将使用指定地址作为调用者地址。
哇,我们已经讲了很多了。现在是时候实践知识了,为我们上一篇文章中的 Starknet 合约写一个测试。
你也可以查看合约代码。
测试分为五个部分检测我们到目前为止所学的所有知识。
指明必要的导入。
指明整个测试所需的一些常量。
使用钩子部署我们的合约。
测试 store_name 函数。
测试 get_name 函数。
对于这个测试,我们将导入 HashBuiltin 库函数,以及我们想在 Starknet 合约中运行测试的所有函数(store_name 和 get_name 函数)。
%lang starknet
from starkware.cairo.common.cairo_builtins import HashBuiltin
from src.starknet import store_name, get_name
在这个测试中,我们需要两个常量:我们打算用来开始测试的呼叫地址,以及我们想作为参数提供给 store_name 函数的名称(用 felts 表示)。
const CALLER = 0x00A596deDe49d268d6aD089B56CC76598af3E949183a8ed10aBdE924de191e48;
const NAME = 322918500091226412576622;
如何用钩子部署合约:
@external
func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{context.address = deploy_contract("./src/starknet.cairo", [ids.NAME]).contract_address %}
return ();
}
从上面的代码中,首先通过使用函数名 setup 来指定我们正在使用一个设置钩子。然后使用 deploy_contract 作弊代码来部署我们的合约,提供我们的合约代码的路径,以及一个参数 NAME。
注意我们使用 ids.NAME,而不是仅仅使用 NAME,这就是我们在 hint 中访问 Cairo 常量的方法。
@external
func test_store_name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{ stop_prank = start_prank(ids.CALLER) %}
store_name(NAME);
%{ expect_events({"name": "stored_name", "data" : [ids.CALLER, ids.NAME]}) %}
%{ stop_prank() %}
return ();
}
测试可以帮助你理解一个函数的行为方式,从我们的函数中,你会注意到我们得到了 caller_address,然后我们用它作为一个键来存储我们的 name 参数。
在 Protostar 中,caller_address 默认为 0,但可以使用 start_prank 来改变这个。因此,你可以从上述代码中看到,首先需要启动一个 prank 来改变来呼叫地址。
接下来我们调用 store_name 函数,提供前面的常量 NAME 作为参数。
最后,我们检查 Starknet 的状态中发出的事件,以确保它与我们提供的参数 (CALLER 和 NAME) 相匹配,最后才停止 prank。
@external
func test_get_name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{ stop_prank = start_prank(ids.CALLER) %}
store_name(NAME);
let (name) = get_name(CALLER);
assert NAME = name;
%{ stop_prank() %}
return ();
}
这个测试非常简单。我们再次重复前面的过程,因为我们需要存储一个名字然后获取这个名字。
所以我们从 prank 开始,存储一个名字,然后调用 get_name 函数,提供常数 CALLER 作为参数。
需要注意这一行:
assert NAME = name;
正如你所看到的,我们遵守了前面的规则,把常数 NAME 放在左手边,这样 Cairo 就不会进行赋值而是比较。
我们的完整代码:
%lang starknet
from starkware.cairo.common.cairo_builtins import HashBuiltin
from src.starknet import store_name, get_name
const CALLER = 0x00A596deDe49d268d6aD089B56CC76598af3E949183a8ed10aBdE924de191e48;
const NAME = 322918500091226412576622;
@external
func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{context.address = deploy_contract("./src/starknet.cairo", [ids.NAME]).contract_address %}
return ();
}
@external
func test_store_name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{ stop_prank = start_prank(ids.CALLER) %}
store_name(NAME);
%{ expect_events({"name": "stored_name", "data" : [ids.CALLER, ids.NAME]}) %}
%{ stop_prank() %}
return ();
}
@external
func test_get_name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{ stop_prank = start_prank(ids.CALLER) %}
store_name(NAME);
let (name) = get_name(CALLER);
assert NAME = name;
%{ stop_prank() %}
return ();
}
今天我们学习了如何用 Protostar 写测试合约,以及其他的作弊代码,它们在编写测试时可能非常有用。你也可以在这里找到 OnlyDust 的深度测试脚本,它实现了 Protostar 的大部分作弊代码。
我们将在下节课深入研究 Empiric 的预言机。如果觉得本教程对你有帮助,转发分享给其他人吧~

明白了写测试的重要性后,让我们深入了解一下如何为 Cairo 合约写测试吧!
类似于 Foundry 让 Solidity 开发者在 Solidity 中编写单元测试,感谢 Protostar 团队的努力让 Cairo 开发者在 Cairo 中编写单元测试更容易!
Protostar 的测试实例:
@external
func test_increase_balance{syscall_ptr: felt*, range_check_ptr, pedersen_ptr: HashBuiltin*}() {
let (result_before) = balance.read();
assert result_before = 0;
increase_balance(42);
let (result_after) = balance.read();
assert result_after = 42;
return ();
}
如上述,有了 Protostar 就可以用 Cairo 写测试。从这段代码中,你可以发现关于编写单元测试:
所有的测试用例都是外部函数,并以 test_ 为前缀。
在这里没有给函数传递参数,因为我们手动提供了所有需要的测试参数。
可以使用 assert 关键字更容易进行比较。
注意:在 Cairo 中使用 assert 关键字,如果左边的变量还没有设置,就会自动把右边的变量分配给左边的变量,因此安全的做法是确保我们要比较的常数总是在左边。
为了进一步解释这个问题,假设我们有一个常数。
const NUMBER = 30;
我们想获得一个函数的返回值并检查它是否等于常数,首先确保常数在左边,如果函数返回一个空参数,我们不想让 Cairo 分配常数。
所以我们需要改写:
let (num) = get_number();
assert NUMBER = num;
在测试用例之前需要进行某些操作,比如部署一个合约并记录其地址,设置一些重要变量等。
类似于在 mocha 和 chai 中使用的 before 钩子 (Hook),我们可以在 protostar 中使用 setup 钩子预先在名叫 context 的存储变量中设置一些变量,并将它们从一个函数传递到另一个函数。
例如,我们可以使用设置钩子来部署我们在上一篇文章中的 starknet 合约,并将合约地址存储在上下文中,然后传递给其他测试案例:
@external
func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{context.address = deploy_contract("./src/starknet.cairo", [ids.NAME]).contract_address %}
return ();
}
在开始写测试时会进一步说明。
引用 protostar 官方文档中的话「大多数时候,不能只用断言来测试智能合约。一些测试案例需要操作区块链的状态,以及检查还原和事件。为此,Protostar 提供了一套作弊代码。」
还需要注意的是,这些作弊代码只能通过提示来访问,而不应该明确地写在你的 Cairo 合约中!
你可以在这里找到全部的,但为了控制篇幅,我们只介绍今天用到的四个:
deploy_contract
expect_revert
expect_events
start_prank
这个作弊代码部署一个合同,输入合同的相对路径和构造函数参数(如果有的话)。
要使用这个作弊代码,我们要传入合同代码的相对路径,以及构造函数的参数:
%{ deploy_contract("./src/starknet.cairo", [322918500091226412576622]) %}
由于部署合约的过程通常很慢,建议你在设置钩子中使用这个作弊代码,这样你只需要执行一次这个动作。deploy_contract 作弊代码还可以访问已部署合同的合同地址,可以访问并存储在一个上下文变量中,以便从测试案例中访问。
%{context.address = deploy_contract("./src/starknet.cairo", [[ids.NAME](http://ids.name/)]).contract_address %}
这个作弊代码是用来检查它下面的某个操作是否以指定的错误恢复,如果没有,则测试失败。换句话说,你可以用这个测试来确认合约回滚情况是否按预期工作。
例如,如果我们通过 main.cairo(由 protostar 初始化时创建的默认合约)的测试,我们会发现下面这段代码,它测试函数 increase_balance 会在输入为负数时回滚。
%{ expect_revert("TRANSACTION_FAILED", "Amount must be positive") %}
increase_balance(-42);
可以看到,expect_revert 执行了它下面的函数调用,并检查错误的类型是否为 "TRANSACTION_FAILED",以及是否符合 "Amount must be positive",如果不符合则测试失败。
这个作弊代码帮助你检查从你的 Starknet 合约中发出的事件是否与一些预期的事件相匹配。
与 expect_revert 不同,你可以在函数测试案例中的任何地方使用这个作弊代码,因为 Protostar 在测试案例完成后会检查发出的事件:
%{ expect_events({"name": "stored_name", "data" : [ids.CALLER, [ids.NAME](http://ids.name/)]}) %}
这个作弊代码在编写单元测试时是非常重要的。你可以用它在编写单元测试时将 caller_address 改为选定的任何地址。使用这个代码比相对麻烦,因为使用时必须初始化一个持有新地址的可调用程序(像一个状态),然后在完成后取消初始化它。
也可以初始化不止一个来进行不同地址的测试:
%{ stop_prank = start_prank(0x00A596deDe49d268d6aD089B5aBdD089BE92D089B191e48) %}
// Your test logic goes here.
%{ stop_prank() %}
我们使用 start_prank 开始一个 prank,并同时初始化一个可调用的 stop_prank。我们可以通过调用 stop_prank() 来结束 prank,在 start_prank 和 stop_prank() 之间的任何函数调用将使用指定地址作为调用者地址。
哇,我们已经讲了很多了。现在是时候实践知识了,为我们上一篇文章中的 Starknet 合约写一个测试。
你也可以查看合约代码。
测试分为五个部分检测我们到目前为止所学的所有知识。
指明必要的导入。
指明整个测试所需的一些常量。
使用钩子部署我们的合约。
测试 store_name 函数。
测试 get_name 函数。
对于这个测试,我们将导入 HashBuiltin 库函数,以及我们想在 Starknet 合约中运行测试的所有函数(store_name 和 get_name 函数)。
%lang starknet
from starkware.cairo.common.cairo_builtins import HashBuiltin
from src.starknet import store_name, get_name
在这个测试中,我们需要两个常量:我们打算用来开始测试的呼叫地址,以及我们想作为参数提供给 store_name 函数的名称(用 felts 表示)。
const CALLER = 0x00A596deDe49d268d6aD089B56CC76598af3E949183a8ed10aBdE924de191e48;
const NAME = 322918500091226412576622;
如何用钩子部署合约:
@external
func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{context.address = deploy_contract("./src/starknet.cairo", [ids.NAME]).contract_address %}
return ();
}
从上面的代码中,首先通过使用函数名 setup 来指定我们正在使用一个设置钩子。然后使用 deploy_contract 作弊代码来部署我们的合约,提供我们的合约代码的路径,以及一个参数 NAME。
注意我们使用 ids.NAME,而不是仅仅使用 NAME,这就是我们在 hint 中访问 Cairo 常量的方法。
@external
func test_store_name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{ stop_prank = start_prank(ids.CALLER) %}
store_name(NAME);
%{ expect_events({"name": "stored_name", "data" : [ids.CALLER, ids.NAME]}) %}
%{ stop_prank() %}
return ();
}
测试可以帮助你理解一个函数的行为方式,从我们的函数中,你会注意到我们得到了 caller_address,然后我们用它作为一个键来存储我们的 name 参数。
在 Protostar 中,caller_address 默认为 0,但可以使用 start_prank 来改变这个。因此,你可以从上述代码中看到,首先需要启动一个 prank 来改变来呼叫地址。
接下来我们调用 store_name 函数,提供前面的常量 NAME 作为参数。
最后,我们检查 Starknet 的状态中发出的事件,以确保它与我们提供的参数 (CALLER 和 NAME) 相匹配,最后才停止 prank。
@external
func test_get_name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{ stop_prank = start_prank(ids.CALLER) %}
store_name(NAME);
let (name) = get_name(CALLER);
assert NAME = name;
%{ stop_prank() %}
return ();
}
这个测试非常简单。我们再次重复前面的过程,因为我们需要存储一个名字然后获取这个名字。
所以我们从 prank 开始,存储一个名字,然后调用 get_name 函数,提供常数 CALLER 作为参数。
需要注意这一行:
assert NAME = name;
正如你所看到的,我们遵守了前面的规则,把常数 NAME 放在左手边,这样 Cairo 就不会进行赋值而是比较。
我们的完整代码:
%lang starknet
from starkware.cairo.common.cairo_builtins import HashBuiltin
from src.starknet import store_name, get_name
const CALLER = 0x00A596deDe49d268d6aD089B56CC76598af3E949183a8ed10aBdE924de191e48;
const NAME = 322918500091226412576622;
@external
func __setup__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{context.address = deploy_contract("./src/starknet.cairo", [ids.NAME]).contract_address %}
return ();
}
@external
func test_store_name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{ stop_prank = start_prank(ids.CALLER) %}
store_name(NAME);
%{ expect_events({"name": "stored_name", "data" : [ids.CALLER, ids.NAME]}) %}
%{ stop_prank() %}
return ();
}
@external
func test_get_name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
%{ stop_prank = start_prank(ids.CALLER) %}
store_name(NAME);
let (name) = get_name(CALLER);
assert NAME = name;
%{ stop_prank() %}
return ();
}
今天我们学习了如何用 Protostar 写测试合约,以及其他的作弊代码,它们在编写测试时可能非常有用。你也可以在这里找到 OnlyDust 的深度测试脚本,它实现了 Protostar 的大部分作弊代码。
我们将在下节课深入研究 Empiric 的预言机。如果觉得本教程对你有帮助,转发分享给其他人吧~
No activity yet