在本文中,我将分享一些示例,说明消除特殊情况如何减少代码复杂性并提高可维护性。 特殊最大值 常见的特殊情况是使用0表示“无最大值”。这种特殊情况通常很容易消除。 Specia...
本文标题减少智能合约代码复杂性并提高可维护性,作者:知世,本文有156个文字,大小约为1KB,预计阅读时间1分钟,请您欣赏。知世金融网众多优秀文章,如果想要浏览更多相关文章,请使用网站导航的搜索进行搜索。本站虽然不乏优秀之作,但仅作为投资者学习参考。
在本文中,我将分享一些示例,说明消除特殊情况如何减少代码复杂性并提高可维护性。
特殊最大值
常见的特殊情况是使用0表示“无最大值”。这种特殊情况通常很容易消除。
Special Expirations
看下面的代码
uint256 expiration;
// Use 0 to mean "no expiration".
function setExpiration(uint256 newExpiration) external {
expiration = newExpiration;
}
function doSomething() external {
require(expiration == 0 || now < expiration, "Error: expired");
...
}
在这段代码中,0是一种特殊情况,表示“没有过期”。这种特殊情况是不直观的,它增加了require语句的复杂性。
然而,真正的危险是团队中的一个新开发人员忽略了这个微妙之处,无法处理expiration==0的特殊情况。这很容易导致资金损失或其他严重问题。
这样代码就更简单更明显了:
// Default to 2**256-1 instead.
uint256 expiration = 2**256-1;
// Use 2**256-1 to mean "no expiration".
function setExpiration(uint256 newExpiration) external {
expiration = newExpiration;
}
function doSomething() external {
require(now <= expiration, "Error: expired");
...
}
这里,我使用的是uint256允许的最大值的expiration,而不是0,当涉及到时间戳时,expiration实际上是无限的。
特殊最大以太币数量
这是一个非常相似的示例,但这次涉及以太币:
uint256 maxWithdrawal;
// Use 0 to mean "no maximum".
function setMaxWithdrawal(uint256 newMax) external {
maxWithdrawal = newMax;
}
function withdraw(uint256 amount) external {
require(maxWithdrawal == 0 || amount <= maxWithdrawal, "Error: too much");
...
}
同样,我们有一个非直观的特例,我们可以通过使用一个有效的无限值来解决这个问题:
// Default to 2**256-1 instead.
uint256 maxWithdrawal = 2**256-1;
// Use 2**256-1 to mean "no maximum".
function setMaxWithdrawal(uint256 newMax) external {
maxWithdrawal = newMax;
}
function withdraw(uint256 amount) external {
require(amount <= maxWithdrawal, "Error: too much");
...
}
2256-1是最大值
注意,同样的技巧可以概括为令牌数量或任何值。由于Solidity不能表示大于2256-1的值,因此它始终可以与uint256进行比较,成为“有效无限”值
解决gas成本问题
通常,在gas成本方面需要进行权衡。人们最终将默认值设为0的一个典型原因是存储非零值会耗费大量gas。
如果存储成本对于您的用例而言是很高的,请考虑以下技巧:
uint256 _expiration; // 0 still means "no expiration"
...
// Properly handle the special cases in one place.
function expiration() internal view returns (uint256) {
return _expiration > 0 ? _expiration : 2**256-1;
}
function doSomething() external {
require(now < expiration(), "Error: expired");
}
在此代码中,写入存储的_expiration值默认情况下为0,与以前的特殊含义相同。但是,我介绍了一个辅助函数expiration(),它将0转换为不太特殊的值2256-1。这意味着我的其余代码无需处理这种特殊情况。
考虑将此技术与自定义的linter规则配对使用,以确保您不会在expiration()函数之外的任何地方直接读取_expiration。
特殊地址
关于地址,我经常看到两种特殊情况:
1. 地址0通常是不允许的。
2. 不允许使用特定地址(通常是特权角色)。
特别地址0
这是一些熟悉的代码,其中使用0作为特殊情况:
function transfer(address to, uint256 amount) external {
require(to != address(0), "Error: can't send to 0x0");
...
}
禁止使用地址0通常是为了保护用户不受错误的影响。将令牌发送到地址0通常不会比将它们发送到地址1更糟糕,但0是默认值,因此更可能由于有错误的工具或库而意外传入。
我个人不喜欢这种地址0的支票,但这很少有问题。与前面的示例不同,如果开发人员在维护代码时忘记了这种特殊情况,那么一切都不会中断。
特殊角色地址
这段代码比上一段要麻烦得多:
address owner;
constructor() public {
owner = msg.sender;
}
function transfer(address to, uint256 amount) external {
require(to != owner, "Error: can't send to owner.");
...
}
当我看到这样的代码时,我的直接问题是为什么所有者地址无法接收令牌。这样的检查通常是为了将安全控制措施放在适当的位置,但通常无法解决Sybil攻击,因为系统中的多个地址由同一个人控制。
在这个特定的例子中,所有者可以简单地接收具有不同地址的令牌。如果这违反了合同的安全性假设,那就有问题了。
像这样的特殊情况是一种代码气息,但这并不意味着它们总是应该被消除。要做的重要事情是记录为什么需要这种特殊情况,并考虑替代方案。
总结
特殊情况会导致代码复杂性,从而导致错误。
在可能的情况下,完全消除特殊情况。
2256-1是最大值的良好替代品。
地址0的特殊情况通常可以。
其他特定地址的特殊情况是代码气味。
如果决定在代码中使用具有特殊意义的值,请尝试隔离用于处理这些值的代码。
本文相关推荐:
以上便是知世金融网给大家分享的关于减少智能合约代码复杂性并提高可维护性/qkl/27566.html的相关信息了,希望能帮助到大家,更多金融相关信息,敬请关注知世金融网!
网站内容均来自互联网,如侵害您的利益联系客服进行删除!
上一篇:针对两篇以太坊批评文的反批评
下一篇:TuringNetwork图灵网络打造加密偶像,用区块链打破经纪公司垄断
本文标题:减少智能合约代码复杂性并提高可维护性
本文地址:/index.php?s=article&c=search&keyword=%E5%8F%AF%E7%BB%B4%E6%8A%A4%E6%80%A7