Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-7774: Web3 URL 中 ERC-5219 模式下的缓存失效

引入一种新的 HTTP 缓存控制方法,使用 EVM 事件进行失效处理

Authors Nicolas Deschildre (@nand2), Sam Wilson (@SamWilsn)
Created 2024-09-20
Discussion Link https://ethereum-magicians.org/t/erc-7774-cache-invalidation-in-erc-5219-mode-web3-url/21255
Requires EIP-5219, EIP-6944

摘要

ERC-6860 web3:// 标准的上下文中,此 ERC 扩展了 ERC-6944 解析模式。它引入了解决限制的机制,这些限制阻止了标准 RFC 9111 HTTP 缓存的使用。

动机

调用以太坊 RPC 提供商代价高昂——无论是对于本地节点的 CPU 而言,还是对于付费外部 RPC 提供商而言。此外,外部 RPC 提供商受到速率限制,这在加载 web3:// URL 时可能会迅速导致中断。

因此,实现缓存机制以尽可能减少 RPC 调用是有意义的。由于 web3:// 旨在尽可能接近 HTTP,因此利用标准 RFC 9111 HTTP 缓存是自然的选择。在 ERC-6944 解析模式中,智能合约已经可以返回标准的 HTTP 缓存头,如 Cache-ControlETag

然而,由于 ERC-6944 解析模式不将请求 HTTP 标头转发到智能合约,因此智能合约无法处理 If-None-MatchIf-Modified-Since 缓存验证标头。 因此,它们仅限于使用 Cache-control: max-age=XX 机制,这会导致每个缓存验证请求都触发 RPC 调用,从而重新生成完整响应。

此 ERC 提出了一种解决方案,通过允许网站通过智能合约事件广播缓存失效来绕过此限制。

此外,即使智能合约可以读取请求 HTTP 标头,使用智能合约事件也更有效,因为它将缓存失效逻辑移到了合约外部。

我们将此功能添加到 ERC-6944 解析模式中,因为它可以在不更改接口的情况下添加。 未来允许请求 HTTP 标头的解析模式也可以实现此 ERC。

规范

此标准为请求响应的 Cache-Control 标头引入了 evm-events 缓存指令,作为 RFC 9111 第 5.2.3 节中定义的扩展指令。

ERC-6944 解析模式网站想要对请求使用基于事件的缓存时,它必须:

  • 在响应的 Cache-Control 标头中包含 evm-events 指令。
  • 按照传统的 RFC 9111 HTTP 缓存,在响应中包含 ETag 和/或 Cache-Control 标头。
  • 当响应的输出发生变化并且它认为需要清除缓存时,在智能合约中为该路径发出缓存失效事件(如下定义)。

evm-events 缓存指令的值是可选的,可用于指定侦听其他智能合约上的其他事件,和/或其他路径。 ABNF 符号中的缓存指令值语法为:

cache-directive-value = [ address-path-absolute *( " " address-path-absolute ) ]
address-path-absolute = [ address ] path-absolute [ "?" query ]
address               = "0x" 20( HEXDIG HEXDIG )
path-absolute         = <path-absolute, see RFC 3986, Section 3.3>
query                 = <query, see RFC 3986, Section 3.4>

示例

  • Cache-control: evm-events:当响应请求的合约为已服务的页面路径发出缓存清除事件时,返回此指令的页面的缓存将被清除。
  • Cache-control: evm-events="/path/path2":与第一个示例的行为相同,但此外,当响应请求的合约为路径 /path/path2 发出缓存清除事件时,返回此指令的页面的缓存将被清除。
  • Cache-control: evm-events="0xe4ba0e245436b737468c206ab5c8f4950597ab7f/path/path2":与第一个示例的行为相同,但此外,当合约 0xe4ba0e245436b737468c206ab5c8f4950597ab7f 为路径 /path/path2 发出缓存清除事件时,返回此指令的页面的缓存将被清除。
  • Cache-control: evm-events="0xe4ba0e245436b737468c206ab5c8f4950597ab7f":与第一个示例的行为相同,但此外,当合约 0xe4ba0e245436b737468c206ab5c8f4950597ab7f 为已服务的页面路径发出缓存清除事件时,返回此指令的页面的缓存将被清除。
  • Cache-control: evm-events="/path/path2 /path/path3":与第一个示例的行为相同,但此外,当响应请求的合约为路径 /path/path2/path/path3 发出缓存清除事件时,返回此指令的页面的缓存将被清除。

缓存失效事件

该事件定义为:

event ClearPathCache(string[] paths);

此事件清除 paths 数组的缓存。 每个 path 引用 ERC-6860 中 ABNF 定义的 pathQuery 部分。

  • path 必须不能以 / 结尾,除非整个路径是根路径,即 /
  • 如果两个 paths 具有相同的 ERC-5219 资源条目并且它们的参数值匹配(无论顺序如何),则认为它们是相同的。

示例

  • /test?a=1&b=2/test?b=2&a=1 被认为是相同的。

通配符用法

paths 可能包含 * 通配符,规则如下:

  1. 资源条目中的通配符
    • 通配符 (*) 可以在 ERC-5219 资源条目中单独使用。
    • 通配符不能与同一条目中的其他字符组合使用; 如果是,则将忽略 path
    • 通配符至少需要匹配一个字符。

    示例

    • /* 将匹配 /test,但不匹配 /test/abc,也不匹配 /
    • /test/* 将匹配 /test/abc,但不匹配 /test//test/abc/def
    • /*/abc 将匹配 /test/abc,但不匹配 //abc
    • /t*t 无效,因此将忽略 path
  2. 参数值中的通配符
    • 通配符可以单独用作参数值。
    • 通配符不能与参数值中的其他字符组合使用,否则将忽略 path
    • 参数值中的通配符至少需要匹配一个字符。

    示例

    • /abc?a=* 将匹配 /abc?a=zz,但不匹配 /abc?a=/abc?a=zz&b=cc
    • /abc?a=*&b=* 将匹配 /abc?a=1&b=2/abc?b=2&a=1
    • /abc?a=z* 无效,因此将忽略 path
  3. 特殊情况:全局通配符
    • 仅包含 *path 将匹配智能合约中的每个路径。

通配符有意限制于这些简单情况,以方便高效的路径查找实现。

缓存行为

web3:// 客户端的缓存失效状态

对于每个链和智能合约,web3:// 客户端可以处于以下两种缓存失效状态之一:

  1. 侦听事件web3:// 客户端必须侦听前面定义的缓存失效事件,并应尽可能接近实时。

  2. 不侦听事件: 这是未实现此 ERC 时的默认状态。 在这种状态下,web3:// 客户端会忽略所有 HTTP 缓存验证请求(例如,If-None-MatchIf-Modified-Since 请求标头)。

web3:// 客户端可以随时在这些状态之间切换,并且可以实现启发式方法,通过根据需要切换状态来优化 RPC 提供商的使用。

缓存键值映射

web3:// 客户端维护用于缓存的键值映射,每当它从“侦听事件”过渡到“不侦听事件”时,必须清除该映射。 该映射的结构如下:

mapping(
  (<链 ID>, <合约地址>, <ERC-6860 pathQuery>) 
  => 
  (<上次修改日期>, <ETag>)
)

必要时,可以将其他元素包含在映射键中。 例如,ERC-7618 要求在映射键中包含 Accept-Encoding 请求标头。

处理“侦听事件”状态下的请求

当在“侦听事件”状态下收到请求时:

  1. 如果不存在映射条目
    • web3:// 客户端查询智能合约。
    • 如果响应在 Cache-Control 标头中包含 evm-events 指令和一个 ETag,则使用 ETag 创建一个映射条目。
    • 如果响应在 Cache-Control 标头中包含 evm-events 指令和 max-age=XX 指令,则使用“上次修改日期”创建一个映射条目,该日期按以下优先级顺序确定:
      • Last-Modified 标头(如果存在)。
      • Date 标头(如果存在)。
      • 否则,为查询智能合约的区块日期。
    • 如果响应同时包含 ETagCache-Control: evm-events max-age=XX 指令,则会创建一个包含 ETag 和“上次修改日期”的单个映射条目。
  2. 如果存在映射条目
    • 如果请求包含有效的 If-None-Match 标头:
      • 如果映射中的 ETagIf-None-Match 值匹配,则 web3:// 客户端会立即返回 304 Not Modified 响应。
      • 如果 ETag 不匹配,则客户端会查询智能合约,删除映射条目,并像不存在映射条目一样处理请求。
    • 如果请求包含有效的 If-Modified-Since 标头:
      • 如果映射中的“上次修改日期”早于 If-Modified-Since 日期,则客户端会立即返回 304 Not Modified 响应。
      • 否则,客户端会查询智能合约,删除映射条目,并像不存在映射条目一样处理请求。
    • 如果请求既不包含 If-None-Match 标头,也不包含 If-Modified-Since 标头(或者它们无效):
      • 客户端会查询智能合约,删除映射条目,并像不存在映射条目一样处理请求。

通过区块链事件进行缓存失效

在“侦听事件”状态下,web3:// 客户端侦听区块链中上一节中定义的缓存失效事件。 对于每个路径匹配,它都会删除相应的映射条目。

理由

为了尽可能接近标准 HTTP,我们重用了 HTTP 缓存机制标头。

使用 evm-events 指令是必要的,以避免网站使用传统的 RFC 9111 HTTP 缓存标头,但合约未能通过不发出事件来实现此 ERC 的情况。 在这种情况下,实现此 ERC 的 web3:// 客户端将无限期地为该网站提供过时的内容。

安全考虑

在用户交易发出缓存清除事件与 web3:// 客户端选取和处理该事件之间的延迟期间,将提供过时的内容。

对于每个缓存的页面,网站必须正确实现缓存失效事件; 否则,将无限期地提供过时的内容。

如果发生链重组,web3:// 客户端必须回滚其缓存状态,否则将提供已回滚的内容,直到发生下一次缓存清除事件。

版权

根据 CC0 放弃版权和相关权利。

Citation

Please cite this document as:

Nicolas Deschildre (@nand2), Sam Wilson (@SamWilsn), "ERC-7774: Web3 URL 中 ERC-5219 模式下的缓存失效 [DRAFT]," Ethereum Improvement Proposals, no. 7774, September 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7774.