Home | 簡體中文 | 繁體中文 | 雜文 | 知乎專欄 | Github | OSChina 博客 | 雲社區 | 雲棲社區 | Facebook | Linkedin | 視頻教程 | 打賞(Donations) | About
知乎專欄多維度架構 | 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者”

14.15. solidity example

14.15.1. Voting

			
pragma solidity ^0.4.25;
//author: netkiller <netkiller@msn.com>
//homepage: http://www.netkiller.cn
contract Voting {

  mapping (bytes32 => uint8) public votesReceived;

  // 存儲候選人名字的數組
  bytes32[] public candidateList;


  // 建構子 初始化候選人名單
  function Voting(bytes32[] candidateNames) public {

    candidateList = candidateNames;
  }

  // 查詢某個候選人的總票數
  function totalVotesFor(bytes32 candidate) public constant returns (uint8) {
    require(validCandidate(candidate) == true);
    // 或者
    // assert(validCandidate(candidate) == true);
    return votesReceived[candidate];
  }

  // 為某個候選人投票
  function voteForCandidate(bytes32 candidate) public{
    assert(validCandidate(candidate) == true);
    votesReceived[candidate] += 1;
  }

  // 檢索投票的姓名是不是候選人的名字
  function validCandidate(bytes32 candidate) public constant returns (bool) {
    for(uint i = 0; i < candidateList.length; i++) {
      if (candidateList[i] == candidate) {
        return true;
      }
    }
    return false;
  }

}
			
			

14.15.2. MetaCoin

			
pragma solidity ^0.4.25;
contract MetaCoin {
	mapping (address => uint) balances;
	event Transfer(address indexed _from, address indexed _to, uint256 _value);
	function MetaCoin() public {
		balances[tx.origin] = 10000;
	}
	function sendCoin(address receiver, uint amount) public returns(bool sufficient) {
		if (balances[msg.sender] < amount) return false;
		balances[msg.sender] -= amount;
		balances[receiver] += amount;
		Transfer(msg.sender, receiver, amount);
		return true;
	}
	function getBalance(address addr) public view returns(uint) {
		return balances[addr];
	}
}
			
			

14.15.3. Anonymous voting on Ethereum without a tally authority. Protocol from this paper

https://github.com/stonecoldpat/anonymousvoting

14.15.4. Ballot

			
pragma solidity ^0.4.0;
contract Ballot {

    struct Voter {
        uint weight;
        bool voted;
        uint8 vote;
        address delegate;
    }
    struct Proposal {
        uint voteCount;
    }

    address chairperson;
    mapping(address => Voter) voters;
    Proposal[] proposals;

    /// Create a new ballot with $(_numProposals) different proposals.
    function Ballot(uint8 _numProposals) public {
        chairperson = msg.sender;
        voters[chairperson].weight = 1;
        proposals.length = _numProposals;
    }

    /// Give $(toVoter) the right to vote on this ballot.
    /// May only be called by $(chairperson).
    function giveRightToVote(address toVoter) public {
        if (msg.sender != chairperson || voters[toVoter].voted) return;
        voters[toVoter].weight = 1;
    }

    /// Delegate your vote to the voter $(to).
    function delegate(address to) public {
        Voter storage sender = voters[msg.sender]; // assigns reference
        if (sender.voted) return;
        while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender)
            to = voters[to].delegate;
        if (to == msg.sender) return;
        sender.voted = true;
        sender.delegate = to;
        Voter storage delegateTo = voters[to];
        if (delegateTo.voted)
            proposals[delegateTo.vote].voteCount += sender.weight;
        else
            delegateTo.weight += sender.weight;
    }

    /// Give a single vote to proposal $(toProposal).
    function vote(uint8 toProposal) public {
        Voter storage sender = voters[msg.sender];
        if (sender.voted || toProposal >= proposals.length) return;
        sender.voted = true;
        sender.vote = toProposal;
        proposals[toProposal].voteCount += sender.weight;
    }

    function winningProposal() public constant returns (uint8 _winningProposal) {
        uint256 winningVoteCount = 0;
        for (uint8 prop = 0; prop < proposals.length; prop++)
            if (proposals[prop].voteCount > winningVoteCount) {
                winningVoteCount = proposals[prop].voteCount;
                _winningProposal = prop;
            }
    }
}			
			
			

14.15.5. Conference

			
pragma solidity ^0.4.25;

contract Conference {
  address public organizer;
  mapping (address => uint) public registrantsPaid;
  uint public numRegistrants;
  uint public quota;

  event Deposit(address _from, uint _amount);  // so you can log these events
  event Refund(address _to, uint _amount); 

  function Conference() public{ // Constructor
    organizer = msg.sender;
    quota = 500;
    numRegistrants = 0;
  }
  function buyTicket() public payable returns (bool success) {
    if (numRegistrants >= quota) { return false; }
    registrantsPaid[msg.sender] = msg.value;
    numRegistrants++;
    Deposit(msg.sender, msg.value);
    return true;
  }
  function changeQuota(uint newquota) public {
    if (msg.sender != organizer) { return; }
    quota = newquota;
  }
  function refundTicket(address recipient, uint amount) public {
    if (msg.sender != organizer) { return; }
    if (registrantsPaid[recipient] == amount) { 
      address myAddress = this;
      if (myAddress.balance >= amount) { 
        recipient.transfer(amount);
        registrantsPaid[recipient] = 0;
        numRegistrants--;
        Refund(recipient, amount);
      }
    }
  }
  function destroy() public{ // so funds not locked in contract forever
    if (msg.sender == organizer) { 
      selfdestruct(organizer); // send funds to organizer
    }
  }
}
			
			

控制台調試

			
var contract;
Conference.deployed().then(function(instance){contract=instance;});
contract.buyTicket();
			
			

測試程序

			
neo@MacBook-Pro ~/ethereum/Conference % cat test/conference.js 
var Conference = artifacts.require("./Conference.sol");

contract('Conference', function(accounts) {
	console.log(accounts);
	var owner_account = accounts[0];
    var sender_account = accounts[1];

  it("Initial conference settings should match", function(done) {
  	
  	Conference.deployed({from: owner_account}).then(function(conference) {
        conference.quota.call().then(function(quota) { 
                assert.equal(quota, 100, "Quota doesn't match!"); 
        }).then(function() { 
                return conference.numRegistrants.call(); 
        }).then(function(num) { 
                assert.equal(num, 0, "Registrants doesn't match!");
                return conference.organizer.call();
        }).then(function(organizer) { 
                assert.equal(organizer, owner_account, "Owner doesn't match!");
                done();
        }).catch(done);
  	}).catch(done);
  });

  it("Should update quota", function(done) {
  	
  	Conference.deployed({from: owner_account}).then(function(conference) {
        conference.quota.call().then(
            function(quota) { 
                assert.equal(quota, 100, "Quota doesn't match!"); 
        }).then(
            function() { 
                return conference.changeQuota(300);
        }).then(
            function() { 
                return conference.quota.call()
        }).then(
            function(quota) { 
                assert.equal(quota, 300, "New quota is not correct!");
                done();
        }).catch(done);
  	}).catch(done);
  });


  it("Should let you buy a ticket", function(done) {

  	Conference.deployed({ from: accounts[0] }).then(function(conference) {

        var ticketPrice = web3.toWei(.05, 'ether');
        var initialBalance = web3.eth.getBalance(conference.address).toNumber();  

  			conference.buyTicket({ from: accounts[1], value: ticketPrice }).then(
          function() {
  					var newBalance = web3.eth.getBalance(conference.address).toNumber();
            var difference = newBalance - initialBalance;
  					assert.equal(difference, ticketPrice, "Difference should be what was sent");
  					return conference.numRegistrants.call(); 
  			}).then(
  				function(num) { 
  					assert.equal(num, 1, "there should be 1 registrant");
  					return conference.registrantsPaid.call(sender_account);
  			}).then(
  				function(amount) {
  					assert.equal(amount.toNumber(), ticketPrice, "Sender's paid but is not listed as paying");	
  					return web3.eth.getBalance(conference.address);
  			}).then(
  				function(bal) {
            assert.equal(bal.toNumber(), ticketPrice, "Final balance mismatch");
  					done();
  			}).catch(done);
  	}).catch(done);
  });

  it("Should issue a refund by owner only", function(done) {
    
    Conference.deployed({ from: accounts[0] }).then(function(conference) {

        var ticketPrice = web3.toWei(.05, 'ether');
        var initialBalance = web3.eth.getBalance(conference.address).toNumber(); 

        conference.buyTicket({ from: accounts[1], value: ticketPrice }).then(
          function() {
            var newBalance = web3.eth.getBalance(conference.address).toNumber();
            var difference = newBalance - initialBalance;
            assert.equal(difference, ticketPrice, "Difference should be what was sent");

            // Now try to issue refund as second user - should fail
            return conference.refundTicket(accounts[1], ticketPrice, {from: accounts[1]});
        }).then(
          function() {  
            var balance = web3.eth.getBalance(conference.address);
            assert.equal(balance, ticketPrice, "Balance should be unchanged");
            // Now try to issue refund as organizer/owner
            return conference.refundTicket(accounts[1], ticketPrice, {from: accounts[0]});
        }).then(
          function() {
            var postRefundBalance = web3.eth.getBalance(conference.address).toNumber();
            assert.equal(postRefundBalance, initialBalance, "Balance should be initial balance");
            done();
        }).catch(done);
      }).catch(done);
    });

});