继续翻译Solidity的官方文档, 以此也算是自己的学习
[Solidity官方手册](https://solidity.readthedocs.io/zh/latest/solidity-by-example.html)
下面的合同十分的复杂, 但是的确是展现出了`Solidity`的许多特性. 它实现了一个投票的合约. 当然, 电子投票的主要的问题, 如何给当前的投票人分发票 和 如何保证正常的进行. 在这里我们并不会解决所有的问题, 但是 至少我们将展现如何进行一场自动化进行和完全透明的委托投票
主要的思路是是对每一个票创建一个合约, 对每个选项提供一个短的名称. 合约的创建者 就作为这次投票的主持人(chairperson)将会给与其他独立地址的投票权利
这些账户(可投票)的拥有者可以自己投这一票, 或者把自己的票委托(delegate)给他们信任的人
在这次投票结束的时候, `winningProposal()` (function)将会返回这个票数最多的人
(下面是实例的投票代码, 翻译水平有限..保留部分原文翻译)
pragma solidity ^0.4.11;
/// @title Voting with delegation.
contract Ballot {
// This declares a new complex type which will
// be used for variables later.
// It will represent a single voter.
(声明一个新的class 将会成为一个变量, 会代表其中的一个投票者)
struct Voter {
uint weight; // weight is accumulated(积累) by delegation(委托)
bool voted; // if true, that person already voted
address delegate; // person delegated to (你所委托的人)
uint vote; // index of the voted proposal (投票索引号)
}
// This is a type for a single proposal. (单个提案类型)
struct Proposal {
bytes32 name; // short name (up to 32 bytes)
uint voteCount; // number of accumulated votes(累计票数)
}
address public chairperson;
// This declares a state variable that
// stores a `Voter` struct for each possible address.
(这里创建里一个投票者的变量, 用于保存每个投票者的地址)
mapping(address => Voter) public voters;
// A dynamically-sized array of `Proposal` structs.(一个动态分配的票据结构)
Proposal[] public proposals;
/// Create a new ballot to choose one of `proposalNames`. (创建一个新的票据来选择一个提案名称)
function Ballot(bytes32[] proposalNames) {
chairperson = msg.sender;
voters[chairperson].weight = 1;
// For each of the provided proposal names, (每一个选举人的名字创建单个的选举对象, 并且添加到数组的尾部)
// create a new proposal object and add it
// to the end of the array.
for (uint i = 0; i < proposalNames.length; i++) {
// `Proposal({...})` creates a temporary
// Proposal object and `proposals.push(...)`
// appends it to the end of `proposals`. (意向人对象`proposal`, 使用proposal.push(), 把意向人压入)
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}
// Give `voter` the right to vote on this ballot. (给与投票者投票权益)
// May only be called by `chairperson`. (只可能是被支持人所调用)
function giveRightToVote(address voter) {
// If the argument of `require` evaluates to `false`, (如何请求的值是 false , 这个将会被终结, 并且回滚所有的改变)
// it terminates and reverts all changes to
// the state and to Ether balances. It is often (如果函数被非法调用, 这将会是个很好的办法)
// a good idea to use this if functions are
// called incorrectly. But watch out, this (但是需要注意的是, 这将会消耗当前所有的 gas(在未来可能有所改善))
// will currently also consume all provided gas
// (this is planned to change in the future).
require((msg.sender == chairperson) && !voters[voter].voted && (voters[voter].weight == 0));
voters[voter].weight = 1;
}
/// Delegate your vote to the voter `to`. (委托你的票到其他的可信投票者)
function delegate(address to) {
// assigns reference
Voter storage sender = voters[msg.sender];
require(!sender.voted); (这里保证是没有投过票的)
// Self-delegation is not allowed. (不允许自己投给自己)
require(to != msg.sender);
// Forward the delegation as long as
// `to` also delegated.
// In general, such loops are very dangerous,
// because if they run too long, they might
// need more gas than is available in a block.
// In this case, the delegation will not be executed,
// but in other situations, such loops might
// cause a contract to get "stuck" completely.
(这里避免一个循环委托的可能性 , 如果A委托给B, B委托给其他人,最终到了A )
while (voters[to].delegate != address(0)) {
to = voters[to].delegate;
// We found a loop in the delegation, not allowed.
require(to != msg.sender);
}
// Since `sender` is a reference, this
// modifies `voters[msg.sender].voted`
sender.voted = true;
sender.delegate = to;
Voter storage delegate = voters[to];
if (delegate.voted) {
// If the delegate already voted, (如果委托投票已经投过, 直接修改票数)
// directly add to the number of votes
proposals[delegate.vote].voteCount += sender.weight; (投票权重)
} else {
// If the delegate did not vote yet,
// add to her weight.
delegate.weight += sender.weight;
}
}
/// Give your vote (including votes delegated to you) (投出你的票票)
/// to proposal `proposals[proposal].name`.
function vote(uint proposal) {
Voter storage sender = voters[msg.sender];
require(!sender.voted); (require 是新版的语法)
sender.voted = true;
sender.vote = proposal;
// If `proposal` is out of the range of the array,(如果提案超出了索引范围, 直接回滚所有数据)
// this will throw automatically and revert all
// changes.
proposals[proposal].voteCount += sender.weight;
}
/// @dev Computes the winning proposal taking all (根据记票找到最终 的胜出者)
/// previous votes into account.
function winningProposal() constant
returns (uint winningProposal)
{
uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) {
if (proposals[p].voteCount > winningVoteCount) {
winningVoteCount = proposals[p].voteCount;
winningProposal = p;
}
}
}
// Calls winningProposal() function to get the index
// of the winner contained in the proposals array and then
// returns the name of the winner
function winnerName() constant
returns (bytes32 winnerName)
{
winnerName = proposals[winningProposal()].name;
}
}
现在如果,需要指派票权到其他的账户,参加多个投票,有好的方案吗?
这一节,我们将展示在以太上创建一个完整的盲拍合约是多么简单. 我们从一个所有人都能看到出价的公开拍卖开始,接着扩展合约成为一个在 **拍卖结束以前不能看到实际出价的盲拍**.
通常简单的公开拍卖合约, 是每个人可以在拍卖期间提出他们的竞拍出价。为了实现竞拍人和他们竞拍内容的绑定,竞拍包括发送金额/ether。如果产生了新的最高竞拍价,前一个最高价竞拍人将会拿回他的钱。在竞拍阶段结束后,受益人人需要手动调用合约收取他的钱 (合约不会激活自己. )(合约是存在的函数,需要用户去调用它 , 他是不能调用自己的)
pragma solidity ^0.4.11;
contract SimpleAuction {
// Parameters of the auction. Times are either (拍卖参数)
// absolute unix timestamps (seconds since 1970-01-01) (自unix时间戳的绝对时间)
// or time periods in seconds.
address public beneficiary;
uint public auctionStart;
uint public biddingTime;
// Current state of the auction. (当前的拍卖状态)
address public highestBidder;
uint public highestBid;
// Allowed withdrawals of previous bids (可以撤出之前的投标)
mapping(address => uint) pendingReturns;
// Set to true at the end, disallows any change (已经结束就不允许任何改变)
bool ended;
// Events that will be fired on changes. (当有了改变的时候, 事件将会被触发)
event HighestBidIncreased(address bidder, uint amount); (到了最高标)
event AuctionEnded(address winner, uint amount); (结束)
// The following is a so-called natspec comment,
// recognizable by the three slashes. (三个斜杠(slash) 的注释是一个 natspec 的注释)
// It will be shown when the user is asked to
// confirm a transaction.
/// Create a simple auction with `_biddingTime` (竞拍时间)
/// seconds bidding time on behalf of the
/// beneficiary address `_beneficiary`. (实际竞拍者账户) (_是private的变量(约定习惯))
function SimpleAuction(
uint _biddingTime,
address _beneficiary
) {
beneficiary = _beneficiary;
auctionStart = now;
biddingTime = _biddingTime;
}
/// Bid on the auction with the value sent (对拍卖的竞拍金会随着交易事务一起发送,)
/// together with this transaction.
/// The value will only be refunded if the (只有没有拍得的时候, 金额才会被退回)
/// auction is not won.
function bid(出价)() payable {
// No arguments are necessary, all (不需要参数, 数据是交易的一部分)
// information is already part of
// the transaction. The keyword payable
// is required for the function to
// be able to receive Ether.
// Revert the call if the bidding (回滚这个调用, 如果标已经结束)
// period is over.
require(now <= (auctionStart + biddingTime));
// If the bid is not higher, send the
// money back.
require(msg.value > highestBid); (如果不是最高出价, 那么把保证金返回)
if (highestBidder != 0) {
// Sending back the money by simply using
// highestBidder.send(highestBid) is a security risk
(只是用上述函数把币送回是有个安全隐患)
// because it could execute an untrusted contract. (因为可能执行一个 不可信任的合约)
// It is always safer to let the recipients
// withdraw their money themselves.
pendingReturns[highestBidder] += highestBid;
}
highestBidder = msg.sender;
highestBid = msg.value;
HighestBidIncreased(msg.sender, msg.value);
}
/// Withdraw a bid that was overbid. (出价过高的退款)
function withdraw() returns (bool) {
uint amount = pendingReturns[msg.sender];
if (amount > 0) {
// It is important to set this to zero because the recipient
// can call this function again as part of the receiving call
// before `send` returns.
pendingReturns[msg.sender] = 0;
if (!msg.sender.send(amount)) {
// No need to call throw here, just reset the amount owing
pendingReturns[msg.sender] = amount;
return false;
}
}
return true;
}
/// End the auction and send the highest bid (结束拍卖,最高者得标)
/// to the beneficiary(受惠者).
function auctionEnd() {
// It is a good guideline to structure functions that interact
// with other contracts (i.e. they call functions or send Ether)
// into three phases:
// 1. checking conditions
// 2. performing actions (potentially changing conditions)
// 3. interacting with other contracts
// If these phases are mixed up, the other contract could call
// back into the current contract and modify the state or cause
// effects (ether payout) to be performed multiple times.
// If functions called internally include interaction with external
// contracts, they also have to be considered interaction with
// external contracts.
// 1. Conditions (当前情况)
require(now >= (auctionStart + biddingTime)); // auction did not yet end
require(!ended); // this function has already been called
// 2. Effects (结果)
ended = true;
AuctionEnded(highestBidder, highestBid); (处理合约中的钱)
// 3. Interaction (通知, 交互)
beneficiary.transfer(highestBid); (给标)
}
}
接下来扩展前面的公开拍卖成为一个盲拍。盲拍的特点是拍卖结束以前没有时间压力。在一个透明的计算平台上创建盲拍系统听起来可能有些矛盾,但是加密算法能让你脱离困境。
在拍卖阶段, 竞拍人不需要发送实际的出价,仅仅只需要发送一个它的散列值。因为目前几乎不可能找到两个值(足够长)的散列值相等,竞拍者提交他们的出价散列值。在拍卖结束后,竞拍人重新发送未加密的竞拍出价,合约将检查其散列值是否和拍卖阶段发送的一样。 另一个挑战是如何让拍卖同时实现绑定和致盲 :防止竞拍人竞拍成功后不付钱的唯一的办法是,在竞拍出价的同时发送保证金。但是在Ethereum上发送保证金是无法致盲,所有人都能看到保证金。下面的合约通过接受任何尽量大的出价来解决这个问题。当然这可以在最后的揭拍阶段进行复核,一些竞拍出价可能是无效的,这样做的目的是(它提供一个显式的标志指出是无效的竞拍,同时包含高额保证金):竞拍人可以通过放置几个无效的高价和低价竞拍来混淆竞争对手。
注: 理解上是, 把hash(出价 + 混淆金) 发给合约, 等待竞拍结束. 每个人发送自己的 明文出价(cleartext), 之后由合约验证 , hash(出价+混) 是否等于之前的 hash.
contract BlindAuction
{
struct Bid
{
bytes32 blindedBid;
uint deposit;
}
address public beneficiary;
uint public auctionStart;
uint public biddingEnd;
uint public revealEnd;
bool public ended;
mapping(address => Bid[]) public bids;
address public highestBidder;
uint public highestBid;
event AuctionEnded(address winner, uint highestBid);
///修饰器(Modifier)是一个简便的途径用来验证函数输入的有效性。
///`onlyBefore` 应用于下面的 `bid`函数,其旧的函数体替换修饰器主体中 `_`后就是其新的函数体
modifier onlyBefore(uint _time) { if (now >= _time) throw; _ }
modifier onlyAfter(uint _time) { if (now <= _time) throw; _ }
function BlindAuction(uint _biddingTime,
uint _revealTime,
address _beneficiary)
{
beneficiary = _beneficiary;
auctionStart = now;
biddingEnd = now + _biddingTime;
revealEnd = biddingEnd + _revealTime;
}
///放置一个盲拍出价使用`_blindedBid`=sha3(value,fake,secret).
///仅仅在竞拍结束正常揭拍后退还发送的以太。当随同发送的以太至少
///等于 "value"指定的保证金并且 "fake"不为true的时候才是有效的竞拍
///出价。设置 "fake"为true或发送不合适的金额将会掩没真正的竞拍出
///价,但是仍然需要抵押保证金。同一个地址可以放置多个竞拍。
function bid(bytes32 _blindedBid)
onlyBefore(biddingEnd)
{
bids[msg.sender].push(Bid({
blindedBid: _blindedBid,
deposit: msg.value
}));
}
///揭开你的盲拍竞价。你将会拿回除了最高出价外的所有竞拍保证金
///以及正常的无效盲拍保证金。
function reveal(uint[] _values, bool[] _fake,
bytes32[] _secret)
onlyAfter(biddingEnd)
onlyBefore(revealEnd)
{
uint length = bids[msg.sender].length;
if (_values.length != length || _fake.length != length ||
_secret.length != length)
throw;
uint refund;
for (uint i = 0; i < length; i++)
{
var bid = bids[msg.sender][i];
var (value, fake, secret) =
(_values[i], _fake[i], _secret[i]);
if (bid.blindedBid != sha3(value, fake, secret))
//出价未被正常揭拍,不能取回保证金。
continue;
refund += bid.deposit;
if (!fake && bid.deposit >= value)
if (placeBid(msg.sender, value))
refund -= value;
//保证发送者绝不可能重复取回保证金
bid.blindedBid = 0;
}
msg.sender.send(refund);
}
//这是一个内部 (internal)函数,
//意味着仅仅只有合约(或者从其继承的合约)可以调用
function placeBid(address bidder, uint value) internal
returns (bool success)
{
if (value <= highestBid)
return false;
if (highestBidder != 0)
//退还前一个最高竞拍出价
highestBidder.send(highestBid);
highestBid = value;
highestBidder = bidder;
return true;
}
///竞拍结束后发送最高出价到竞拍人
function auctionEnd()
onlyAfter(revealEnd)
{
if (ended) throw;
AuctionEnded(highestBidder, highestBid);
//发送合约拥有所有的钱,因为有一些保证金退回可能失败了。
beneficiary.send(this.balance);
ended = true;
}
function () { throw; }
}
Safe Remote Purchase 安全的远程购物
contract Purchase
{
uint public value;
address public seller;
address public buyer;
enum State { Created, Locked, Inactive }
State public state;
function Purchase()
{
seller = msg.sender;
value = msg.value / 2;
if (2 * value != msg.value) throw;
}
modifier require(bool _condition)
{
if (!_condition) throw;
_
}
modifier onlyBuyer()
{
if (msg.sender != buyer) throw;
_
}
modifier onlySeller()
{
if (msg.sender != seller) throw;
_
}
modifier inState(State _state)
{
if (state != _state) throw;
_
}
event aborted();
event purchaseConfirmed();
event itemReceived();
///终止购物并收回以太。仅仅可以在合约未锁定时被卖家调用。
function abort()
onlySeller
inState(State.Created)
{
aborted();
seller.send(this.balance);
state = State.Inactive;
}
///买家确认购买。交易包含两倍价值的(`2 * value`)以太。
///这些以太会一直锁定到收货确认(confirmReceived)被调用。
function confirmPurchase()
inState(State.Created)
require(msg.value == 2 * value)
{
purchaseConfirmed();
buyer = msg.sender;
state = State.Locked;
}
///确认你(买家)收到了货物,这将释放锁定的以太。
function confirmReceived()
onlyBuyer
inState(State.Locked)
{
itemReceived();
buyer.send(value);//我们有意忽略了返回值。
seller.send(this.balance);
state = State.Inactive;
}
function() { throw; }
}
先挂起这个吧, 这些东西需要消耗太久