Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot use contract calls with signing middleware: invalid "from" key error #2198

Closed
Pet3ris opened this issue Nov 3, 2021 · 8 comments · Fixed by ethereum/eth-tester#297

Comments

@Pet3ris
Copy link

Pet3ris commented Nov 3, 2021

  • Version: latest web3["tester"]
  • Python: 3.8
  • OS: osx

What was wrong?

MOCK_CONTRACT = """
val: public(uint256)
"""

MOCK_ABI = """[
    {
        "inputs": [],
        "name": "val",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "",
                "type": "uint256"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    }
]
"""

def deploy_contract(w3):
    compiled = compile_code(MOCK_CONTRACT)
    deployment_bytecode = compiled["bytecode"]
    vault = w3.eth.contract(
        abi=MOCK_ABI, bytecode=deployment_bytecode
    )

    # Deploy vault contract
    receipt = w3.eth.wait_for_transaction_receipt(
        vault.constructor().transact()
    )
    return receipt["contractAddress"]

def test_call_signed():
    w3 = Web3(EthereumTesterProvider())
    acct = Account.create("TEST ACCOUNT")
    w3.eth.send_transaction({"to": acct.address, "value": 10**9})
    w3.middleware_onion.add(construct_sign_and_send_raw_middleware(acct))
    w3.eth.default_account = acct.address

    contract_address = deploy_contract(w3)
    contract = w3.eth.contract(address=contract_address, abi=MOCK_ABI)
    _ = contract.functions.val().call()

This test fails with the error No valid "from" key was provided. Please note that the deployment transaction succeeds but the contract call fails even though contract calls don't require signing.

I've also confirmed that the calls work well without the signing middleware.

How can it be fixed?

Could we remove the from check from call() altogether even in signed middleware mode?

@fselmo
Copy link
Collaborator

fselmo commented Nov 3, 2021

Hey @Pet3ris. This code is using EthereumTesterProvider as the provider and this message is coming from eth-tester, not web3.py. This could possibly be argued as an improvement on the eth-tester messaging but notice that web3.py is not stopping the call before it goes to the provider. I'm not sure the scope of usage for eth-tester but if you would like to see this implemented we can move the conversation to an issue on the eth-tester repo.

I'm going to close this for now but if you are still seeing issues with other providers / on a test net... or if I missed something... then please feel free to re-open!

@fselmo
Copy link
Collaborator

fselmo commented Nov 3, 2021

@Pet3ris I think I understand this a bit better. So the messaging in eth-tester could probably definitely improve still and we can talk about that over in that thread. eth_call is not getting signed here but you are setting w3.eth.default_account = acct.address which will always use the from as the default address (including in contract calls).

That line is explicitly saying "every time I make a request, use this address as the from address".

So when you send it to eth-tester, it correctly doesn't recognize your from address because it only exists locally. What was confusing me a bit is the messaging in the eth-tester error. You are providing a from "key"... its just that it isn't a valid or known address (since it only exists locally).

Does that make sense? If you remove the line w3.eth.default_account = acct.address, this should work. Can you give that a try?

@Pet3ris
Copy link
Author

Pet3ris commented Nov 3, 2021

@fselmo makes sense!

If I remove the line it works, but my understanding from the web3.py documentation (https://web3py.readthedocs.io/en/stable/middleware.html#web3.middleware.construct_sign_and_send_raw_middleware) is that this line is a convenient way to ensure that all transactions would be sent from that from address?

Would the work-around be to manually specify the "from" address in all the transact calls but not specify it in the calls?

In terms of eth-tester, my goal was to use it to unit test the logic. I guess I still don't understand from a UX perspective why eth-tester would be able to submit transactions from accounts that are not created but not able to issue calls from those accounts :)?

@fselmo
Copy link
Collaborator

fselmo commented Nov 3, 2021

I'm actually going to re-open this to investigate some different scenarios too to see if we can improve this flow a bit more. But I'm glad you were at least able to get unstuck for now. I will update here if / when I have any updates after doing some testing. Thanks for reporting this!

@fselmo fselmo reopened this Nov 3, 2021
@Pet3ris
Copy link
Author

Pet3ris commented Nov 3, 2021

Thanks - happy to answer more questions or clarify more about use case if at all helpful but love the fact that I can just insert the middleware and reuse the same code across unit tests and prod.

@kclowes
Copy link
Collaborator

kclowes commented Feb 4, 2022

@fselmo or @Pet3ris can this be closed with the eth-tester upgrade in web3.py 5.27.0?

@fselmo
Copy link
Collaborator

fselmo commented Feb 4, 2022

I think I originally thought this was a missing from key issue (when I linked this to ethereum/eth-tester#228) but this is likely something else altogether. Thanks for reminding me this exists though 😄. I think we should keep this open for now.

@eshgovil
Copy link

eshgovil commented May 30, 2022

I am also having a similar issue when doing unit tests, using EthereumTesterProvider:

I'm creating a local account (using w3.eth.account.create) to sign a message with the private key, then later when I try to deploy a contract "from" the local account's address, I get eth_tester.exceptions.ValidationError: No valid "from" key was provided in the transaction which is required for transaction signing.

Essentially when I call w3.eth.account.create I expect that new address to get added to the list of "available" accounts i.e. w3.eth.accounts. Would be great to hear if there are any updates here, or learn if/why that is not possible!

FYI I think this is possible to do this with Brownie. Ideally I don't want to rewrite my test suite to use Brownie (yet) but it's a good alternative.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants