您好,登錄后才能下訂單哦!
本篇內容主要講解“Solidity編程開發實例分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Solidity編程開發實例分析”吧!
接下來的智能合約教程非常復雜,但展示了很多Solidity的編程開發特性。它實現了一個入門的投票合約。當然,電子選舉的主要問題是如何賦予投票權給準確的人,并防止操縱。我們不能解決所有的問題,但至少我們會展示如何委托投票可以同時做到投票統計是自動和完全透明。
思路是為每張選票創建一個合約,每個投票選項提供一個短名稱。合約創建者作為會長將會給每個投票參與人各自的地址投票權。
地址后面的人們可以選擇自己投票或者委托信任的代表人替他們投票。在投票結束后,winningProposal()將會返回獲得票數最多的提案。
/// @title Voting with delegation. /// @title 授權投票 contract Ballot { // 這里聲明了復雜類型 // 將會在被后面的參數使用 // 代表一個獨立的投票人。 struct Voter { uint weight; // 累積的權重。 bool voted; // 如果為真,則表示該投票人已經投票。 address delegate; // 委托的投票代表 uint vote; // 投票選擇的提案索引號 } // 這是一個獨立提案的類型 struct Proposal { bytes32 name; // 短名稱(32字節) uint voteCount; // 累計獲得的票數 } address public chairperson; //這里聲明一個狀態變量,保存每個獨立地址的`Voter` 結構 mapping(address => Voter) public voters; //一個存儲`Proposal`結構的動態數組 Proposal[] public proposals; // 創建一個新的投票用于選出一個提案名`proposalNames`. function Ballot(bytes32[] proposalNames) { chairperson = msg.sender; voters[chairperson].weight = 1; //對提供的每一個提案名稱,創建一個新的提案 //對象添加到數組末尾 for (uint i = 0; i < proposalNames.length; i++) //`Proposal({...})` 創建了一個臨時的提案對象, //`proposal.push(...)`添加到了提案數組`proposals`末尾。 proposals.push(Proposal({ name: proposalNames[i], voteCount: 0 })); } //給投票人`voter`參加投票的投票權, //只能由投票主持人`chairperson`調用。 function giveRightToVote(address voter) { if (msg.sender != chairperson || voters[voter].voted) //`throw`會終止和撤銷所有的狀態和以太改變。 //如果函數調用無效,這通常是一個好的選擇。 //但是需要注意,這會消耗提供的所有gas。 throw; voters[voter].weight = 1; } // 委托你的投票權到一個投票代表 `to`。 function delegate(address to) { // 指定引用 Voter sender = voters[msg.sender]; if (sender.voted) throw; //當投票代表`to`也委托給別人時,尋找到最終的投票代表 while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender) to = voters[to].delegate; // 當最終投票代表等于調用者,是不被允許的。 if (to == msg.sender) throw; //因為`sender`是一個引用, //這里實際修改了`voters[msg.sender].voted` sender.voted = true; sender.delegate = to; Voter delegate = voters[to]; if (delegate.voted) //如果委托的投票代表已經投票了,直接修改票數 proposals[delegate.vote].voteCount += sender.weight; else //如果投票代表還沒有投票,則修改其投票權重。 delegate.weight += sender.weight; } ///投出你的選票(包括委托給你的選票) ///給 `proposals[proposal].name`。 function vote(uint proposal) { Voter sender = voters[msg.sender]; if (sender.voted) throw; sender.voted = true; sender.vote = proposal; //如果`proposal`索引超出了給定的提案數組范圍 //將會自動拋出異常,并撤銷所有的改變。 proposals[proposal].voteCount += sender.weight; } ///@dev 根據當前所有的投票計算出當前的勝出提案 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; } } } }
現在,指派投票權到所有的投票參加者需要許多的交易。你能想出更好的方法么?
這一節,我們將展示在以太上創建一個完整的盲拍合約是多么簡單。我們從一個所有人都能看到出價的公開拍賣開始,接著擴展合約成為一個在拍賣結束以前不能看到實際出價的盲拍。
通常簡單的公開拍賣合約,是每個人可以在拍賣期間發送他們的競拍出價。為了實現綁定競拍人的到他們的拍賣,競拍包括發送金額/ether。如果產生了新的最高競拍價,前一個最高價競拍人將會拿回他的錢。在競拍階段結束后,受益人人需要手動調用合約收取他的錢 — — 合約不會激活自己。
contract SimpleAuction { // 拍賣的參數。 // 時間要么為unix絕對時間戳(自1970-01-01以來的秒數), // 或者是以秒為單位的出塊時間 address public beneficiary; uint public auctionStart; uint public biddingTime; //當前的拍賣狀態 address public highestBidder; uint public highestBid; //在結束時設置為true來拒絕任何改變 bool ended; //當改變時將會觸發的Event event HighestBidIncreased(address bidder, uint amount); event AuctionEnded(address winner, uint amount); //下面是一個叫做natspec的特殊注釋, //由3個連續的斜杠標記,當詢問用戶確認交易事務時將顯示。 ///創建一個簡單的合約使用`_biddingTime`表示的競拍時間, /// 地址`_beneficiary`.代表實際的拍賣者 function SimpleAuction(uint _biddingTime, address _beneficiary) { beneficiary = _beneficiary; auctionStart = now; biddingTime = _biddingTime; } ///對拍賣的競拍保證金會隨著交易事務一起發送, ///只有在競拍失敗的時候才會退回 function bid() { //不需要任何參數,所有的信息已經是交易事務的一部分 if (now > auctionStart + biddingTime) //當競拍結束時撤銷此調用 throw; if (msg.value <= highestBid) //如果出價不是最高的,發回競拍保證金。 throw; if (highestBidder != 0) highestBidder.send(highestBid); highestBidder = msg.sender; highestBid = msg.value; HighestBidIncreased(msg.sender, msg.value); } ///拍賣結束后發送最高的競價到拍賣人 function auctionEnd() { if (now <= auctionStart + biddingTime) throw; //拍賣還沒有結束 if (ended) throw; //這個收款函數已經被調用了 AuctionEnded(highestBidder, highestBid); //發送合約擁有所有的錢,因為有一些保證金可能退回失敗了。 beneficiary.send(this.balance); ended = true; } function () { //這個函數將會在發送到合約的交易事務包含無效數據 //或無數據的時執行,這里撤銷所有的發送, //所以沒有人會在使用合約時因為意外而丟錢。 throw; } }
接下來擴展前面的公開拍賣成為一個盲拍。盲拍的特點是拍賣結束以前沒有時間壓力。在一個透明的計算平臺上創建盲拍系統聽起來可能有些矛盾,但是加密算法能讓你脫離困境。
在拍賣階段, 競拍人不需要發送實際的出價,僅僅只需要發送一個它的散列值。因為目前幾乎不可能找到兩個值(足夠長)的散列值相等,競拍者提交他們的出價散列值。在拍賣結束后,競拍人重新發送未加密的競拍出價,合約將檢查其散列值是否和拍賣階段發送的一樣。 另一個挑戰是如何讓拍賣同時實現綁定和致盲 :防止競拍人競拍成功后不付錢的唯一的辦法是,在競拍出價的同時發送保證金。但是在Ethereum上發送保證金是無法致盲,所有人都能看到保證金。下面的合約通過接受任何盡量大的出價來解決這個問題。當然這可以在最后的揭拍階段進行復核,一些競拍出價可能是無效的,這樣做的目的是(它提供一個顯式的標志指出是無效的競拍,同時包含高額保證金):競拍人可以通過放置幾個無效的高價和低價競拍來混淆競爭對手。
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; } }
到此,相信大家對“Solidity編程開發實例分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。