是否可以获取从另一个合约外部函数获取数据的外部函数的 return 值?
Is it possible to get the return value of an external function that gets data from another contracts external function?
注意:这只是从 web3js 调用外部视图函数时的一个问题,因为它不会创建事务
我有 2 份合同,A
和 B
(一个是存储合约,一个更像是逻辑合约)
如果 A
有这样的函数:
function getValueFor(uint8 index) external view returns(uint8) {
return someMapping[index];
}
而 B
具有如下函数:
function isValid() external view returns(bool) {
return instanceOfA.getValueFor(1) == 1;
}
从 Mist 或 web3js 中,A
中的 return 值按预期工作,并且在调用 B
时,默认值始终是 returned。
(在本例中为 0
)
你不能从合同中获取 return 值 -> 来自 web3js 的合同 external/constant 函数调用吗?这需要交易吗?
更新
参见 ethereum.stackexchange 上的 answer。
我在交易期间的工作大多不正确。它似乎与我的特定测试功能一起工作,尽管大多数其他功能都失败了 (我只是 lucky/unlucky 我正在使用的一个测试功能).
问题的根源只是没有在我的 Geth 节点上启用新的拜占庭 (启用新的 EVM 功能)。
当然可以。 Truffle 控制台中的快速 运行 将显示它:
pragma solidity >0.4.23 <0.5.0;
contract A {
uint256 value;
constructor(uint256 v) public {
value = v;
}
function getValue() external view returns (uint256) {
return value;
}
}
contract B {
A other;
constructor(address a) public {
other = A(a);
}
function getValueFromA() external view returns (uint256) {
return other.getValue();
}
}
执行:
$ truffle console
truffle(development)> var aContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"v","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]);
truffle(development)> var transObj = { from: web3.eth.accounts[0], data: '0x608060405234801561001057600080fd5b506040516020806100ea83398101806040528101908080519060200190929190505050806000819055505060a1806100496000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806320965255146044575b600080fd5b348015604f57600080fd5b506056606c565b6040518082815260200191505060405180910390f35b600080549050905600a165627a7a72305820dd332a08d090a6766cf7c2e86f41abc58a31e4d1afe7cb635a0a1b755a9b81cd0029', gas: '4700000'};
truffle(development)> var a = aContract.new(35, transObj);
truffle(development)> a.getValue();
BigNumber { s: 1, e: 1, c: [ 35 ] }
truffle(development)> var bContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"getValueFromA","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"a","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]);
truffle(development)> transObj.data = '0x608060405234801561001057600080fd5b506040516020806101e783398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610164806100836000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680639b9be7cd14610046575b600080fd5b34801561005257600080fd5b5061005b610071565b6040518082815260200191505060405180910390f35b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663209652556040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156100f857600080fd5b505af115801561010c573d6000803e3d6000fd5b505050506040513d602081101561012257600080fd5b81019080805190602001909291905050509050905600a165627a7a7230582096cc7381535016229911569ae3821103afb9a1ce582f3fc7bf226f3b5fac72380029';
truffle(development)> b = bContract.new(a.address, transObj);
truffle(development)> b.getValueFromA();
BigNumber { s: 1, e: 1, c: [ 35 ] }
这里有一个 work-around/hack 可以使它在事务之外工作 (使用 web3js
的外部视图函数调用)
pragma solidity >0.4.23 <0.5.0;
contract Parent {
int value;
function setValue(int v) public {
value = v;
}
function getValue() external view returns (int) {
return value;
}
}
contract Child {
Parent parent;
function setParent(address a) public {
parent = Parent(a);
}
function getValue() external view returns (int value) {
// -- Should work
//return parent.getValue();
// -- Make it work
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)
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))
}
}
}
这似乎仍然很愚蠢,因为这不能仅使用常规函数调用来工作。
(也许这是一个错误?)
注意:这只是从 web3js 调用外部视图函数时的一个问题,因为它不会创建事务
我有 2 份合同,A
和 B
(一个是存储合约,一个更像是逻辑合约)
如果 A
有这样的函数:
function getValueFor(uint8 index) external view returns(uint8) {
return someMapping[index];
}
而 B
具有如下函数:
function isValid() external view returns(bool) {
return instanceOfA.getValueFor(1) == 1;
}
从 Mist 或 web3js 中,A
中的 return 值按预期工作,并且在调用 B
时,默认值始终是 returned。
(在本例中为 0
)
你不能从合同中获取 return 值 -> 来自 web3js 的合同 external/constant 函数调用吗?这需要交易吗?
更新
参见 ethereum.stackexchange 上的 answer。
我在交易期间的工作大多不正确。它似乎与我的特定测试功能一起工作,尽管大多数其他功能都失败了 (我只是 lucky/unlucky 我正在使用的一个测试功能).
问题的根源只是没有在我的 Geth 节点上启用新的拜占庭 (启用新的 EVM 功能)。
当然可以。 Truffle 控制台中的快速 运行 将显示它:
pragma solidity >0.4.23 <0.5.0;
contract A {
uint256 value;
constructor(uint256 v) public {
value = v;
}
function getValue() external view returns (uint256) {
return value;
}
}
contract B {
A other;
constructor(address a) public {
other = A(a);
}
function getValueFromA() external view returns (uint256) {
return other.getValue();
}
}
执行:
$ truffle console
truffle(development)> var aContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"v","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]);
truffle(development)> var transObj = { from: web3.eth.accounts[0], data: '0x608060405234801561001057600080fd5b506040516020806100ea83398101806040528101908080519060200190929190505050806000819055505060a1806100496000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806320965255146044575b600080fd5b348015604f57600080fd5b506056606c565b6040518082815260200191505060405180910390f35b600080549050905600a165627a7a72305820dd332a08d090a6766cf7c2e86f41abc58a31e4d1afe7cb635a0a1b755a9b81cd0029', gas: '4700000'};
truffle(development)> var a = aContract.new(35, transObj);
truffle(development)> a.getValue();
BigNumber { s: 1, e: 1, c: [ 35 ] }
truffle(development)> var bContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"getValueFromA","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"a","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]);
truffle(development)> transObj.data = '0x608060405234801561001057600080fd5b506040516020806101e783398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610164806100836000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680639b9be7cd14610046575b600080fd5b34801561005257600080fd5b5061005b610071565b6040518082815260200191505060405180910390f35b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663209652556040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156100f857600080fd5b505af115801561010c573d6000803e3d6000fd5b505050506040513d602081101561012257600080fd5b81019080805190602001909291905050509050905600a165627a7a7230582096cc7381535016229911569ae3821103afb9a1ce582f3fc7bf226f3b5fac72380029';
truffle(development)> b = bContract.new(a.address, transObj);
truffle(development)> b.getValueFromA();
BigNumber { s: 1, e: 1, c: [ 35 ] }
这里有一个 work-around/hack 可以使它在事务之外工作 (使用 web3js
的外部视图函数调用)
pragma solidity >0.4.23 <0.5.0;
contract Parent {
int value;
function setValue(int v) public {
value = v;
}
function getValue() external view returns (int) {
return value;
}
}
contract Child {
Parent parent;
function setParent(address a) public {
parent = Parent(a);
}
function getValue() external view returns (int value) {
// -- Should work
//return parent.getValue();
// -- Make it work
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)
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))
}
}
}
这似乎仍然很愚蠢,因为这不能仅使用常规函数调用来工作。
(也许这是一个错误?)