Solidity(4)
第一章 可支付(payable修饰符)
函数修饰符:
- 决定函数何时和被谁调用的可见性修饰符:
private
意味着它只能被合约内部调用;internal
就像 private 但是也能被继承的合约调用;external
只能从合约外部调用;public
可以在任何地方调用,不管是内部还是外部。
- 有状态修饰符, 告诉我们函数如何和区块链交互:
view
告诉我们运行这个函数不会更改和保存任何数据;pure
告诉我们这个函数不但不会往区块链写数据,它甚至不从区块链读取数据。- 这两种在被从合约外部调用的时候都不花费任何gas(但是它们在被内部其他函数调用的时候将会耗费gas)。
- 自定义的
modifiers
,对于这些修饰符我们可以自定义其对函数的约束逻辑。
payable修饰符:
在以太坊中, 因为钱 (以太), 数据 (事务负载), 以及合约代码本身都存在于以太坊。你可以在同时调用函数 并付钱给另外一个合约。
例子:
contract OnlineStore {
function buySomething() external payable {
// 检查以确定0.001以太发送出去来运行函数:
require(msg.value == 0.001 ether);
// 如果为真,一些用来向函数调用者发送数字内容的逻辑
transferThing(msg.sender);
}
}
msg.value
是一种可以查看向合约发送了多少以太的方法,另外 ether
是一个內建单元。
这里发生的事是,一些人会从 web3.js 调用这个函数 (从DApp的前端), 像这样 :
// 假设 `OnlineStore` 在以太坊上指向你的合约:
OnlineStore.buySomething().send(from: web3.eth.defaultAccount, value: web3.utils.toWei(0.001))
注意这个 value 字段, JavaScript 调用来指定发送多少(0.001)以太。如果把事务想象成一个信封,你发送到函数的参数就是信的内容。 添加一个 value 很像在信封里面放钱 —— 信件内容和钱同时发送给了接收者。
第二章 提现
在你发送以太之后,它将被存储进以合约的以太坊账户中, 并冻结在哪里 —— 除非你添加一个函数来从合约中把以太提现。
contract GetPaid is Ownable {
function withdraw() external onlyOwner {
owner.transfer(this.balance);
}
}
注意我们使用 Ownable 合约中的 owner 和 onlyOwner,假定它已经被引入了。
你可以通过 transfer 函数向一个地址发送以太, 然后 this.balance 将返回当前合约存储了多少以太。 所以如果100个用户每人向我们支付1以太, this.balance
将是100以太。
你可以通过 transfer 向任何以太坊地址付钱。 比如,你可以有一个函数在 msg.sender
超额付款的时候给他们退钱:
uint itemFee = 0.001 ether;
msg.sender.transfer(msg.value - itemFee);
或者在一个有卖家和卖家的合约中, 你可以把卖家的地址存储起来, 当有人买了它的东西的时候,把买家支付的钱发送给它 seller.transfer(msg.value)
。
第四章 随机数
- 用keccak256来制造随机数
// 生成一个0到100的随机数:
uint randNonce = 0;
uint random = uint(keccak256(now, msg.sender, randNonce)) % 100;
randNonce++;
uint random2 = uint(keccak256(now, msg.sender, randNonce)) % 100;
// 利用 keccak 把输入的值转变为一个哈希值, 再将哈希值转换为 uint, 然后利用 % 100 来取最后两位, 就生成了一个0到100之间随机数了
这个方法首先拿到 now
的时间戳、 msg.sender
、 以及一个自增数 nonce
(一个仅会被使用一次的数,这样我们就不会对相同的输入值调用一次以上哈希函数了)。