Skip to content

Request send() hangs if response can not be parsed when using WebSocketService #2120

Closed
@Shohou

Description

no result from send()

I'm trying to load blocks in batch from infura.io and sometimes due to some issue in infura I'm getting incorrect result. Instead of block object it could be just string, or id could be some uuid instead of long. If this situation occurs exception is logged in console and application just stops because send() method never exits.

As I see it, WebSocketService.processBatchRequestReply receives response, removes it from map, so timeout never happens, parsing throws one of Jackson exceptions and WebSocketService doesn't catch it. It is logged in WebSocketClient.onMessage(), but request never gets any response.

ERROR [org.web3j.protocol.websocket.WebSocketClient] (WebSocketConnectReadThread-186) Failed to process message '...' from server wss://holesky.infura.io/ws/v3/<mykey>: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `org.web3j.protocol.core.methods.response.EthBlock$Block` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('0x0000000000000000000000000000000000000000000000000000000000002460') at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: org.web3j.protocol.core.methods.response.EthBlock["result"])
        at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
        at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1754)
        at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1379)
        at com.fasterxml.jackson.databind.deser.std.StdDeserializer._deserializeFromString(StdDeserializer.java:311)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1592)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:197)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:187)
        at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342)
        at com.fasterxml.jackson.databind.ObjectReader._bind(ObjectReader.java:2099)
        at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1249)
        at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1267)
        at org.web3j.protocol.core.methods.response.EthBlock$ResponseDeserialiser.deserialize(EthBlock.java:1001)
        at org.web3j.protocol.core.methods.response.EthBlock$ResponseDeserialiser.deserialize(EthBlock.java:992)
        at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:310)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177)
        at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342)
        at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:4893)
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3036)
        at com.fasterxml.jackson.databind.ObjectMapper.treeToValue(ObjectMapper.java:3500)
        at org.web3j.protocol.websocket.WebSocketService.processBatchRequestReply(WebSocketService.java:319)
        at org.web3j.protocol.websocket.WebSocketService.onWebSocketMessage(WebSocketService.java:281)
        at org.web3j.protocol.websocket.WebSocketService$1.onMessage(WebSocketService.java:155)
        at org.web3j.protocol.websocket.WebSocketClient.lambda$onMessage$0(WebSocketClient.java:52)
        at java.base/java.util.Optional.ifPresent(Optional.java:178)
        at org.web3j.protocol.websocket.WebSocketClient.onMessage(WebSocketClient.java:49)
        at org.java_websocket.client.WebSocketClient.onWebsocketMessage(WebSocketClient.java:644)
        at org.java_websocket.drafts.Draft_6455.processFrameText(Draft_6455.java:986)
        at org.java_websocket.drafts.Draft_6455.processFrame(Draft_6455.java:910)
        at org.java_websocket.WebSocketImpl.decodeFrames(WebSocketImpl.java:402)
        at org.java_websocket.WebSocketImpl.decode(WebSocketImpl.java:234)
        at org.java_websocket.client.WebSocketClient.run(WebSocketClient.java:527)
        at java.base/java.lang.Thread.run(Thread.java:1583)

Exception can be different depending on what faulty response I get

Steps To Reproduce

    web3jService = new WebSocketService(network.getRpcUrl(), false);
    web3jService.connect();
    web3j = Web3j.build(web3jService);

    BatchRequest batchRequest = web3j.newBatch();
    for (long i = startBlockNum; i < endBlockNum; i++) {
        batchRequest.add(web3j.ethGetBlockByNumber(DefaultBlockParameter.valueOf(BigInteger.valueOf(i)), true));
    }

    //this call never exists if response is incorrect
    BatchResponse batchResponse = batchRequest.send();

Expected behavior

IOException or RuntimeException should be thrown or in case of sendAsync future should complete exceptionally.

Actual behavior

send method never exits

Environment

  • Web3j version - 4.12.2
  • Jackson databind - 2.18.1, but I think could be any

Additional context

I think problem and its possible solution is clear, but ask me if anything more information is needed

Metadata

Assignees

No one assigned

    Labels

    bugA bug in behaviour or functionality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions