无法在已部署的合约中调用函数

Posted

技术标签:

【中文标题】无法在已部署的合约中调用函数【英文标题】:Cannot call function within deployed contract 【发布时间】:2017-12-21 00:49:06 【问题描述】:

我正在尝试让已部署的 HelloWorld 合同在节点应用程序中运行。我想像这样运行call() 函数来检查它:

const deployed = helloWorldContract.new(
  from: acct1,
  data: compiled.contracts[':HelloWorld'].bytecode,
  gas: 151972,
  gasPrice: 5
, (error, contract) => 
    if(!error)
      console.log(contract.displayMessage.call());
     else 
      console.log(error);
    
);

以下是合同供参考:

contract HelloWorld 
  function displayMessage() public constant returns (string)
    return "hello from smart contract - name";
  

当我在回调中尝试 console.log(contract.displayMessage.call()) 时,返回:TypeError: Cannot read property 'call' of undefined,但是,当我登录 console.log(contract.displayMessage) 时,它返回:

 [Function: bound ]
   request: [Function: bound ],
   call: [Function: bound ],
   sendTransaction: [Function: bound ],
   estimateGas: [Function: bound ],
   getData: [Function: bound ],
   '': [Circular] 

我在这里做错了什么?如何在已部署的合约中运行 call 函数?

【问题讨论】:

它不是一个函数而不是一个属性吗? 正确。如果它是一个属性,我不会使用 contract.displayMessage.call 访问吗?如果它是一个函数,我不能用 contract.displayMessage.call() 访问它吗?为了清楚起见,将合同代码添加到问题中 我的意思是 displayMessage? 是的,它是一个函数,在我的合同中定义,尽管console.log(contract.displayMessage) 将返回上面发布的对象。如果我自己运行console.log(contract.displayMessage());,我会得到:contract.displayMessage is not a function 如果我运行console.log(contract.displayMessage().call());,我会得到:contract.displayMessage is not a function 你有什么建议? 【参考方案1】:

我认为您的问题可能是由.new 构造函数引起的。我个人不推荐使用它,因为它很奇怪。相反,您应该将字节码部署为标准事务。

无论如何,如果您查看.new 的source code,您会发现回调实际上被调用了两次。这是完全非标准的,据我所知,没有记录。

事务发送后第一次调用回调,contract对象会设置transactionHash

第二次调用回调时,contract 对象应该设置了address 属性。这就是你想要的,因为没有地址属性,你不能调用合约方法。

简而言之,试试这个

const deployed = helloWorldContract.new(
  from: acct1,
  data: compiled.contracts[':HelloWorld'].bytecode,
  gas: 151972,
  gasPrice: 5
, (error, contract) => 
    if (error)
      console.error(error);
     else 
      console.log(contract);
      if (contract.address) 
        console.log(contract.displayMessage());
      
    
);

不使用.new方法部署合约,首先需要生成合约字节码和ABI。您可以使用solc 或在线solidity 编译器或任何其他方式获得它。

然后部署您使用web3.eth.sendTransaction 并将data 参数设置为字节码和一个空的to 地址的合约。 sendTransaction会给你一个transactionHash,你需要等待被挖掘和确认。最简单的方法是通过轮询——我写的这个方法是一个很好的起点——https://gist.github.com/gaiazov/17c9fc7fdedf297e82386b74b34c61cd

如果您的合约采用构造函数参数,它们会附加到字节码中,例如data: bytecode + encodedConstructorArguments.

【讨论】:

非常感谢!你是对的,它被调用了两次,我没有任何线索(因为我什至没有走那么远)。您能否提供一个关于如何将字节码部署为标准事务的建议? 我添加了关于如何在没有“新”方法的情况下部署合约的简短描述。它有点高级,但我希望它有所帮助!

以上是关于无法在已部署的合约中调用函数的主要内容,如果未能解决你的问题,请参考以下文章

如何调用 Solidity 函数从智能合约中返回以太币?

无法以大数字作为参数从 web3 调用合约函数

如何使用 Python 和 web3.py 调用智能合约函数

调用 Rust 初始化函数时出现“无法反序列化合约状态”

Web3 错误:Geth 无法与/调用合约函数进行交易

无法在已部署的反应本机应用程序上使用 IP 地址进行本地网络调用