Solidity - 編程實例
1. 投票
接下來的合約非常複雜,但展示了很多Solidity的特性。它實現了一個投票合約。當然,電子選舉的主要問題是如何賦予投票權給準確的人,並防止操縱。我們不能解決所有的問題,但至少我們會展示如何委託投票可以同時做到投票統計是自動和完全透明。
思路是爲每張選票創建一個合約,每個投票選項提供一個短名稱。合約創建者作爲會長將會給每個投票參與人各自的地址投票權。
地址後面的人們可以選擇自己投票或者委託信任的代表人替他們投票。在投票結束後,winningProposal()將會返回獲得票數最多的提案。
pragma solidity ^0.4.11;
contract Ballot {
struct Voter {
uint weight;
bool voted;
address delegate;
uint vote;
}
struct Proposal {
bytes32 name;
uint voteCount;
}
address public chairperson;
mapping(address => Voter) public voters;
Proposal[] public proposals;
function Ballot(bytes32[] proposalNames) {
chairperson = msg.sender;
voters[chairperson].weight = 1;
for (uint i = 0; i < proposalNames.length; i++) {
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}
function giveRightToVote(address voter) {
require((msg.sender == chairperson) && !voters[voter].voted && (voters[voter].weight == 0));
voters[voter].weight = 1;
}
function delegate(address to) {
Voter storage sender = voters[msg.sender];
require(!sender.voted);
require(to != msg.sender);
while (voters[to].delegate != address(0)) {
to = voters[to].delegate;
require(to != msg.sender);
}
sender.voted = true;
sender.delegate = to;
Voter storage delegate = voters[to];
if (delegate.voted) {
proposals[delegate.vote].voteCount += sender.weight;
} else {
delegate.weight += sender.weight;
}
}
function vote(uint proposal) {
Voter storage sender = voters[msg.sender];
require(!sender.voted);
sender.voted = true;
sender.vote = proposal;
proposals[proposal].voteCount += sender.weight;
}
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;
}
}
}
function winnerName() constant
returns (bytes32 winnerName)
{
winnerName = proposals[winningProposal()].name;
}
}
2. 簡單的公開拍賣
通常簡單的公開拍賣合約,是每個人可以在拍賣期間發送他們的競拍出價。爲了實現綁定競拍人的到他們的拍賣,競拍包括髮送金額ether。如果產生了新的最高競拍價,前一個最高價競拍人將會拿回他的錢。在競拍階段結束後,受益人人需要手動調用合約收取他的錢 — — 合約不會激活自己。
pragma solidity ^0.4.11;
contract SimpleAuction {
address public beneficiary;
uint public auctionStart;
uint public biddingTime;
address public highestBidder;
uint public highestBid;
mapping(address => uint) pendingReturns;
bool ended;
event HighestBidIncreased(address bidder, uint amount);
event AuctionEnded(address winner, uint amount);
function SimpleAuction(uint _biddingTime, address _beneficiary) {
beneficiary = _beneficiary;
auctionStart = now;
biddingTime = _biddingTime;
}
function bid() payable {
require(now <= (auctionStart + biddingTime));
require(msg.value > highestBid);
if (highestBidder != 0) {
pendingReturns[highestBidder] += highestBid;
}
highestBidder = msg.sender;
highestBid = msg.value;
HighestBidIncreased(msg.sender, msg.value);
}
function withdraw() returns (bool) {
uint amount = pendingReturns[msg.sender];
if (amount > 0) {
pendingReturns[msg.sender] = 0;
if (!msg.sender.send(amount)) {
pendingReturns[msg.sender] = amount;
return false;
}
}
return true;
}
function auctionEnd() {
require(now >= (auctionStart + biddingTime));
require(!ended);
ended = true;
AuctionEnded(highestBidder, highestBid);
beneficiary.transfer(highestBid);
}
}
3.盲拍
接下來擴展前面的公開拍賣成爲一個盲拍。盲拍的特點是拍賣結束以前沒有時間壓力。在一個透明的計算平臺上創建盲拍系統聽起來可能有些矛盾,但是加密算法能讓你脫離困境。
在拍賣階段, 競拍人不需要發送實際的出價,僅僅只需要發送一個它的散列值。因爲目前幾乎不可能找到兩個值(足夠長)的散列值相等,競拍者提交他們的出價散列值。在拍賣結束後,競拍人重新發送未加密的競拍出價,合約將檢查其散列值是否和拍賣階段發送的一樣。 另一個挑戰是如何讓拍賣同時實現綁定和致盲 :防止競拍人競拍成功後不付錢的唯一的辦法是,在競拍出價的同時發送保證金。但是在Ethereum上發送保證金是無法致盲,所有人都能看到保證金。下面的合約通過接受任何儘量大的出價來解決這個問題。當然這可以在最後的揭拍階段進行復核,一些競拍出價可能是無效的,這樣做的目的是(它提供一個顯式的標誌指出是無效的競拍,同時包含高額保證金):競拍人可以通過放置幾個無效的高價和低價競拍來混淆競爭對手。
pragma solidity ^0.4.11;
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;
mapping(address => uint) pendingReturns;
event AuctionEnded(address winner, uint highestBid);
modifier onlyBefore(uint _time) { require(now < _time); _; }
modifier onlyAfter(uint _time) { require(now > _time); _; }
function BlindAuction(uint _biddingTime, uint _revealTime, address _beneficiary) {
beneficiary = _beneficiary;
auctionStart = now;
biddingEnd = now + _biddingTime;
revealEnd = biddingEnd + _revealTime;
}
function bid(bytes32 _blindedBid) payable 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;
require(_values.length == length);
require(_fake.length == length);
require(_secret.length == length);
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 != keccak256(value, fake, secret)) {
continue;
}
refund += bid.deposit;
if (!fake && bid.deposit >= value) {
if (placeBid(msg.sender, value))
refund -= value;
}
bid.blindedBid = bytes32(0);
}
msg.sender.transfer(refund);
}
function placeBid(address bidder, uint value) internal
returns (bool success)
{
if (value <= highestBid) {
return false;
}
if (highestBidder != 0) {
pendingReturns[highestBidder] += highestBid;
}
highestBid = value;
highestBidder = bidder;
return true;
}
function withdraw() {
uint amount = pendingReturns[msg.sender];
if (amount > 0) {
pendingReturns[msg.sender] = 0;
msg.sender.transfer(amount);
}
}
function auctionEnd() onlyAfter(revealEnd)
{
require(!ended);
AuctionEnded(highestBidder, highestBid);
ended = true;
beneficiary.transfer(this.balance);
}
}
轉載自:here
參考原文:here