Solidity

來自 web3 的持續合約呼叫返回不一致的值

  • December 5, 2018

我在這裡的主網上有這個 dapp 。

以下合約已部署在此地址

pragma solidity ^0.4.19;

import 'zeppelin-solidity/contracts/ownership/Ownable.sol';
import 'zeppelin-solidity/contracts/lifecycle/Destructible.sol';
import 'zeppelin-solidity/contracts/lifecycle/Pausable.sol';
import 'zeppelin-solidity/contracts/math/SafeMath.sol';

contract CryptoTwittos is Ownable, Pausable, Destructible {
 using SafeMath for uint;

 // A Twitto is owned by a stealer and has a price
 struct Twitto {
   address stealer;
   uint price;
 }

 // Look up Twitto by ids
 mapping(uint => Twitto) public twittos;

 // All Twitto ids and counter
 uint[] public twittoIds;
 uint public twittosCounter;


 // Fire event when steal happens
 event stealEvent(
   uint indexed id,
   address indexed owner,
   uint price,
   address indexed stealer,
   uint newPrice
 );


 // Get twittoIds
 function getTwittoIds(bool all) public view returns (uint[]) {
   // Return empty array if counter is zero
   if (twittosCounter == 0) return new uint[](0);

   if (all) {
     // Return all of them
     return twittoIds;

   } else {
     // Create memory array to store filtered ids
     uint[] memory filteredIds = new uint[](twittosCounter);
     // Store number of belongings
     uint twittosCount = 0;

     for (uint i = 0; i < twittosCounter; i++) {
       // Check if stealer is sender
       if (twittos[twittoIds[i]].stealer == msg.sender) {
         filteredIds[twittosCount] = twittoIds[i];
         twittosCount++;
       }
     }

     // Copy the filteredIds array into a smaller array
     uint[] memory trophies = new uint[](twittosCount);
     for (uint j = 0; j < twittosCount; j++) {
       trophies[j] = filteredIds[j];
     }
     return trophies;
   }
 }

 // Steal a Twitto by paying its price and setting a new one
 function steal(uint id, uint256 newPrice) payable whenNotPaused public {

   // look up the twitto and put on storage
   Twitto storage _twitto = twittos[id];

   // Prevent self stealing!
   require(msg.sender != _twitto.stealer);

   // Make sure the sender pays the right price
   require(msg.value == _twitto.price);

   // Make sure that the new price is higher than the old price
   require(newPrice > _twitto.price);

   // Transfer value with the 1% dev fee
   if (msg.value > 0) {
     _twitto.stealer.transfer(msg.value.mul(99).div(100));
   }

   // Push new Twitto if not existing
   if (_twitto.price == 0) {
     twittoIds.push(id);
     twittosCounter++;
   }

   // Trigger event
   stealEvent(id, _twitto.stealer, _twitto.price, msg.sender, newPrice);

   // Store new stealer
   _twitto.stealer = msg.sender;

   // Store new price
   _twitto.price = newPrice;

 }

 function withdraw() public onlyOwner {

   // Transfer balance to owner
   msg.sender.transfer(address(this).balance);
 }


}

引起麻煩的常量方法是getTwittoIds:一切正常,但是數組的大小增加了一點(正如您可以看到Etherscan上的事務數),現在這個常量方法呼叫有時會返回一個空數組有時不是。

閱讀類似這樣的問題時,我認為這是由於氣體限製過低(對於不斷呼叫),但問題仍然存在。

重現此“錯誤”的最簡單步驟​​如下:

  1. 轉到https://cryptotwittos.com/
  2. 確保 MetaMask 已啟用
  3. 打開控制台
  4. 與 abi 簽訂契約:
var CT = web3.eth.contract([{"constant":true,"inputs":[],"name":"twittosCounter","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"destroy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"twittos","outputs":[{"name":"stealer","type":"address"},{"name":"price","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"twittoIds","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"}],"name":"destroyAndSend","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"id","type":"uint256"},{"indexed":true,"name":"owner","type":"address"},{"indexed":false,"name":"price","type":"uint256"},{"indexed":true,"name":"stealer","type":"address"},{"indexed":false,"name":"newPrice","type":"uint256"}],"name":"stealEvent","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"constant":true,"inputs":[{"name":"all","type":"bool"}],"name":"getTwittoIds","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"id","type":"uint256"},{"name":"newPrice","type":"uint256"}],"name":"steal","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}])
  1. 獲取實例
var CTInstance = CT.at("0xa4b9054417ee4f06453152a45ebeba7786c84c66")
  1. 應返回所有 TwittoIds 的呼叫方法
CTInstance.getTwittoIds(true, console.log)
  1. 說服自己該方法不應該返回一個空數組
CTInstance.twittosCounter(console.log)

經過兩天的研究,我仍然不知道發生了什麼,所以任何幫助將不勝感激。

非常感謝!

我嘗試在geth節點上執行它並且確實返回0x

但是在奇偶校驗節點上執行它會返回一個巨大的輸出(我想這就是你需要的)

> eth.call({to:"0xa4b9054417ee4f06453152a45ebeba7786c84c66", data:"0xd15e656c0000000000000000000000000000000000000000000000000000000000000001", gas: "440000"})

輸出: https ://gist.github.com/cleanunicorn/b90fc5141d157e7dcc861522af25cb5a

該操作消耗的氣體接近440000並且會增加。

我還沒有檢查過 geth 原始碼,但似乎它在停止之前可以執行多少是有限制的。

Infura 有geth節點,這就是為什麼(如果你正在使用它們)它返回0x. 可能他們也在嘗試parity或自定義建構,有時您會得到正確的結果

引用自:https://ethereum.stackexchange.com/questions/44537