tomusdrw / rust-web3

Ethereum JSON-RPC multi-transport client. Rust implementation of web3 library. ENS address: rust-web3.eth
MIT License
1.45k stars 466 forks source link

Got response from unknown request #566

Open MrCasCode opened 2 years ago

MrCasCode commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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

I've created a PR on the jsonrpc library https://github.com/paritytech/jsonrpc/pull/649

marmistrz-stc commented 2 years ago

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 commented 2 years ago

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: https://github.com/tomusdrw/rust-web3/blob/0a32ab5a0ca0a8943157174c702069b22f166f08/src/transports/ws.rs#L295

marmistrz commented 2 years ago

I implemented a workaround in #639.