¿Cómo llamar a la función de cambio de estado en web3.py?

Tengo un contrato de prueba simple:

contract TestContract {
    address public owner;
    address public someAddress;

    function TestContract() public {
        owner = msg.sender;
    }

    modifier onlyOwner {
        assert(msg.sender == owner);
        _;
    }

    function setSomeAddress(address _newAddress) onlyOwner public {
        someAddress = _newAddress;
    }
}

Según la documentación , debería poder llamar a una función de cambio de estado en un contrato como este:

transact_params = {
    'from': addr_owner,
    'gas': 21000,
    'gas_price': 1,
}
my_contract_instance.transact(transact_params).setSomeAddress(w3.eth.accounts[1])

Sin embargo, esto arroja una excepción:

File "/usr/local/lib/python3.5/dist-packages/web3/contract.py", line 624, in _find_matching_fn_abi
    raise ValueError("No matching functions found")

Intenté eliminar parámetros, verificar ABI (la definición está ahí), ... sin éxito. ¿Qué estoy haciendo mal? ¿Cómo puedo llamar a una función de cambio de estado con web3.py?

¿En qué versión de web3.py estás? ¿Agregaría la definición de ABI que está usando y la línea que crea la instancia del contrato? En general, el enfoque parece correcto.
Estoy en 3.16.2, pero creo que lo descubrí desde la fuente, publicaré la respuesta ... Veo que usted es uno de los desarrolladores, ¡gracias por ayudar y gracias por una gran biblioteca!
¡Feliz de ayudar! :)

Respuestas (2)

A través del seguimiento, quedó claro que ConciseContractse utilizó la fábrica de contratos personalizados. Eso se puede especificar de esta manera:

my_contract_instance = w3.eth.contract(..., ContractFactoryClass=ConciseContract)

ConciseContractbusca la primera llamada de función como un método de contrato. Así que esto:

my_contract_instance.transact(transact_params).setSomeAddress(w3.eth.accounts[1])

... intenta buscar el método transact()que no está disponible en el contrato. Eso produce el error:

raise ValueError("No matching functions found")

En general, si obtiene ese error, significa que está tratando de interactuar con una función que no está definida en la ABI. Tenga en cuenta que las funciones dependen de los argumentos, por lo que si intenta llamar a la función definida en la ABI myfunc(int)con una cadena como argumento, el mensaje será "No se encontraron funciones coincidentes".

Cierto: supongo que lo copié de alguna parte... El problema fue que entendí que la documentación decía que ConciseContractera el único tipo (no abstracto) de Contract. Entonces, si entiendo correctamente, mi ejemplo original debería funcionar si elimino , ContractFactoryClass=ConciseContract?
Sí, parece correcto para el contrato predeterminado. Gracias por marcar la documentación. Veo cómo podría interpretarse de esa manera, así que intentaré aclararlo.
No estoy usando la fábrica ConciseContractde contratos personalizados y sigo recibiendo el mismo error. ¿Puede extender su respuesta si sabe por qué?
@goodvibration Agregué un poco más de información general a la respuesta. Si eso no ayuda, recomendaría hacer una nueva pregunta con antecedentes, código, etc.

EDITAR: la respuesta a continuación es correcta para ConciseContract.

La sintaxis correcta (probada en la versión 13.6.2) es:

my_contract_instance.setSomeAddress(w3.eth.accounts[1], transact=transact_params)

Sin embargo, tenga cuidado: si lo entiendo correctamente, **kwargsdebe tener cero o un elemento que se use para especificar el tipo de llamada (la clave debe ser una de call, transacto estimateGas). Si **kwargsestá vacío, callse utiliza.

*argsluego se pasan a la función de contrato.

Esto es cierto, solo si está utilizando la ConciseContractfábrica por contrato. La sintaxis de su pregunta era correcta para la fábrica de contratos clásica/predeterminada.