Solidity

從 python 呼叫 web3 函式的問題

  • October 31, 2019

我試圖從我的 python 伺服器呼叫一個函式到部署在 Ropsten 的契約。

這是我在契約中的方法:

function send(address receiver, uint amount) public {
   require(msg.sender == owner);
   balances[receiver] += amount;
   emit Sent(msg.sender, receiver, amount);
}

在這裡我嘗試呼叫該方法:

def default_reward():
   name =  request.json["ckan_user_id"]
   user = db["userinfos"].find_one({"ckan_user_id":name})
   address = user["bc_user_address"]
   contract = wb3.eth.contract(
                       address=config.audacoin_contract_address,
                       abi=get_abi_audacoin(),
                   )
   tx_hash = contract.functions.send(address, 5).call().transact({"from": config.ADMIN_ADDRESS})
   tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)

   return "Sended"

但我不能呼叫該函式。¿ 有人知道我怎麼能呼叫這個方法嗎?

非常感謝。

更新 我已經改變了方法,但我有一個新的錯誤:

def default_reward():
   name =  request.json["ckan_user_id"]
   user = db["userinfos"].find_one({"ckan_user_id":name})
   address = user["bc_user_address"]
   contract = wb3.eth.contract(
                       address=config.audacoin_contract_address,
                       abi=get_abi_audacoin(),
                   )
   tx_hash = contract.functions.send(address, 5).transact({"from": config.ADMIN_ADDRESS})
   tx_receipt = wb3.eth.waitForTransactionReceipt(tx_hash)
   return "Sended"

但我有這個錯誤:

127.0.0.1 - - [31/Oct/2019 12:44:18] "POST /dataset/audacoin/default_reward HTTP/1.1" 500 -
Traceback (most recent call last):
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/flask/app.py", line 2328, in __call__
   return self.wsgi_app(environ, start_response)
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/flask/app.py", line 2314, in wsgi_app
   response = self.handle_exception(e)
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/flask/app.py", line 1760, in handle_exception
   reraise(exc_type, exc_value, tb)
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/flask/_compat.py", line 36, in reraise
   raise value
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/flask/app.py", line 2311, in wsgi_app
   response = self.full_dispatch_request()
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/flask/app.py", line 1834, in full_dispatch_request
   rv = self.handle_user_exception(e)
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/flask/app.py", line 1737, in handle_user_exception
   reraise(exc_type, exc_value, tb)
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/flask/_compat.py", line 36, in reraise
   raise value
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/flask/app.py", line 1832, in full_dispatch_request
   rv = self.dispatch_request()
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/flask/app.py", line 1818, in dispatch_request
   return self.view_functions[rule.endpoint](**req.view_args)
 File "/home/ibai/Documentos/proyecto/AudablokAPI/api/dataset.py", line 665, in default_reward
   tx_hash = contract.functions.send(address, 5).transact({"from": config.ADMIN_ADDRESS})
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/web3/contract.py", line 1151, in transact
   **self.kwargs
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/web3/contract.py", line 1454, in transact_with_contract_function
   txn_hash = web3.eth.sendTransaction(transact_transaction)
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/web3/eth.py", line 269, in sendTransaction
   [transaction],
 File "/home/ibai/Documentos/proyecto/AudablokAPI/venv/lib/python3.6/site-packages/web3/manager.py", line 112, in request_blocking
   raise ValueError(response["error"])
ValueError: {'code': -32601, 'message': 'The method eth_sendTransaction does not exist/is not available'}

簡短的回答

問題在於您嘗試使用該功能進行交易。您不應該call()在之前呼叫transact(). 以下修改應該可以解決它:

tx_hash = contract.functions.send(address, 5).transact({"from": config.ADMIN_ADDRESS})

解釋

鑑於您問題的措辭,我認為您可能不清楚呼叫契約和向契約發送交易之間的區別

  • 呼叫是合約函式的本地呼叫,不會在區塊鏈上廣播或發布任何內容。這是一個只讀操作,不會消耗任何乙太幣。它模擬事務中會發生的情況,但在完成後丟棄所有狀態更改。
  • 交易被廣播到網路,由礦工處理,如果有效,則在區塊鏈上發布。這是一個寫入操作,會影響其他賬戶,更新區塊鏈的狀態,並消耗 Ether(除非礦工以零的 gas 價格接受它)。

web3.py 合約 API允許您呼叫或與任何合約函式進行交易。call返回合約函式返回的任何值,transact返回交易雜湊。

在您的範例中,您首先call()用於呼叫該send函式,該函式返回,None因為send沒有返回值。然後,您嘗試呼叫transact返回的NoneType,這會引發AttributeError.

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