21个重大版本发布

0.64.1 2024年7月22日
0.63.0 2024年4月17日
0.62.0 2024年2月22日
0.55.0 2023年12月12日
0.39.0 2023年3月23日

#1132 in 神奇豆子

Download history 151/week @ 2024-04-14 8/week @ 2024-04-21 1/week @ 2024-04-28 15/week @ 2024-05-19 3/week @ 2024-05-26 14/week @ 2024-06-02 8/week @ 2024-06-09 2/week @ 2024-06-16 113/week @ 2024-06-23 70/week @ 2024-06-30 2/week @ 2024-07-07 127/week @ 2024-07-21 376/week @ 2024-07-28

506 每月下载量
用于 3 个crate(2个直接使用)

AGPL-3.0-only

1.5MB
30K SLoC

AIR

概述

该crate定义了旨在执行控制Fluence网络执行流的脚本的AIR解释器的核心。从高层次的角度来看,解释器可以被视为一个状态转换函数,它接受两个状态,将它们合并,然后产生一个新的状态。

解释器接口

该解释器只有一个导出函数,名为 invoke,没有导入函数。导出函数的签名如下

pub fn executed_air(
    /// AIR script to execute.
    air: String,
    
    /// Previous data that should be equal to the last returned by the interpreter. 
    prev_data: Vec<u8>,
    
    /// So-called current data that was sent with a particle from the interpreter on some other peer.
    data: Vec<u8>,
    
    /// Running parameters that includes different settings.
    params: RunParameters,
    
    /// Results of calling services.
    call_results: Vec<u8>,
) -> InterpreterOutcome {...}

pub struct InterpreterOutcome {
    /// A return code, where 0 means success.
    pub ret_code: i32,

    /// Contains error message if ret_code != 0.
    pub error_message: String,

    /// Contains so-called new data that should be preserved in an executor of this interpreter
    /// regardless of ret_code value.
    pub data: Vec<u8>,

    /// Public keys of peers that should receive data.
    pub next_peer_pks: Vec<String>,

    /// Collected parameters of all met call instructions that could be executed on a current peer.
    pub call_requests: Vec<u8>,
}

如前文所述,invoke 接受两个状态(prev_datacurrent_data),并返回一个新的状态(new_data)。此外,它接受要执行的AIR脚本、一些运行参数(如 init_peer_idcurrent_peer_id)以及 call_results,即调用服务的返回结果。因此,它提供了上文代码片段中描述的 IntepreterOutcome 结构。

主要特性

首先让我们从数据的角度来考虑解释器,因为之前、当前和结果数据是参数和结果中最有趣的部分。假设 X 是数据可能具有的所有可能值的集合,我们将导出函数 executed_air 表示为 f: X * X -> X。可以看出,在数据方面,f 形成了一个 magma。

更进一步,f 是一个幂等的非交换幺半群,因为

  1. f 是结合的:forall a, b, c from X: f(f(a,b), c) = f(a, f(b,c))
  2. f 有一个中性元素:exists e, forall a from X: f(e, a) = f(a, e) = a,其中 e 是一个带有空轨迹的数据
  3. f 是一个非交换函数:exists a, b from X: f(a, b) != f(b, a)
  4. X 可以从构成 ExecutedState 枚举(这就是为什么这个幺半群是自由的)的四个基元素中构建
  5. f 满足这些幂等性质
    1. forall x from X: f(x,x) =x
    2. forall a,b from X: f(a,b) =c, f(c,b) =c, f(c,a) =c

与解释器的交互

解释器允许对等方(节点或浏览器)异步调用服务,通过从执行期间可能调用的每个 call 指令中收集所有参数和其他必要的内容,并在 InterpreterOutcome 中返回它们。然后,主机可以在任何时间执行它们,并通过提供执行服务结果作为 call_results 参数回调解释器。

与解释器交互的方案应如下所示

  1. 对于从网络接收到的每个新的 current_data,主机应使用相应的 prev_datacurrent_data 以及空的 call_results 调用解释器。prev_data 这里是解释器返回的最后 new_data

  2. 获得解释器的结果后,在 InterpreterOutcome 中可能会有非空的 next_peer_ids 和非空的 call_requests

    1. re next_peer_pks:它是对等方的责任决定是否在每次解释器调用后发送粒子,或者在整个粒子执行后(即完成所有 call_requests 后)发送粒子。
    2. re call_requestscall_requests是一个HashMap<u32, CallRequestParams>,主机需要保持u32和调用CallRequestParams之间的对应关系,因为它们将在第3步返回结果时使用。
  3. 如果第2步中call_requests不为空,对等方必须再次调用解释器,并带有提供的调用结果(HashMap<u32, CallServiceResult>),遵循以下规则:

  • 这里不应该提供current_data(实际上,由于f是幂等的,它可以提供,但这是不必要的,并且会稍微减慢解释器执行的速度)。
  • 在处理下一个粒子之前,没有必要提供call_results,实际上,对等方可以在任何时候提供它。
  • 在每个执行步骤之后,对等方必须保留new_data。这是非常重要的,因为f不是可交换的,并且解释器在data中保存额外的信息,期望在下一次启动时看到结果数据作为prev_data返回。

    然后应该从第2点开始重复此流程。
  1. 如果call_requests为空,整个执行完成,必须保留new_data,并且必须像往常一样向所有new_peer_pks发送粒子。

交互示例可以在测试中找到。

依赖关系

~14–27MB
~421K SLoC