本篇內(nèi)容主要講解“Solidity編程開(kāi)發(fā)實(shí)例分析”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Solidity編程開(kāi)發(fā)實(shí)例分析”吧!
創(chuàng)新互聯(lián)建站專(zhuān)業(yè)提供成都主機(jī)托管四川主機(jī)托管成都服務(wù)器托管四川服務(wù)器托管,支持按月付款!我們的承諾:貴族品質(zhì)、平民價(jià)格,機(jī)房位于中國(guó)電信/網(wǎng)通/移動(dòng)機(jī)房,成都移動(dòng)機(jī)房托管服務(wù)有保障!
接下來(lái)的智能合約教程非常復(fù)雜,但展示了很多Solidity的編程開(kāi)發(fā)特性。它實(shí)現(xiàn)了一個(gè)入門(mén)的投票合約。當(dāng)然,電子選舉的主要問(wèn)題是如何賦予投票權(quán)給準(zhǔn)確的人,并防止操縱。我們不能解決所有的問(wèn)題,但至少我們會(huì)展示如何委托投票可以同時(shí)做到投票統(tǒng)計(jì)是自動(dòng)和完全透明。
思路是為每張選票創(chuàng)建一個(gè)合約,每個(gè)投票選項(xiàng)提供一個(gè)短名稱。合約創(chuàng)建者作為會(huì)長(zhǎng)將會(huì)給每個(gè)投票參與人各自的地址投票權(quán)。
地址后面的人們可以選擇自己投票或者委托信任的代表人替他們投票。在投票結(jié)束后,winningProposal()將會(huì)返回獲得票數(shù)最多的提案。
/// @title Voting with delegation. /// @title 授權(quán)投票 contract Ballot { // 這里聲明了復(fù)雜類(lèi)型 // 將會(huì)在被后面的參數(shù)使用 // 代表一個(gè)獨(dú)立的投票人。 struct Voter { uint weight; // 累積的權(quán)重。 bool voted; // 如果為真,則表示該投票人已經(jīng)投票。 address delegate; // 委托的投票代表 uint vote; // 投票選擇的提案索引號(hào) } // 這是一個(gè)獨(dú)立提案的類(lèi)型 struct Proposal { bytes32 name; // 短名稱(32字節(jié)) uint voteCount; // 累計(jì)獲得的票數(shù) } address public chairperson; //這里聲明一個(gè)狀態(tài)變量,保存每個(gè)獨(dú)立地址的`Voter` 結(jié)構(gòu) mapping(address => Voter) public voters; //一個(gè)存儲(chǔ)`Proposal`結(jié)構(gòu)的動(dòng)態(tài)數(shù)組 Proposal[] public proposals; // 創(chuàng)建一個(gè)新的投票用于選出一個(gè)提案名`proposalNames`. function Ballot(bytes32[] proposalNames) { chairperson = msg.sender; voters[chairperson].weight = 1; //對(duì)提供的每一個(gè)提案名稱,創(chuàng)建一個(gè)新的提案 //對(duì)象添加到數(shù)組末尾 for (uint i = 0; i < proposalNames.length; i++) //`Proposal({...})` 創(chuàng)建了一個(gè)臨時(shí)的提案對(duì)象, //`proposal.push(...)`添加到了提案數(shù)組`proposals`末尾。 proposals.push(Proposal({ name: proposalNames[i], voteCount: 0 })); } //給投票人`voter`參加投票的投票權(quán), //只能由投票主持人`chairperson`調(diào)用。 function giveRightToVote(address voter) { if (msg.sender != chairperson || voters[voter].voted) //`throw`會(huì)終止和撤銷(xiāo)所有的狀態(tài)和以太改變。 //如果函數(shù)調(diào)用無(wú)效,這通常是一個(gè)好的選擇。 //但是需要注意,這會(huì)消耗提供的所有g(shù)as。 throw; voters[voter].weight = 1; } // 委托你的投票權(quán)到一個(gè)投票代表 `to`。 function delegate(address to) { // 指定引用 Voter sender = voters[msg.sender]; if (sender.voted) throw; //當(dāng)投票代表`to`也委托給別人時(shí),尋找到最終的投票代表 while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender) to = voters[to].delegate; // 當(dāng)最終投票代表等于調(diào)用者,是不被允許的。 if (to == msg.sender) throw; //因?yàn)閌sender`是一個(gè)引用, //這里實(shí)際修改了`voters[msg.sender].voted` sender.voted = true; sender.delegate = to; Voter delegate = voters[to]; if (delegate.voted) //如果委托的投票代表已經(jīng)投票了,直接修改票數(shù) proposals[delegate.vote].voteCount += sender.weight; else //如果投票代表還沒(méi)有投票,則修改其投票權(quán)重。 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`索引超出了給定的提案數(shù)組范圍 //將會(huì)自動(dòng)拋出異常,并撤銷(xiāo)所有的改變。 proposals[proposal].voteCount += sender.weight; } ///@dev 根據(jù)當(dāng)前所有的投票計(jì)算出當(dāng)前的勝出提案 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; } } } }
現(xiàn)在,指派投票權(quán)到所有的投票參加者需要許多的交易。你能想出更好的方法么?
這一節(jié),我們將展示在以太上創(chuàng)建一個(gè)完整的盲拍合約是多么簡(jiǎn)單。我們從一個(gè)所有人都能看到出價(jià)的公開(kāi)拍賣(mài)開(kāi)始,接著擴(kuò)展合約成為一個(gè)在拍賣(mài)結(jié)束以前不能看到實(shí)際出價(jià)的盲拍。
通常簡(jiǎn)單的公開(kāi)拍賣(mài)合約,是每個(gè)人可以在拍賣(mài)期間發(fā)送他們的競(jìng)拍出價(jià)。為了實(shí)現(xiàn)綁定競(jìng)拍人的到他們的拍賣(mài),競(jìng)拍包括發(fā)送金額/ether。如果產(chǎn)生了新的最高競(jìng)拍價(jià),前一個(gè)最高價(jià)競(jìng)拍人將會(huì)拿回他的錢(qián)。在競(jìng)拍階段結(jié)束后,受益人人需要手動(dòng)調(diào)用合約收取他的錢(qián) — — 合約不會(huì)激活自己。
contract SimpleAuction { // 拍賣(mài)的參數(shù)。 // 時(shí)間要么為unix絕對(duì)時(shí)間戳(自1970-01-01以來(lái)的秒數(shù)), // 或者是以秒為單位的出塊時(shí)間 address public beneficiary; uint public auctionStart; uint public biddingTime; //當(dāng)前的拍賣(mài)狀態(tài) address public highestBidder; uint public highestBid; //在結(jié)束時(shí)設(shè)置為true來(lái)拒絕任何改變 bool ended; //當(dāng)改變時(shí)將會(huì)觸發(fā)的Event event HighestBidIncreased(address bidder, uint amount); event AuctionEnded(address winner, uint amount); //下面是一個(gè)叫做natspec的特殊注釋?zhuān)? //由3個(gè)連續(xù)的斜杠標(biāo)記,當(dāng)詢問(wèn)用戶確認(rèn)交易事務(wù)時(shí)將顯示。 ///創(chuàng)建一個(gè)簡(jiǎn)單的合約使用`_biddingTime`表示的競(jìng)拍時(shí)間, /// 地址`_beneficiary`.代表實(shí)際的拍賣(mài)者 function SimpleAuction(uint _biddingTime, address _beneficiary) { beneficiary = _beneficiary; auctionStart = now; biddingTime = _biddingTime; } ///對(duì)拍賣(mài)的競(jìng)拍保證金會(huì)隨著交易事務(wù)一起發(fā)送, ///只有在競(jìng)拍失敗的時(shí)候才會(huì)退回 function bid() { //不需要任何參數(shù),所有的信息已經(jīng)是交易事務(wù)的一部分 if (now > auctionStart + biddingTime) //當(dāng)競(jìng)拍結(jié)束時(shí)撤銷(xiāo)此調(diào)用 throw; if (msg.value <= highestBid) //如果出價(jià)不是最高的,發(fā)回競(jìng)拍保證金。 throw; if (highestBidder != 0) highestBidder.send(highestBid); highestBidder = msg.sender; highestBid = msg.value; HighestBidIncreased(msg.sender, msg.value); } ///拍賣(mài)結(jié)束后發(fā)送最高的競(jìng)價(jià)到拍賣(mài)人 function auctionEnd() { if (now <= auctionStart + biddingTime) throw; //拍賣(mài)還沒(méi)有結(jié)束 if (ended) throw; //這個(gè)收款函數(shù)已經(jīng)被調(diào)用了 AuctionEnded(highestBidder, highestBid); //發(fā)送合約擁有所有的錢(qián),因?yàn)橛幸恍┍WC金可能退回失敗了。 beneficiary.send(this.balance); ended = true; } function () { //這個(gè)函數(shù)將會(huì)在發(fā)送到合約的交易事務(wù)包含無(wú)效數(shù)據(jù) //或無(wú)數(shù)據(jù)的時(shí)執(zhí)行,這里撤銷(xiāo)所有的發(fā)送, //所以沒(méi)有人會(huì)在使用合約時(shí)因?yàn)橐馔舛鴣G錢(qián)。 throw; } }
接下來(lái)擴(kuò)展前面的公開(kāi)拍賣(mài)成為一個(gè)盲拍。盲拍的特點(diǎn)是拍賣(mài)結(jié)束以前沒(méi)有時(shí)間壓力。在一個(gè)透明的計(jì)算平臺(tái)上創(chuàng)建盲拍系統(tǒng)聽(tīng)起來(lái)可能有些矛盾,但是加密算法能讓你脫離困境。
在拍賣(mài)階段, 競(jìng)拍人不需要發(fā)送實(shí)際的出價(jià),僅僅只需要發(fā)送一個(gè)它的散列值。因?yàn)槟壳皫缀醪豢赡苷业絻蓚€(gè)值(足夠長(zhǎng))的散列值相等,競(jìng)拍者提交他們的出價(jià)散列值。在拍賣(mài)結(jié)束后,競(jìng)拍人重新發(fā)送未加密的競(jìng)拍出價(jià),合約將檢查其散列值是否和拍賣(mài)階段發(fā)送的一樣。 另一個(gè)挑戰(zhàn)是如何讓拍賣(mài)同時(shí)實(shí)現(xiàn)綁定和致盲 :防止競(jìng)拍人競(jìng)拍成功后不付錢(qián)的唯一的辦法是,在競(jìng)拍出價(jià)的同時(shí)發(fā)送保證金。但是在Ethereum上發(fā)送保證金是無(wú)法致盲,所有人都能看到保證金。下面的合約通過(guò)接受任何盡量大的出價(jià)來(lái)解決這個(gè)問(wèn)題。當(dāng)然這可以在最后的揭拍階段進(jìn)行復(fù)核,一些競(jìng)拍出價(jià)可能是無(wú)效的,這樣做的目的是(它提供一個(gè)顯式的標(biāo)志指出是無(wú)效的競(jìng)拍,同時(shí)包含高額保證金):競(jìng)拍人可以通過(guò)放置幾個(gè)無(wú)效的高價(jià)和低價(jià)競(jìng)拍來(lái)混淆競(jìng)爭(zhēng)對(duì)手。
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)是一個(gè)簡(jiǎn)便的途徑用來(lái)驗(yàn)證函數(shù)輸入的有效性。 ///`onlyBefore` 應(yīng)用于下面的 `bid`函數(shù),其舊的函數(shù)體替換修飾器主體中 `_`后就是其新的函數(shù)體 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; } ///放置一個(gè)盲拍出價(jià)使用`_blindedBid`=sha3(value,fake,secret). ///僅僅在競(jìng)拍結(jié)束正常揭拍后退還發(fā)送的以太。當(dāng)隨同發(fā)送的以太至少 ///等于 "value"指定的保證金并且 "fake"不為true的時(shí)候才是有效的競(jìng)拍 ///出價(jià)。設(shè)置 "fake"為true或發(fā)送不合適的金額將會(huì)掩沒(méi)真正的競(jìng)拍出 ///價(jià),但是仍然需要抵押保證金。同一個(gè)地址可以放置多個(gè)競(jìng)拍。 function bid(bytes32 _blindedBid) onlyBefore(biddingEnd) { bids[msg.sender].push(Bid({ blindedBid: _blindedBid, deposit: msg.value })); } ///揭開(kāi)你的盲拍競(jìng)價(jià)。你將會(huì)拿回除了最高出價(jià)外的所有競(jìng)拍保證金 ///以及正常的無(wú)效盲拍保證金。 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)) //出價(jià)未被正常揭拍,不能取回保證金。 continue; refund += bid.deposit; if (!fake && bid.deposit >= value) if (placeBid(msg.sender, value)) refund -= value; //保證發(fā)送者絕不可能重復(fù)取回保證金 bid.blindedBid = 0; } msg.sender.send(refund); } //這是一個(gè)內(nèi)部 (internal)函數(shù), //意味著僅僅只有合約(或者從其繼承的合約)可以調(diào)用 function placeBid(address bidder, uint value) internal returns (bool success) { if (value <= highestBid) return false; if (highestBidder != 0) //退還前一個(gè)最高競(jìng)拍出價(jià) highestBidder.send(highestBid); highestBid = value; highestBidder = bidder; return true; } ///競(jìng)拍結(jié)束后發(fā)送最高出價(jià)到競(jìng)拍人 function auctionEnd() onlyAfter(revealEnd) { if (ended) throw; AuctionEnded(highestBidder, highestBid); //發(fā)送合約擁有所有的錢(qián),因?yàn)橛幸恍┍WC金退回可能失敗了。 beneficiary.send(this.balance); ended = true; } function () { throw; } } Safe Remote Purchase 安全的遠(yuǎn)程購(gòu)物 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(); ///終止購(gòu)物并收回以太。僅僅可以在合約未鎖定時(shí)被賣(mài)家調(diào)用。 function abort() onlySeller inState(State.Created) { aborted(); seller.send(this.balance); state = State.Inactive; } ///買(mǎi)家確認(rèn)購(gòu)買(mǎi)。交易包含兩倍價(jià)值的(`2 * value`)以太。 ///這些以太會(huì)一直鎖定到收貨確認(rèn)(confirmReceived)被調(diào)用。 function confirmPurchase() inState(State.Created) require(msg.value == 2 * value) { purchaseConfirmed(); buyer = msg.sender; state = State.Locked; } ///確認(rèn)你(買(mǎi)家)收到了貨物,這將釋放鎖定的以太。 function confirmReceived() onlyBuyer inState(State.Locked) { itemReceived(); buyer.send(value);//我們有意忽略了返回值。 seller.send(this.balance); state = State.Inactive; } function() { throw; } }
到此,相信大家對(duì)“Solidity編程開(kāi)發(fā)實(shí)例分析”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
當(dāng)前名稱:Solidity編程開(kāi)發(fā)實(shí)例分析
URL分享:http://chinadenli.net/article46/gspjeg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航、App開(kāi)發(fā)、網(wǎng)站導(dǎo)航、網(wǎng)站維護(hù)、網(wǎng)站排名、微信公眾號(hào)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)