使用java語言類比實現以太坊智能合約執行過程
package contract;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;/** * Created by haibiao on 2018/1/5. */public class BallotContract { private static final String TAG = "BallotContract"; /**身份審核(賦予投票權)截止時間*/ public static final long VERIFY_DEADLINE = 1515168000000L;//2018/01/06 00:00:00.000 /**投票(委託)截止時間*/ public static final long VOTE_DEADLINE = VERIFY_DEADLINE + (1000 * 60 * 2);//身份審核結束後的2分鐘內為投票時間 /**合約單一實例*/ private static BallotContract INSTANCE; /**合約建立者(投票主持人)地址*/ private final String mChairAddress; /**投票者狀態儲存*/ private final Map<String,Voter> mVoterMap = new HashMap<>(); /**提案列表*/ private final Proposal[] mProposals; /**投票結果,得票數最多的提案索引*/ private int[] mVoteResult; /**每次調用合約都會包含的上下文*/ private Ctx ctx; /** * 建立合約,只會執行一次 * @param ctx 調用時的上下文 * @param names 提案名稱數組 */ public static void create(Ctx ctx,String[] names){ if(INSTANCE == null){ INSTANCE = new BallotContract(ctx,names); } } /** * 擷取合約執行個體 * @param ctx 調用時的上下文 * @return 投票合約執行個體 */ public static BallotContract getDefault(Ctx ctx){ INSTANCE.ctx = ctx; return INSTANCE; } /** * 投票合約建構函式,初始化一些變數 * @param ctx 上下文 * @param names 提案名稱數組 */ private BallotContract(Ctx ctx, String[] names) { mChairAddress = ctx.msg.sender; Voter chair = new Voter(); chair.weight = 1; mVoterMap.put(mChairAddress,chair); mProposals = new Proposal[names.length]; for(int i = 0 ; i < mProposals.length ; i++){ mProposals[i] = new Proposal(); mProposals[i].name = names[i]; } } /** * 擷取投票結果,只有當投票階段結束且調用了一次統票方法才會有值 * @return 投票結果 */ public int[] getVoteResult(){ return mVoteResult; } /** * 賦予投票權,只能主持人調用 * @param address 賦予的目標地址 * @return 賦予投票權結果 */ public boolean giveVoteRight(String address){ if(System.currentTimeMillis() > VERIFY_DEADLINE){ log("giveVoteRight time already over"); return false; } if(!mChairAddress.equals(ctx.msg.sender)){ log("giveVoteRight only the chairman can call"); return false; } Voter voter = mVoterMap.get(address); if(voter == null){ voter = new Voter(); voter.weight = 1; mVoterMap.put(address,voter); log("giveVoteRight success , address = " + address); return true; }else{ log("giveVoteRight failed , yet give,address = "+address); } return false; } /** * 委託操作,將投票權委託給他人 * @param to 受託人地址 * @return 委託結果 */ public boolean delegate(final String to){ final long curr = System.currentTimeMillis(); if(curr <= VERIFY_DEADLINE){ log("delegate failed,The delegate hasn't begun"); return false; } if(curr > VOTE_DEADLINE){ log("delegate failed,delegate already over "); return false; } final String sender = ctx.msg.sender; Voter fromVoter = mVoterMap.get(sender); if(fromVoter == null //沒有投票權 || fromVoter.weight <= 0 //沒有投票權 || sender.equals(to) //委託給自己 ){ log("delegate failed"); return false; } String toTemp = to; Voter toVoter = null; while (true){ toVoter = mVoterMap.get(toTemp); if(toVoter == null//受託人沒有投票權 || toVoter.weight <= 0 //受託人沒有投票權 ){ return false; } if(toVoter.delegate == null){ toVoter.weight += fromVoter.weight; fromVoter.weight = 0; fromVoter.delegate = toTemp; return true; }else{ toTemp = toVoter.delegate; } } } /** * 執行投票 * @param index 提案的索引 * @return 投票結果 */ public boolean vote(int index){ final long curr = System.currentTimeMillis(); if(curr <= VERIFY_DEADLINE){ log("vote failed,The delegate hasn't begun"); return false; } if(curr > VOTE_DEADLINE){ log("vote failed,vote already over"); return false; } if(index < 0 || index >= mProposals.length){ log("proposal index error , index = "+index); return false; } final String sender = ctx.msg.sender; Voter voter = mVoterMap.get(sender); if(voter == null //沒有投票權 || voter.weight <= 0 //沒有投票權 ){ log("vote failed"); return false; } final Proposal proposal = mProposals[index]; proposal.voteCount += voter.weight; voter.weight = 0; voter.proposalIndex = index; return true; } /** * 統計票數,任何人都可以隨時調用,當投票階段結束後,調用此方法會將會儲存最終的投票結果 * @return 當前統票結果 */ public int[] statisticsVote(){ if(System.currentTimeMillis() <= VERIFY_DEADLINE){ log("The statistics vote hasn't begun"); return new int[0]; } final List<Integer> result = new ArrayList<>(1); int maxCount = -1; for(int i = 0 ; i < mProposals.length ; i++){ int count = mProposals[i].voteCount; if(count > maxCount){ maxCount = count; result.clear(); result.add(i); }else if(count == maxCount){ result.add(i); } } int[] arr = new int[result.size()]; for(int i = 0 ; i < arr.length ; i++){ arr[i] = result.get(i); } if(System.currentTimeMillis() > VOTE_DEADLINE){ //投票階段已結束,儲存統票結果 mVoteResult = arr; } log("statistics vote result = "+ Arrays.toString(arr)); return arr; } private static void log(String msg){ System.out.println(String.format("[%s]%s",TAG,msg)); } /** * 投票者資料結構 */ private static class Voter{ int weight;//票數 String delegate;//受託者 int proposalIndex;//提案索引號 } /** * 提案資料結構 */ private static class Proposal{ String name;//提案名稱 int voteCount;//提案所得票數 }}