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

Got response from unknown request #566

Open
MrCasCode opened this issue Nov 5, 2021 · 8 comments
Open

Got response from unknown request #566

MrCasCode opened this issue Nov 5, 2021 · 8 comments

Comments

@MrCasCode
Copy link

MrCasCode commented Nov 5, 2021

Hi, I'm trying to subscribe to events in a contract:

   let ws = web3::transports::WebSocket::new("mynode").await?;
   let web3 = web3::Web3::new(ws);
 
   let contract = Contract::from_json(
        web3.eth(),
        hex!("4e68Ccd3E89f51C3074ca5072bbAC773960dFa36").into(),
        include_bytes!("../contracts/uniswap_v3_pool.json"),
    )?;

   filter = FilterBuilder::default()
        .address(vec![contract.address()])
        .from_block(BlockNumber::Latest)
        .build();

    let mut evsub = web3ws.eth_subscribe().subscribe_logs(filter).await?;

    println!("Sub id {:?}", evsub.id());

    loop {
        let r = evsub.next().await;
        match r {
            Some(ev) => println!("{:?}", ev?),
            None => ()
        }
    }

And everytime an event happens (checking on etherscan) I receive a response from unknown request

[2021-11-05T08:14:40Z DEBUG web3::transports::ws] [1] Calling: {"jsonrpc":"2.0","method":"eth_subscribe","params":["logs",{"address":"0x4e68ccd3e89f51c3074ca5072bbac773960dfa36","fromBlock":"latest"}],"id":1}
Sub id SubscriptionId("0x10ff0e1299f046edb86e5c774741102fa889ab7e15dd")
[2021-11-05T08:14:58Z WARN  web3::transports::ws] Got response for unknown request (id: 0)
[2021-11-05T08:15:32Z WARN  web3::transports::ws] Got response for unknown request (id: 0)

The same is happening when I try to run the examples subscribing to new heads.

I know my node connection is working because I can fetch past events and I receive the correct data

let logs = web3ws.eth().logs(filter).await?;
    println!("Got {:?} logs", logs.len());

    for l in logs {
        let event: (Address, Address, U256, U256, U256, u128, i32) = Detokenize::from_tokens(
            contract
            .abi()
            .event("Swap")?
            .parse_log(ethabi::RawLog {topics: l.topics.clone(), data: l.data.0.clone()})?
            .params
            .into_iter()
            .map(|x| x.value)
            .collect::<Vec<_>>())?;

            println!("event {:?} ", event);
    }
event (0xe592427a0aece92de3edee1f18e0157c05861564, 0xe592427a0aece92de3edee1f18e0157c05861564, 320000000000000000, 115792089237316195423570985008687907853269984665640564039457584007911902018681, 4914607075100445747082281, 10392763788743888306, -193768) 

Any idea of what could be happening?

Thanks.

@MrCasCode
Copy link
Author

MrCasCode commented Nov 5, 2021

I can see in ws.rs:259:

response = Error("data did not match any variant of untagged enum Response", line: 0, column: 0)

And when I decode the raw bytes that I received I get what I was subscribed to:

{"JSONRPC":"2.0", "method":"eth_subscription", "params": {"subscription":"0x10ff0e12f0313a0de8d542b1ae656ac614d451f456e2","result":{"removed":false,"logIndex":"0x156","transactionIndex":"0xe4","transactionHash":"0x901a47aa4f7dcc6f9f390171d40979856f0ea55a4e65455a824dc984cb237bf4","blockHash":"0xfeb0a0f446350eb6205c7a0f72168a108b9a953135cdabdca4e676c05362fdff","blockNumber":"0xcedd7b","address":"0x4e68ccd3e89f51c3074ca5072bbac773960dfa36","data":"0xffffffffffffffffffffffffffffffffffffffffffffffffdfcd05c3906437360000000000000000000000000000000000000000000000000000000272a39ffe0000000000000000000000000000000000000000000467a87e34429148e9ee3e000000000000000000000000000000000000000000000000912ef544f1c55642fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd115d","topics":["0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67","0x000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564","0x000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564"]}}} 

It seems the same as #563 but in my case I'm using Infura.

How could I bypass this limitation? Which eth node provider should I use to get this running?

@MrCasCode
Copy link
Author

Still digging trying to understand why the websocket response fails to be decoded whereas the http works.

Received http:

{
    "jsonrpc": "2.0",
    "id": 93,
    "result": [
        {
            "address": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
            "blockHash": "0x88cd879b0d64a1a182148424e033498c2fef0903133dca66364fdf5fa41202b8",
            "blockNumber": "0xcef012",
            "data": "0x0000000000000000000000000000000000000000000000000000000242760b91ffffffffffffffffffffffffffffffffffffffffffffffffe1f87f7a58f76dfd0000000000000000000000000000000000003a579793d13959af617c84b3aaa400000000000000000000000000000000000000000000000109efec8446be0a78000000000000000000000000000000000000000000000000000000000002eeef",
            "logIndex": "0x20",
            "removed": false,
            "topics": [
                "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
                "0x000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564",
                "0x000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564"
            ],
            "transactionHash": "0xca67ee912802c0eb4fadfa98cdde71915c821e43f6ce11a98e2a33e1d3524afe",
            "transactionIndex": "0x11"
        }
    ]
}

Websocket

{
    "JSONRPC": "2.0",
    "method": "eth_subscription",
    "params": {
        "subscription": "0x10ff0e12f0313a0de8d542b1ae656ac614d451f456e2",
        "result": {
            "removed": false,
            "logIndex": "0x156",
            "transactionIndex": "0xe4",
            "transactionHash": "0x901a47aa4f7dcc6f9f390171d40979856f0ea55a4e65455a824dc984cb237bf4",
            "blockHash": "0xfeb0a0f446350eb6205c7a0f72168a108b9a953135cdabdca4e676c05362fdff",
            "blockNumber": "0xcedd7b",
            "address": "0x4e68ccd3e89f51c3074ca5072bbac773960dfa36",
            "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffdfcd05c3906437360000000000000000000000000000000000000000000000000000000272a39ffe0000000000000000000000000000000000000000000467a87e34429148e9ee3e000000000000000000000000000000000000000000000000912ef544f1c55642fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd115d",
            "topics": [
                "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
                "0x000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564",
                "0x000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564"
            ]
        }
    }
}

@MrCasCode
Copy link
Author

Okay.. it turns out it was the capital case on "JSONRPC": "2.0"

I've created a PR on the jsonrpc library paritytech/jsonrpc#649

@marmistrz-stc
Copy link
Contributor

I'm also getting this warning while using ganache with instamine support. What's worse, the application hangs after this warning. To reproduce, run ganache as

ganache-cli -v --miner.legacyInstamine

And run the following code as RUST_LOG=debug cargo run

use web3::types::TransactionRequest;

#[tokio::main]
async fn main() {
    env_logger::init();
    let node = "ws://127.0.0.1:8545";
    let ws = web3::transports::WebSocket::new(node)
        .await
        .expect("building ws");
    let web3 = web3::Web3::new(ws);
    let accounts = web3.eth().accounts().await.expect("accounts");

    let src_account = accounts[0];
    let target_account = accounts[1];

    let src_balance = web3
        .eth()
        .balance(src_account, None)
        .await
        .expect("balance");

    let eth_tx_value = src_balance * 10;
    let tx = TransactionRequest::builder()
        .from(src_account)
        .to(target_account)
        .value(eth_tx_value)
        .build();

    web3.eth()
        .send_transaction(tx)
        .await
        .expect_err("sending ETH should fail because exceeds balance");
}

Then the log is:

[2021-11-30T11:29:51Z DEBUG web3::transports::ws] [1] Calling: {"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}
[2021-11-30T11:29:51Z DEBUG web3::transports::ws] [2] Calling: {"jsonrpc":"2.0","method":"eth_getBalance","params":["0x6ef26921b8d91a9da113ad9b2ac4218ccd70aa7b","latest"],"id":2}
[2021-11-30T11:29:51Z DEBUG web3::transports::ws] [3] Calling: {"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from":"0x6ef26921b8d91a9da113ad9b2ac4218ccd70aa7b","to":"0xc8ba9e7a1ceeaf4410dcfcf979e9f392c7063cd7","value":"0x21e19e0c9bab2400000"}],"id":3}
[2021-11-30T11:29:51Z WARN  web3::transports::ws] Got response for unknown request (id: 0)

and the application just hangs indefinitely.

@marmistrz
Copy link
Contributor

I managed to debug the issue. With ganache v7.0.3 (@ganache/cli: 0.1.4, @ganache/core: 0.1.4), the JSON-RPC respose is received as follows:

"{\"id\":3,\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"insufficient funds for gas * price + value\",\"stack\":\"Error: insufficient funds for gas * price + value\\n    at TransactionPool.prepareTransaction (/usr/lib/node_modules/ganache/dist/node/1.js:2:131154)\",\"code\":-32003}}"

Note that the case of jsonrpc is correct. This response is rejected due to the fact that error is supposed to contain message, code and possibly data. The field stack is unknown and thus rejected by serde because of deny_unknown_fields: https://github.com/paritytech/jsonrpc/blob/0a2702595b8831a9a30dec7dc476157c648c361c/core/src/types/error.rs#L86

This means that, if the response fails to be parsed due to messages which do not conform to the JSON-RPC specification, we can't obtain the subscription id and pass any kind of message through the channel and the application will freeze indefinitely. This is unacceptable behavior.

IMO, as long as the message request contains id (and perhaps jsonrpc) and the parsing fails, we should use the id to propagate the parsing error to the caller.

@tomusdrw you were the one to introduce strict parsing in jsonrpc-core in this PR. How would you like to solve it? One option would be to drop deny_unknown_fields for Error, another would be to provide a very barebones type for fallback parsing and use it if all else fails.

I also think that assuming id == 0 for a request which failed to parse is not quite right:

None => rpc::Id::Num(0),

@marmistrz
Copy link
Contributor

I implemented a workaround in #639.

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

No branches or pull requests

4 participants
@marmistrz @MrCasCode @marmistrz-stc and others