Solidity

無法讓合約到合約函式呼叫正常工作

  • August 15, 2018

我似乎無法弄清楚阻止合約到合約函式呼叫的問題。

我相當有信心這與我的部署方式有關。

***前言:*我有一個ParentChild契約,孩子可以呼叫父母的電話。子節點擁有父節點的地址,該地址是在部署後設置的,並且在部署新 Parent合約時應該可以更新。

契約:

iParent.sol

pragma solidity >0.4.23 <0.5.0;

interface IParent {
   function setValue(int v) external;
   function getValue() external view returns (int);                                                         
   function getSender() external view returns (address);
}

父.sol

pragma solidity >0.4.23 <0.5.0;

import "./IParent.sol";

contract Parent is IParent {
   int value;

   function setValue(int v) public {
       value = v;
   }

   function getValue() external view returns (int) {
       return value;
   }

   function getSender() external view returns (address) {
       return msg.sender;
   }
}

孩子.sol

pragma solidity >0.4.23 <0.5.0;

import "./IParent.sol";

contract Child {
   IParent parent;

   function setParent(address a) public {
       parent = IParent(a);
   }

   function getValue() external view returns (int value) {
       return parent.getValue();
   }

   function getSender() external view returns (address value) {
       return parent.getSender();
   }
}

腳步

(我使用 Mist 進行部署以避免我可能引入的任何問題並嘗試隔離問題。使用 web3js 部署時我也得到相同的結果)

  1. 編譯合約:

solc --bin Child.sol Parent.sol 2. 部署合約

  • Binary:for 部分複製Child.sol到 Mist 的合約部署CONTRACT BYTE CODE部分,然後部署
  • 重複Parent.sol
  1. 獲取 ABI:

solc --abi Child.sol Parent.sol 4. 觀看契約:

  • Contract JSON ABI部分 for複製Child.sol到 Mist’sWATCH CONTRACT中,以及相應的地址
  • 重複Parent.sol
  1. 連結契約
  • 選擇Child契約
  • setParent使用父合約的地址執行函式
  1. 在 Parent 中設置值:
  • 選擇Parent契約
  • setValue用 999 或 0 以外的值執行函式

從這裡,如果您查看Child契約,valuemsg.sender值都反映了預設值。

我也嘗試過以下,在Child

function getValueSuccess() external view returns (bool) {
   return parentAddress.call(bytes4(keccak256("getValue()")));
}

這將返回true,但以下始終返回0

function getDummyValue() external view returns (int) {                                                       
   parent.getValue();                                                                                   
   return 999;                                                                                          
} 

此外,使用以下裝配工作:

function getValue() external view returns (int value) {
   address addr = address(parent);
   bytes4 sig = bytes4(keccak256("getValue()"));

   assembly {
      let o := mload(0x40) // Empty storage pointer
      mstore(o,sig)        // Push function signature to memory (function signature is 4 bytes/0x04)
      //mstore(add(ptr,0x40), someInt32Argument); // Append function argument after signature
      // From here, the call data size (input) would be functiona signature size + sum(argument size)
      //   4bytes + 0 in this case, or 4bytes + 32bytes in the above commented `mstore`

      let success := call(
          15000,           // Gas limit
          addr,            // To address
          0,               // No ether to transfer
          o,               // Input location ptr
          0x04,            // Input size (0)
          o,               // Store oputput over input
          0x20)            // Output size (32 bytes)

      value := mload(o)
      mstore(0x40,add(o,0x04))
   }
}

似乎從父地址到IParent的強制轉換不起作用,因為所有呼叫似乎都失敗了,除非我們使用 assembly 或address.call(),我假設它只是將消息發送到地址,避免類型約束*(如使用反射)*

此外,如果我只是將所有契約合併到一個文件中,請將其複制並粘貼到 Mist 的 SOLIDITY CONTRACT SOURCE CODE框中,從下拉列表中部署它們中的每一個。一切都按預期工作。

我在上面缺少哪些步驟才能使其按預期工作?


更新 1

如果我部署一組工作合約,使用 Mist 部署原始碼,然後使用 Mist 中Parent的二進製文件部署,我可以成功地從子級連結/呼叫它。

因此,它看起來像是特定於Child部署的東西。

更新 2

這僅適用於上述測試契約。一旦我把它轉移到我的實際契約中,我就會遇到同樣的問題

我遇到了這個問題,@smarx 的回答是:

僅供參考,您可以這樣做(並以相同的方式從客戶端呼叫它):

NonFungibleToken public nft;

函式 setNFTAddress(NonFungibleToken _nft) onlyOwner{ nft

= _nft;

}

無論出於何種原因,這似乎都有效,而只是將地址轉換為契約並沒有?

為什麼會這樣:

function setParent(Parent p) external {
   parent = p;
}

但不是這個:

function setParent(address addr) external {
   parent = Parent(addr);
}

…更令人困惑的是,為什麼在 Mist 中使用原始碼進行部署時它們都可以工作,而在使用二進製文件時只有第一個工作?

版本:

  • geth:1.8.13-穩定
  • solc: 0.4.24+commit.e67f0147.Linux.g++ (Docker 鏡像: ethereum/solc:stable)
  • 霧:0.10.0

Byzantium通過添加到config您的部分來啟用新的 EVM 功能genesis.json

 "config": {
   "chainId": 1234,
   "homesteadBlock": 0,
   "eip155Block": 0,
   "eip158Block": 0,
   "eip160Block": 0,
   "byzantiumBlock": 0
},

感謝 Solidity 的 @chriseth 幫助找到這個

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