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

Add ERC: Cache invalidation in ERC-5219 mode Web3 URL #652

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
121 changes: 121 additions & 0 deletions ERCS/erc-7761.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
eip: 7761
nand2 marked this conversation as resolved.
Show resolved Hide resolved
title: Cache invalidation in ERC-5219 mode Web3 URL
description: In ERC-5219 resolve mode, add mechanisms to alleviate limitations to the use of RFC 9111 HTTP caching
author: Nicolas Deschildre (@nand2)
discussions-to: https://ethereum-magicians.org/t/eip-4804-web3-url-to-evm-call-message-translation/8300
nand2 marked this conversation as resolved.
Show resolved Hide resolved
status: Draft
type: Standards Track
category: ERC
created: 2024-09-20
requires: 5219, 6944
---

## Abstract

In the context of the [ERC-6860](./eip-6860.md) `web3://` standard, this ERC extends the [ERC-6944](./eip-6944.md) resolve mode: This standard add mechanisms to alleviate limitations to the use of standard [RFC 9111](https://www.rfc-editor.org/rfc/rfc9111) HTTP caching.

## Motivation

Calls to an Ethereum RPC provider are costly: CPU-wise for local nodes, and money-wise for paid external RPC providers. Additionally, external RPC providers are rate-limited, and can quickly lead to the breaking of the loading of `web3://` URLs.

Thus, it makes sense to use a caching mechanism to limit RPC calls when possible.

In the [ERC-6944](./eip-6944.md) resolve mode, smart contracts can already reply with standard [RFC 9111](https://www.rfc-editor.org/rfc/rfc9111) HTTP caching headers, such as `Cache-Control`, `ETag`.

Unfortunately, due to the impossibility of reading request HTTP headers, they cannot act on the `If-None-Match` and `If-Modified-Since` cache validation headers. Thus they are limited to the `Cache-control: max-age=XX` mechanism, and each cache validation request ends up with RPC calls regenerating the whole response.

This ERC defines a mechanism to bypass this limitation by having websites broadcast cache invalidations with smart contract events.

Besides, even if the smart contract could read request HTTP headers, using smart contract events is more efficient as it will eliminate a significant proportion of RPC calls.

## Specification

This standard introduces the `evm-events` cache directive for the `Cache-Control` header, as an extension directive as defined in section 5.2.3 of [RFC 9111](https://www.rfc-editor.org/rfc/rfc9111).

When a [ERC-6944](./eip-6944.md) resolve mode website wants to use event-based caching for a request, it MUST :

- Include the `evm-events` directive in the `Cache-Control` header in the request response
- Include the `ETag` and/or `Cache-Control` headers in the request response, as in traditional [RFC 9111](https://www.rfc-editor.org/rfc/rfc9111) HTTP caching.
- Ensure that it emits a cache invalidation event (as defined in a later section) in the smart contract when it determines that the changes made to the body returned by the path warrants a cache clear.

The use of the `evm-events` directive is necessary to avoid a situation where a website use traditional [RFC 9111](https://www.rfc-editor.org/rfc/rfc9111) HTTP caching headers, but does not implement this ERC (by not emitting the events) : `web3://` clients implementing this ERC would end up serving stale content for this website indefinitely.


### Caching behavior

The `web3://` client will have 2 possible states per chain and per smart contract regarding cache invalidation :

- `Listening events` : The `web3://` client MUST listen for cache invalidation events (defined in next section). It MUST try to stay as close to real time as possible.
- `Not Listening events` : The opposite of the above state, and the default constant state when this ERC is not implemented: the `web3://` client ignore all HTTP caching validation requests (the `If-None-Match`, `If-Modified-Since` request headers).

The `web3://` client can switch between each state anytime, and MAY implement state-switching heuristics to optimize the RPC providers usage.

The `web3://` client will host a caching key-value mapping, which MUST be cleared on any `Listening events` to `Not Listening events` state change :

```
mapping(
(<chain id>, <contract address>, <ERC-6860 pathQuery>, <hash of the headers advertised in the Vary HTTP header>))
=>
(<last modified date>, <ETag>)
)
```

In `Listening events` state, when a incoming request arrives :

- If a mapping entry does not exist : the `web3://` client query the smart contract.
- If the request response contains the `evm-events` cache directive in the `Cache-Control` header, and an `Etag` HTTP header, a mapping entry is created with the `Etag`.
- If the request response contains the `evm-events` cache directive in the `Cache-Control` header, and contains a `max-age` directive in a `Cache-Control` HTTP header, a mapping entry is created with the `last modified date` being :
- The content of the `Last-Modified` HTTP header, if present
- The content of the `Date` HTTP header, if present
- The date of the block at which the smart contract was queried otherwise
- If the request response match both cases above, then a single mapping entry is created with both the `Etag` and the `last modified date` fields filled.
- If a mapping entry already exists :
- If the request contains a valid `If-None-Match` HTTP header:
- If the mapping entry has the same `Etag` as the one provided by `If-None-Match`, then the `web3://` client returns a HTTP code `304 Not Modified` response right away.
- Otherwise if the mapping entry has a non-empty different `ETag`, the `web3://` client query the smart contract. The mapping entry is deleted, and the answer is processed as if there had been no mapping entry initially.
- Otherwise the `Etag` of the mapping entry is empty (and the `last modified date` is not). The `web3://` client query the smart contract, and the answer is processed as if there had been no mapping entry initially, except that the mapping entry is updated instead of created.
- If the request contains a valid `If-Modified-Since` HTTP header:
- If the mapping entry has a `last modified date`, and is before the date provided by `If-Modified-Since`, then the `web3://` client returns a HTTP code `304 Not Modified` response right away.
- Otherwise if the mapping entry has a `last modified date` which is after, the `web3://` client query the smart contract. The mapping entry is deleted, and the answer is processed as if there had been no mapping entry initially.
- Otherwise the `last modified date` field of the mapping entry is empty (and the `Etag` is not). The `web3://` client query the smart contract, and the answer is processed as if there had been no mapping entry initially, except that the mapping entry is updated instead of created.
- If the request does not have a `If-None-Match` or `If-Modified-Since` HTTP header (or are invalid): the `web3://` client query the smart contract, and the answer is processed as if there had been no mapping entry initially, except that the mapping entry is updated instead of created.

In `Listening events` state, the `web3://` client listens the blockchain for the cache invalidation events which are defined in the next section. For each path match, it will delete their corresponding mapping entry.

### Cache invalidation event

The event definition is :

```
event ClearPathCache(string[] paths);
```

A single event can thus clear cache for an array of `path`. A `path` contains the `pathQuery` part as defined in the ABNF definition of [ERC-6860](./eip-6860.md). They MAY contains `*` wildcards :

- A wildcard can be used in a [ERC-5219](./eip-5219.md) resource entry. A wildcard CANNOT be used with other characters, or the `path` will be ignored. A wildcard require at least one character to match. Examples :
- `/*` will match `/test` but not `/test/abc`
- `/test/*` will match `/test/abc` but will not match `/test/` and not match `/test/abc/def`
- `/*/abc` will match `/test/abc`, but will not match `//abc`
- `/t*t/` is invalid, the path is ignored.
- A wildcard can be used in a [ERC-5219](./eip-5219.md) param value. A wildcard CANNOT be used with other characters, or it will the `path` be ignored. A wildcard require at least one character to match. Examples :
- `/abc?a=*` will match `/abc?a=zz` but will not match `/abc?a=` and not match `/abc?a=zz&b=cc`
- `/abc?a=*&b=*` will match `/abc?a=1&b=2` and `/abc?b=2&a=1`
- `/abc?a=z*` is invalid, the path is ignored.
- Special case: Global wildcard : A `path` containing a single `*` match every path of the smart contract.

Wildcards are limited to these simple cases to simplify fast path lookup implementations.

## Rationale

We add this feature to the [ERC-6944](./eip-6944.md) resolve mode because it can be added without changes the interface.

To stay as close as possible to standard HTTP, we reuse the HTTP caching mechanism headers.

## Security Considerations

No security considerations were found.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
Loading