有几点以太坊上的 DApp 跟普通的应用程序有着天壤之别。
把智能协议传上以太坊之后,它就变得不可更改, 这种永固性意味着你的代码永远不能被调整或更新。
你编译的程序会一直,永久的,不可更改的,存在以太坊上。这就是 Solidity 代码的安全性如此重要的一个原因。如果你的智能协议有任何漏洞,即使你发现了也无法补救。你只能让你的用户们放弃这个智能协议,然后转移到一个新的修复后的合约上。
在引用外部关系的时候,不能硬编码,而要采用“函数”,以便于 DApp 的关键部分可以以参数形式修改。
Ownable 合约基本都会这么干:
合约创建,构造函数先行,将其 owner 设置为msg.sender(其部署者)
为它加上一个修饰符 onlyOwner,它会限制陌生人的访问,将访问某些函数的权限锁定在 owner 上。
允许将合约所有权转让给他人。
function Ownable()是一个 _ constructor_ (构造函数),构造函数不是必须的,它与合约同名,构造函数一生中唯一的一次执行,就是在合约最初被创建的时候。
modifier onlyOwner()。 修饰符跟函数很类似,不过是用来修饰其他已有函数用的, 在其他语句执行前,为它检查下先验条件。 在这个例子中,我们就可以写个修饰符 onlyOwner 检查下调用者,确保只有合约的主人才能运行本函数。
函数修饰符看起来跟函数没什么不同,不过关键字modifier 告诉编译器,这是个modifier(修饰符),而不是个function(函数)。它不能像函数那样被直接调用,只能被添加到函数定义的末尾,用以改变函数的行为。
/**
* @dev 调用者不是‘主人’,就会抛出异常
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
onlyOwner 函数修饰符是这么用的:
contract MyContract is Ownable {
event LaughManiacally(string laughter);
//注意! `onlyOwner`上场 :
function likeABoss() external onlyOwner {
LaughManiacally("Muahahahaha");
}
}
一个 DApp 收取多少 gas 取决于功能逻辑的复杂程度,一次操作所需要花费的 gas 等于这个操作背后的所有运算花销的总和。
注意:如果你使用侧链,倒是不一定需要付费,比如咱们在 Loom Network 上构建的 CryptoZombies 就免费。
当 uint 定义在一个 struct 中的时候,尽量使用最小的整数子类型以节约空间。 并且把同样类型的变量放一起(即在 struct 中将把变量按照类型依次放置),这样 Solidity 可以将存储空间最小化。例如,有两个 struct:
uint c; uint32 a; uint32 b; 和 uint32 a; uint c; uint32 b;
前者比后者需要的gas更少,因为前者把uint32放一起了。
Solidity 使用自己的本地时间单位。
变量 now 将返回当前的unix时间戳(自1970年1月1日以来经过的秒数)
Solidity 还包含秒(seconds),分钟(minutes),小时(hours),天(days),周(weeks) 和 年(years) 等时间单位。它们都会转换成对应的秒数放入 uint 中。所以 1分钟 就是 60,1小时是 3600(60秒×60分钟),1天是86400(24小时×60分钟×60秒),以此类推。
修饰符可以像函数一样接收参数,是“宿主”函数把参数传递给它的修饰符的。
记住,修饰符的最后一行为 _;,表示修饰符调用结束后返回,并执行调用函数余下的部分。
// 存储用户年龄的映射
mapping (uint => uint) public age;
// 限定用户年龄的修饰符
modifier olderThan(uint _age, uint _userId) {
require(age[_userId] >= _age);
_;
}
// 必须年满16周岁才允许开车 (至少在美国是这样的).
// 我们可以用如下参数调用`olderThan` 修饰符:
function driveCar(uint _userId) public olderThan(16, _userId) {
// 其余的程序逻辑
}