無法讓合約到合約函式呼叫正常工作
我似乎無法弄清楚阻止合約到合約函式呼叫的問題。
我相當有信心這與我的部署方式有關。
***前言:*我有一個
Parent
和Child
契約,孩子可以呼叫父母的電話。子節點擁有父節點的地址,該地址是在部署後設置的,並且在部署新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 部署時我也得到相同的結果)
- 編譯合約:
solc --bin Child.sol Parent.sol
2. 部署合約
- 將
Binary:
for 部分複製Child.sol
到 Mist 的合約部署CONTRACT BYTE CODE
部分,然後部署- 重複
Parent.sol
- 獲取 ABI:
solc --abi Child.sol Parent.sol
4. 觀看契約:
- 將
Contract JSON ABI
部分 for複製Child.sol
到 Mist’sWATCH CONTRACT
中,以及相應的地址- 重複
Parent.sol
- 連結契約
- 選擇
Child
契約setParent
使用父合約的地址執行函式
- 在 Parent 中設置值:
- 選擇
Parent
契約setValue
用 999 或 0 以外的值執行函式從這裡,如果您查看
Child
契約,value
和msg.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 幫助找到這個