Solidity
msg.sender.transfer(purchaseExcess);堅固性測試失敗
msg.sender.transfer(purchaseExcess);
在我的 truffle solidity 單元測試中遇到了異常。知道原因嗎?我的契約程式碼:
function purchase(uint256 _tokenId) public payable { address oldOwner = tokenOwner[_tokenId]; uint256 sellingPrice = emojiIndexToPrice[_tokenId]; address newOwner = msg.sender; require(oldOwner != newOwner); require(newOwner != address(0)); require(msg.value >= sellingPrice); uint256 percentage = SafeMath.sub(100, ownerCut); uint256 payment = uint256(SafeMath.div(SafeMath.mul(sellingPrice, percentage), 100)); uint256 purchaseExcess = SafeMath.sub(msg.value, sellingPrice); emojiIndexToPrice[_tokenId] = SafeMath.div(SafeMath.mul(sellingPrice, 150), percentage); _transfer(oldOwner, newOwner, _tokenId); if (oldOwner != address(this)) { oldOwner.transfer(payment); } msg.sender.transfer(purchaseExcess); }
單元測試程式碼:
contract TestEmojiCoin { uint public initialBalance = 1 ether; function testPurchase() public { address contractAddress = DeployedAddresses.EmojiCoin(); EmojiCoin emojiCoin = EmojiCoin(contractAddress); // Emoji 0 is created in previous test. emojiCoin.purchase.value(1 ether).gas(30000000000)(0); } }
錯誤資訊
Error: VM Exception while processing transaction: revert at Object.InvalidResponse (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/errors.js:38:1) at /usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/requestmanager.js:86:1 at /usr/local/lib/node_modules/truffle/build/webpack:/~/truffle-provider/wrapper.js:134:1 at XMLHttpRequest.request.onreadystatechange (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/httpprovider.js:128:1) at XMLHttpRequestEventTarget.dispatchEvent (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:64:1) at XMLHttpRequest._setReadyState (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:354:1) at XMLHttpRequest._onHttpResponseEnd (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:509:1) at IncomingMessage.<anonymous> (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:469:1) at endReadableNT (_stream_readable.js:1101:12) at process._tickCallback (internal/process/next_tick.js:114:19)
交易失敗是因為測試合約沒有支付回退功能來接受超額資金“轉移”。
pragma solidity ^0.4.17; import "../contracts/EmojiCoin.sol"; import "truffle/Assert.sol"; import "truffle/DeployedAddresses.sol"; contract TestEmojiCoin { uint public initialBalance = 1 ether; function testPurchase() public { address contractAddress = DeployedAddresses.EmojiCoin(); EmojiCoin emojiCoin = EmojiCoin(contractAddress); // Emoji 0 is created in previous test. address owner_0 = emojiCoin.tokenOwner(0); Assert.notEqual( owner_0, this, "owner for coin 0 is incorrect" ); emojiCoin.purchase.value(1 ether).gas(30000000000)(0); owner_0 = emojiCoin.tokenOwner(0); Assert.equal( owner_0, this, "owner for coin 0 is incorrect" ); } // this new function IS REQUIRED for the test to work function() public payable { } }
添加了兩個斷言測試(有些人可能認為這不是在同一個測試中擁有多個斷言的最佳實踐)
此外,必須實施一個非常基本的 EmojiCoin 合約來檢查這是否是問題所在:
pragma solidity ^0.4.17; import "zeppelin-solidity/contracts/math/SafeMath.sol"; contract EmojiCoin { mapping(uint256 => address) public tokenOwner; mapping(uint256 => uint256) public emojiIndexToPrice; uint256 public ownerCut = 5; function EmojiCoin() public { // very simple constructor for the purpose of testing only tokenOwner[0] = msg.sender; emojiIndexToPrice[0] = 1 ether; } // simple _transfer implementation for the purpose of testing only function _transfer(address oldOwner, address newOwner, uint256 _tokenId) internal { require(tokenOwner[_tokenId] == oldOwner); tokenOwner[_tokenId] = newOwner; } function purchase(uint256 _tokenId) public payable { address oldOwner = tokenOwner[_tokenId]; uint256 sellingPrice = emojiIndexToPrice[_tokenId]; address newOwner = msg.sender; require(oldOwner != newOwner); require(newOwner != address(0)); require(msg.value >= sellingPrice); uint256 percentage = SafeMath.sub(100, ownerCut); uint256 payment = uint256(SafeMath.div(SafeMath.mul(sellingPrice, percentage), 100)); uint256 purchaseExcess = SafeMath.sub(msg.value, sellingPrice); emojiIndexToPrice[_tokenId] = SafeMath.div(SafeMath.mul(sellingPrice, 150), percentage); _transfer(oldOwner, newOwner, _tokenId); if (oldOwner != address(this)) { oldOwner.transfer(payment); } msg.sender.transfer(purchaseExcess); } }