ethers.js icon indicating copy to clipboard operation
ethers.js copied to clipboard

JsonRpcApiProvider: sendImmediate()

Open adraffy opened this issue 1 year ago • 2 comments

Describe the Feature

Some RPCs cannot be batched. It would be nice to be able to force a send() to only contain one request instead of using batchMaxSize = 1 on the provider.


Maybe something like sendImmediate() (same arguments as send()) except just calls _send() directly and increases #nextId

This can be accomplished currently using _send() and constructing a JsonRpcPayload and handling the JsonRpcResult | JsonRpcError result but the #nextId doesn't get updated.

Code Example

await provider.sendImmediate('eth_getProof', ...)

// alternative idea #1
provider.nextId(); // expose the incrementer

// alternative idea #2:
await provider.flushDrain(); // clears timer and flushes payloads
await provider.send('eth_getProof', ...)
await provider.flushDrain(); // not guaranteed that payloads.length = 1

Possible implementation:

export async function sendImmediate(
  provider: ethers.JsonRpcApiProvider,
  method: string,
  params: any[]
): Promise<any> {
  const payload: ethers.JsonRpcPayload = {
    method,
    params,
    id: 1, // meh
    jsonrpc: '2.0',
  };
  return provider._send(payload).then(([res]) => {
    if ('result' in res) {
      return res.result;
    } else {
      throw provider.getRpcError(payload, res);
    }
  });
}

adraffy avatar Aug 25 '24 23:08 adraffy

Why RPC methods cannot be batched? Is that specified in the documentation?

The goal of a JsonRpcProvider is to abstract much of this away from developers and keep a nice clean interface, but requiring a bunch of low-level calls would make the interface very difficult to describe.

My current suggestion for this would be to keep two instances of providers; one that is used normally and one that is "batchless" by setting maxBatchCount to 1, since it seems it is only commands sent using the lower-level .send?

ricmoo avatar Sep 16 '24 16:09 ricmoo

For example, Linea does not handle batched eth_getProof, even [{...}] (a single request in a batch)


When I control the stack, I agree, I can just use 2 providers and this is a non-issue, but almost all tooling/middleware/etc, I don't have that option, I'm given a provider that someone else created, then what? I can't modify batchMaxSize and I can't access #nextId, hence this issue.

Now that I look a bit closer, ~~I think I could switch on the type of provider and create a temporary batchMaxSize = 1 provider by cloning _getConnection() if the provider is HTTP.~~ I guess if it's HTTP I can just use id = 1 and otherwise batching isn't supported. I think that's what my code essentially does.


Isn't the above function general and abstract? It simply gives the developer the ability to bypass the send queue. The code above is valid implementation except it cannot update the internal private state. Here is a more complete solution that triggers all of the appropriate events.

adraffy avatar Sep 16 '24 19:09 adraffy