[Ethereum] Web3.py transact works but call doesn’t

pythontransactionsweb3.py

I am trying to call a fairly simple contract on a private blockchain:

function getOwner() public returns (address) {
    return owner;
}

And here is my running it from an interactive Python shell:

>>> e.unlock_account()

>>> instance.functions.getOwner().transact()
HexBytes('0x4f366ba7bb7ae0ef70e48c3ce7eb4f920d7079e90a10bfea36fc9fbbb48d52fe')

That works fine, but I need the function return value, not the transaction hash. So I believe I need to then call it right?

>>> e.unlock_account()

>>> instance.functions.getOwner().call({'from': e.account})

... error trace ...
eth_abi.exceptions.InsufficientDataBytes: Tried to read 32 bytes.  Only got 0 bytes
... more error traces ...
raise BadFunctionCallOutput(msg) from e
web3.exceptions.BadFunctionCallOutput: Could not transact with/call contract function, is contract deployed correctly and chain synced?

Has anyone any idea what I'm doing wrong?


Edit: I have tested it with another even more basic contract, and it seems to work fine. The contracts only differ in that the one that works returns an int..

function reveal() public view returns (int) {
    return number;
}

When I call() the function above, it returns the correct number.


Edit 2: I removed all of the functions from the contract related to setting an owner address, and now everything works. I have supplied the before and after versions of the contract, in case anyone else comes across the same issue. I still have no idea what is causing the contract not to work with addresses.. Is it something to do with the constructor? Any explanations are appreciated!

BEFORE EDIT (NOT WORKING)    

pragma solidity ^0.4.0;

contract CryptoCert {

struct Award {
    bool isValid;
    string hash;
}

struct Authority {
    bool isValid;
    string hash;
    address[] representatives;
    Award[] awards;
}

address private owner;

mapping(address => Authority) authorities;

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

modifier onlyBy(address _address) {
    require(msg.sender == _address);
    _;
}

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

function kill() external {
    if (msg.sender == owner) {
        selfdestruct(owner);
    }
}

function createAuthority(address _address, string _hash) public onlyOwner {
    authorities[_address].hash = _hash;
    authorities[_address].isValid = true;
}

function addAuthorizedAddress(address _authAddress, address _repAddress) public onlyBy(_authAddress) {
    authorities[_authAddress].representatives.push(_repAddress);
}

function getAuthorityHash(address _address) public view returns (uint) {
    if (authorities[_address].isValid) {
        return 1;
    } else {
        return 0;
    }
}

function getOwner() public view returns (address) {
    return owner;
}

function test() public pure returns (string) {
    return "nigchicken69";
}

}

And after…

AFTER EDIT (WORKING)

pragma solidity ^0.4.0;

contract CryptoCert2 {

    struct Award {
        bool isValid;
        string hash;
    }

    struct Authority {
        bool isValid;
        string hash;
        address[] representatives;
        Award[] awards;
    }

    mapping(address => Authority) authorities;

    function createAuthority(address _address, string _hash) public {
        authorities[_address].hash = _hash;
        authorities[_address].isValid = true;
    }

    function addAuthorizedAddress(address _authAddress, address _repAddress) public {
        authorities[_authAddress].representatives.push(_repAddress);
    }

    function getAuthorityHash(address _address) public view returns (uint) {
        if (authorities[_address].isValid) {
            return 1;
        } else {
            return 0;
        }
    }

}

Best Answer

Calling read functions is easy:

print('returned value: {}'.format(contractInstance.functions.getXyz().call()))

Make sure you install the latest Python and web3.py version 4

Related Topic