Solidity沒有print或console.log方法可以用來打印變量,這會給我們調試程序增加難度。
Solidity有event功能,可以在event中記錄變量信息,通過調用event方法也可以實現打印功能,但不可能處處寫event方法,麻煩。
以下代碼實現了可重用的log方法,只要調用log()方法就可以打印不同類型的變量值。
使用方法為:log(string name, var value)
pragma solidity ^0.4.21; //通過log函數重載,對不同類型的變量trigger不同的event,實現solidity打印效果,使用方法為:log(string name, var value) contract Console { event LogUint(string, uint); function log(string s , uint x) internal { emit LogUint(s, x); } event LogInt(string, int); function log(string s , int x) internal { emit LogInt(s, x); } event LogBytes(string, bytes); function log(string s , bytes x) internal { emit LogBytes(s, x); } event LogBytes32(string, bytes32); function log(string s , bytes32 x) internal { emit LogBytes32(s, x); } event LogAddress(string, address); function log(string s , address x) internal { emit LogAddress(s, x); } event LogBool(string, bool); function log(string s , bool x) internal { emit LogBool(s, x); } }
我嘗試過用var替代變量類型,但是編譯不通過,應該是var不能做函數參數類型。
以下是編譯不過的:
pragma solidity ^0.4.21; contract Console { event LogUint(string, var); function log(string s , var x) internal { emit LogUint(s, x); } }
使用時只需要將Console.sol import進程序且繼承Console就好(注意第3行和第41行):
1 pragma solidity ^0.4.21; 2 3 import "browser/Console.sol"; 4 5 contract SimpleAuction is Console { 6 // Parameters of the auction. Times are either 7 // absolute unix timestamps (seconds since 1970-01-01) 8 // or time periods in seconds. 9 address public beneficiary; //受益人 10 uint public auctionEnd; //競拍終止時間 11 12 // Current state of the auction. 13 address public highestBidder; //最高競拍者 14 uint public highestBid; //最高競拍 15 16 // Allowed withdrawals of previous bids 17 mapping(address => uint) pendingReturns; //待退回的競拍(不是最高出價都退回) 18 19 // Set to true at the end, disallows any change 20 bool ended; //一旦設置不允許再投標 21 22 // Events that will be fired on changes. 23 event HighestBidIncreased(address bidder, uint amount); //最高出價變動時調用事件 24 event AuctionEnded(address winner, uint amount); // 拍賣結束時調用事件 25 26 // The following is a so-called natspec comment, 27 // recognizable by the three slashes. 28 // It will be shown when the user is asked to 29 // confirm a transaction. 30 31 /// Create a simple auction with `_biddingTime` 32 /// seconds bidding time on behalf of the 33 /// beneficiary address `_beneficiary`. 34 /// 初始化拍賣對象:受益人地址、拍賣持續時間 35 function SimpleAuction( 36 uint _biddingTime, 37 address _beneficiary 38 ) public { 39 beneficiary = _beneficiary; 40 auctionEnd = now + _biddingTime; 41 log("time now", now); 42 } 43 44 /// Bid on the auction with the value sent 45 /// together with this transaction. 46 /// The value will only be refunded if the 47 /// auction is not won. 48 ///對競拍投標,payable代表該交易可以獲取ether,只有沒有競拍成功的交易款才會退回 49 function bid() public payable { 50 // No arguments are necessary, all 51 // information is already part of 52 // the transaction. The keyword payable 53 // is required for the function to 54 // be able to receive Ether. 55 56 // Revert the call if the bidding 57 // period is over. 58 //輸入檢查,競拍如果結束則終止 59 require(now <= auctionEnd); 60 61 // If the bid is not higher, send the 62 // money back. 63 //如果投標金額未超過當前最高金額,則終止 64 require(msg.value > highestBid); 65 66 if (highestBid != 0) { 67 // Sending back the money by simply using 68 // highestBidder.send(highestBid) is a security risk 69 // because it could execute an untrusted contract. 70 // It is always safer to let the recipients 71 // withdraw their money themselves. 72 pendingReturns[highestBidder] += highestBid; //原來的最高變次高出價,次高出價要退回 73 } 74 highestBidder = msg.sender; //新的最高出價者 75 highestBid = msg.value; //新的最高出價 76 emit HighestBidIncreased(msg.sender, msg.value); //觸發最高出價增加事件 77 } 78 79 /// Withdraw a bid that was overbid. 80 /// 取回被淘汰的競拍 81 function withdraw() public returns (bool) { 82 uint amount = pendingReturns[msg.sender]; 83 if (amount > 0) { 84 // It is important to set this to zero because the recipient 85 // can call this function again as part of the receiving call 86 // before `send` returns. 87 pendingReturns[msg.sender] = 0; //在send方法被執行之前,將待退還的錢置為0 *這個很重要* 因為如果不置為0的話,可以重復發起withdraw交易,send需要時間,在交易沒確認之前,重復發起可能就要退N倍的錢 88 89 if (!msg.sender.send(amount)) { //用戶自己取回退回的款項時,如果出錯不用調用throw方法,而是將被置0的待退款金額恢復 90 // No need to call throw here, just reset the amount owing 91 pendingReturns[msg.sender] = amount; 92 return false; 93 } 94 } 95 return true; 96 } 97 98 /// End the auction and send the highest bid 99 /// to the beneficiary. 100 function auctionEnd() public { 101 // It is a good guideline to structure functions that interact 102 // with other contracts (i.e. they call functions or send Ether) 103 // into three phases: 104 // 1. checking conditions 105 // 2. performing actions (potentially changing conditions) 106 // 3. interacting with other contracts 107 // If these phases are mixed up, the other contract could call 108 // back into the current contract and modify the state or cause 109 // effects (ether payout) to be performed multiple times. 110 // If functions called internally include interaction with external 111 // contracts, they also have to be considered interaction with 112 // external contracts. 113 114 // 1. Conditions 115 require(now >= auctionEnd); // auction did not yet end 116 require(!ended); // this function has already been called 117 118 // 2. Effects 119 ended = true; 120 emit AuctionEnded(highestBidder, highestBid); 121 122 // 3. Interaction 123 beneficiary.transfer(highestBid); 124 } 125 }
log方法執行后可以在這里找到打印出的變量信息: