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

Generated wrapper around struct containing a address[] member can't be instantiated #2001

Open
mcornaton opened this issue Jan 16, 2024 · 0 comments
Labels
bug A bug in behaviour or functionality

Comments

@mcornaton
Copy link

mcornaton commented Jan 16, 2024

Steps To Reproduce

  1. Write a struct containing an array of addresses and a function to access such an object:
struct Task
{
  TaskStatusEnum status;
  bytes32   dealid;
  uint256   idx;
  uint256   timeref;
  uint256   contributionDeadline;
  uint256   revealDeadline;
  uint256   finalDeadline;
  bytes32   consensusValue;
  uint256   revealCounter;
  uint256   winnerCounter;
  address[] contributors;     <-----Note the `address[]` type
  bytes32   resultDigest;
  bytes     results;
  uint256   resultsTimestamp;
  bytes     resultsCallback; // Expansion - result separation
}

function viewTask(bytes32 _taskid)
external view override returns (IexecLibCore_v5.Task memory)
{
  return m_tasks[_taskid];
}
  1. Generate the Java wrapper using Web3j. It should give the following constructor and function:
public Task(Uint8 status,
            Bytes32 dealid,
            Uint256 idx,
            Uint256 timeref,
            Uint256 contributionDeadline,
            Uint256 revealDeadline,
            Uint256 finalDeadline,
            Bytes32 consensusValue,
            Uint256 revealCounter,
            Uint256 winnerCounter,
            DynamicArray<Address> contributors,     <---- Note the parameter declaration
            Bytes32 resultDigest,
            DynamicBytes results,
            Uint256 resultsTimestamp,
            DynamicBytes resultsCallback) {
    super(status, dealid, idx, timeref, contributionDeadline, revealDeadline, finalDeadline, consensusValue, revealCounter, winnerCounter, contributors, resultDigest, results, resultsTimestamp, resultsCallback);
    this.status = status.getValue();
    this.dealid = dealid.getValue();
    this.idx = idx.getValue();
    this.timeref = timeref.getValue();
    this.contributionDeadline = contributionDeadline.getValue();
    this.revealDeadline = revealDeadline.getValue();
    this.finalDeadline = finalDeadline.getValue();
    this.consensusValue = consensusValue.getValue();
    this.revealCounter = revealCounter.getValue();
    this.winnerCounter = winnerCounter.getValue();
    this.contributors = contributors.getValue().stream().map(v -> v.getValue()).collect(Collectors.toList());
    this.resultDigest = resultDigest.getValue();
    this.results = results.getValue();
    this.resultsTimestamp = resultsTimestamp.getValue();
    this.resultsCallback = resultsCallback.getValue();
}

public RemoteFunctionCall<Task> viewTask(byte[] param0) {
    final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(FUNC_VIEWTASK,
            Arrays.<Type>asList(new org.web3j.abi.datatypes.generated.Bytes32(param0)),
            Arrays.<TypeReference<?>>asList(new TypeReference<Task>() {
            }));
    return executeRemoteCallSingleValueReturn(function, Task.class);
}
  1. Call the method to retrieve an instance of this object... 💥
2024-01-16 09:50:55.626 ERROR 1 --- [o-13300-exec-10] c.i.c.p.chain.IexecHubAbstractService    : Failed to get ChainTask [chainTaskId:0x1f3e39ef6942fe708d8030e39c0bf737761f6f2c1064666f5f91dfea4f3fa9d5]

java.lang.NullPointerException: Cannot invoke "java.lang.reflect.Type.getTypeName()" because "type" is null
	at org.web3j.abi.Utils.getTypeName(Utils.java:286)
	at org.web3j.abi.TypeReference.getClassType(TypeReference.java:94)
	at org.web3j.abi.Utils.getParameterizedTypeFromArray(Utils.java:182)
	at org.web3j.abi.TypeDecoder.decodeArrayElements(TypeDecoder.java:638)
	at org.web3j.abi.TypeDecoder.decodeDynamicArray(TypeDecoder.java:442)
	at org.web3j.abi.TypeDecoder.decodeDynamicParameterFromStruct(TypeDecoder.java:569)
	at org.web3j.abi.TypeDecoder.decodeDynamicStructElements(TypeDecoder.java:522)
	at org.web3j.abi.TypeDecoder.decodeDynamicStruct(TypeDecoder.java:458)
	at org.web3j.abi.DefaultFunctionReturnDecoder.build(DefaultFunctionReturnDecoder.java:94)
	at org.web3j.abi.DefaultFunctionReturnDecoder.decodeFunctionResult(DefaultFunctionReturnDecoder.java:52)
	at org.web3j.abi.FunctionReturnDecoder.decode(FunctionReturnDecoder.java:57)
	at org.web3j.tx.Contract.executeCall(Contract.java:313)
	at org.web3j.tx.Contract.executeCallSingleValueReturn(Contract.java:324)
	at org.web3j.tx.Contract.executeCallSingleValueReturn(Contract.java:335)
	at org.web3j.tx.Contract.lambda$executeRemoteCallSingleValueReturn$1(Contract.java:457)
	at org.web3j.protocol.core.RemoteCall.send(RemoteCall.java:42)
	at com.iexec.commons.poco.chain.IexecHubAbstractService.getChainTask(IexecHubAbstractService.java:802)
	at com.iexec.commons.poco.chain.IexecHubAbstractService.lambda$repeatGetChainTask$7(IexecHubAbstractService.java:791)
	at net.jodah.failsafe.Functions.lambda$get$0(Functions.java:48)
	at net.jodah.failsafe.RetryPolicyExecutor.lambda$supply$0(RetryPolicyExecutor.java:66)
	at net.jodah.failsafe.Execution.executeSync(Execution.java:128)
	at net.jodah.failsafe.FailsafeExecutor.call(FailsafeExecutor.java:379)
	at net.jodah.failsafe.FailsafeExecutor.get(FailsafeExecutor.java:68)
	at com.iexec.commons.poco.utils.Retryer.repeatCall(Retryer.java:63)
	at com.iexec.commons.poco.chain.IexecHubAbstractService.repeatGetChainTask(IexecHubAbstractService.java:791)
	at com.iexec.commons.poco.chain.IexecHubAbstractService.repeatGetTaskDescriptionFromChain(IexecHubAbstractService.java:1069)
	at com.iexec.commons.poco.chain.IexecHubAbstractService.getTaskDescriptionFromChain(IexecHubAbstractService.java:1059)
	at com.iexec.commons.poco.chain.IexecHubAbstractService.isTeeTask(IexecHubAbstractService.java:1093)
	at com.iexec.sms.authorization.AuthorizationService.isAuthorizedOnExecutionWithDetailedIssue(AuthorizationService.java:64)
	at com.iexec.sms.tee.TeeController.generateTeeSession(TeeController.java:143)
	[... Java / Spring internal calls ...]

Expected behavior

The generated code should be able to build an instance without encountering a NPE.

Actual behavior

Web3j can't find the type for the contributors parameter. It knows the parameter is some sort of dynamic array, but can't find out the generics type because of type erasure. It misses some sort of information to find out the expect type of each contributor is String.

As far as I understand Web3j code, the constructor misses the @Parameterized annotation. Its signature should be the following:

public Task(Uint8 status,
            Bytes32 dealid,
            Uint256 idx,
            Uint256 timeref,
            Uint256 contributionDeadline,
            Uint256 revealDeadline,
            Uint256 finalDeadline,
            Bytes32 consensusValue,
            Uint256 revealCounter,
            Uint256 winnerCounter,
            @Parameterized(type = String.class) DynamicArray<Address> contributors,   <---- Note the newly-added annotation
            Bytes32 resultDigest,
            DynamicBytes results,
            Uint256 resultsTimestamp,
            DynamicBytes resultsCallback)

In fact, if I manually add this annotation to the generated wrappers, then everything works fine! So I guess this annotation should be added during the wrappers generation.

Environment

  • Web3j version: 4.9.7
  • Java 11

Additional context

References:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A bug in behaviour or functionality
Projects
None yet
Development

No branches or pull requests

1 participant