4

Here is my contract:

pragma solidity ^0.4.17;
contract SignVerify {
    function recoverAddr(bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) returns (address) {
        return ecrecover(msgHash, v, r, s);
    }

    function isSigned(address _addr, bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) returns (bool) {
        return ecrecover(msgHash, v, r, s) == _addr;
    }
}

The corresponding java code generated by web3j (version 3.2.0) contains the following generated method for isSigned.

public RemoteCall<TransactionReceipt> isSigned(String _addr, byte[] msgHash, BigInteger v, byte[] r, byte[] s) {
        Function function = new Function(
                "isSigned", 
                Arrays.<Type>asList(new org.web3j.abi.datatypes.Address(_addr), 
                new org.web3j.abi.datatypes.generated.Bytes32(msgHash), 
                new org.web3j.abi.datatypes.generated.Uint8(v), 
                new org.web3j.abi.datatypes.generated.Bytes32(r), 
                new org.web3j.abi.datatypes.generated.Bytes32(s)), 
                Collections.<TypeReference<?>>emptyList());
        return executeRemoteCallTransaction(function);
    }

Notice the Collections.<TypeReference<?>>emptyList()? that is the output return types. Why is it an empty list?
In the well known Greeter example which returns a string that line becomes Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}).

The web3j script to generate java code is pretty straight forward:

web3j solidity generate \
        ${dirName}/build/${fileName}.bin \
        ${dirName}/build/${fileName}.abi \
        -p org.web3j.sample.contracts.generated \
        -o ../../java/ > /dev/null

I tried using --javaTypes and --solidtyTypes with no change to generated code. My suspicion now is that web3j only generates return types for constant functions on the contract. Let me know if I can somehow get the return type(the boolean) from the TransactionReceipt returned by the generated java method.

1 Answer 1

3

Smart contracts have two main types of functions:

- Transactions: transaction on the Blockchain can change the state of the Blockchain by modifying a smart contract storage for instance. By design, a transaction is asynchronous because, it needs to be broadcasted on the network, picked up by a miner before being added to a block. This process can take a long time, that's why a transaction function can't return a value even if declared in the definition.

- Calls: Function that doesn't change the global state of the blockchain. A call is however synchronous and return a value.


In Web3j, in order to distinguish transaction functions from call functions, you need to use the keyword view (or constant for solidity 0.4.x) in your definition.

pragma solidity ^0.4.17;
contract SignVerify {
    function recoverAddr(bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) constant returns (address) {
        return ecrecover(msgHash, v, r, s);
    }

    function isSigned(address _addr, bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) constant returns (bool) {
        return ecrecover(msgHash, v, r, s) == _addr;
    }
}

Given this, Web3j Smart Contract wrapper will know it is a call function that can return a value instead of transaction function.

    public RemoteCall<Boolean> isSigned(String _addr, byte[] msgHash, BigInteger v, byte[] r, byte[] s) {
        final Function function = new Function(FUNC_ISSIGNED, 
                Arrays.<Type>asList(new org.web3j.abi.datatypes.Address(_addr), 
                new org.web3j.abi.datatypes.generated.Bytes32(msgHash), 
                new org.web3j.abi.datatypes.generated.Uint8(v), 
                new org.web3j.abi.datatypes.generated.Bytes32(r), 
                new org.web3j.abi.datatypes.generated.Bytes32(s)), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Bool>() {}));
        return executeRemoteCallSingleValueReturn(function, Boolean.class);
    }

    public RemoteCall<String> recoverAddr(byte[] msgHash, BigInteger v, byte[] r, byte[] s) {
        final Function function = new Function(FUNC_RECOVERADDR, 
                Arrays.<Type>asList(new org.web3j.abi.datatypes.generated.Bytes32(msgHash), 
                new org.web3j.abi.datatypes.generated.Uint8(v), 
                new org.web3j.abi.datatypes.generated.Bytes32(r), 
                new org.web3j.abi.datatypes.generated.Bytes32(s)), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}));
        return executeRemoteCallSingleValueReturn(function, String.class);
    }
1
  • 1
    And what do you do if you need to edit the state. i.e. it's not a view function - but you still want the result
    – Tobi
    Feb 22, 2022 at 17:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.