Web3.py Python – Solve Problems Calling Function with Web3

etherpythonropstensolidityweb3.py

I was trying to call a function from my python server to a contract deployed in Ropsten.

This is my method in the contract:

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

Here I try to call the method:

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"

But I can't call the function. ¿Anybody know how can I call this method?

Thanks very much.

UPDATE
I have changed the method, but I have a new error:

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"

But I am having this error:

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'}

Best Answer

Short answer

The issue is in the line where you try to transact with the function. You should not be invoking call() before transact(). The following modification should fix it:

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

Explanation

Given the wording of your question I think you maybe be unclear on the difference between calling a contract and sending a transaction to a contract:

  • A call is a local invocation of a contract function that does not broadcast or publish anything on the blockchain. It is a read-only operation and will not consume any Ether. It simulates what would happen in a transaction, but discards all the state changes when it is done.
  • A transaction is broadcasted to the network, processed by miners, and if valid, is published on the blockchain. It is a write-operation that will affect other accounts, update the state of the blockchain, and consume Ether (unless a miner accepts it with a gas price of zero).

The web3.py contract API allows you to call or transact with any contract function. call returns whatever value(s) the contract function returns, transact returns a transaction hash.

In your example you are first using call() to call the send function, which returns None because send has no return value. You are then attempting to call transact upon the returned NoneType, which raises an AttributeError.

Related Topic