Lido 详解 #2:共识与提款

  • Oxorio
  • 更新于 2024-06-26 12:12
  • 阅读 1026

在这份指南中,深入探讨以太坊共识和 Lido 的提款模块的复杂性。了解从信标链到验证者生命周期的关键组件,以及它们如何塑造协议的安全性和功能

img

在这份指南中,深入探讨以太坊共识和 Lido 的提款模块的复杂性。了解从信标链到验证者生命周期的关键组件,以及它们如何塑造协议的安全性和功能

Lido 介绍

在本系列的上一篇文章中,我们探讨了 Lido 协议的发展历史,讨论了其架构的组成部分以及它们如何相互作用。

在本文的这一部分中,我们将深入探讨以太坊共识和 Lido 提款模块的结构。我们强烈建议先阅读本系列的第一部分,以捕捉所有细节。

如前所述,要深入了解 Lido 协议中的提款机制,首先需要探索以太坊本身的共识,特别是自从过渡到 2.0 版本以来带来的重大变化。

在深入探讨之前,我们需要先达成一些将在后文中使用的定义。我们的定义将有所概括,以保持一致的上下文。

  • 信标链 是以太坊生态系统区块链的更新版本的名称。它基于权益证明(PoS)范式,于 2020 年推出。该链负责协调和促进网络验证者和分片链之间的交互,分片链的支持将在未来的更新中添加。将生态系统的这一部分视为共识层的核心,我们稍后将定义这一概念。
  • 共识层 是负责验证区块、组织区块并确保验证者之间成功达成一致的层级。它类似于一本“规则书”,包含以太坊协议每个阶段操作的指令。
  • 执行层 是为应用程序和智能合约提供运行环境并处理应用程序内和应用程序之间交易的层级。在这一层,所有网络变化以交易的形式进行处理和积累。
  • 验证者(Validator) 是在特定节点的计算能力上运行的软件,包含一套规则和指令,规范所有节点的活动。每个验证者都是网络的全权参与者,有义务通过履行其职责来维护网络功能,我们稍后将讨论这些职责。
  • 区块提议者(Block Proposer) 是由信标链随机选择的验证者,负责创建并在网络中分发一个新的区块。
  • 区块见证者或证明者(Block Attester) 是在区块提议者创建的新区块在网络中分发之前,检查其内容正确性的验证者。

让我们首先通过共同的概念——网络层,来审视网络操作的核心规则。

网络层

首先,让我们确定网络层本质上是一组标准化以太坊网络节点之间通信过程的协议栈。它使它们能够按照适用于所有网络参与者的统一规则进行一对一一对多通信。每个节点都必须遵守这些规则,以确保其正确发送和接收有关网络状态的数据。

交互的一般方案

随着升级到版本 2,网络被分成了两个相互支持的链。一个处理交易(执行层——EL),而另一个(共识层——CL)管理以有向无环图形式构建主链,通常与区块链相关。为了保持这一结构的运作,其参与者使用网络客户端,而网络客户端又由验证者客户端执行客户端组成,每个客户端在各自的层级上运行。

让我们看看下面的图表,以了解 EL(eth1)和 CL(eth2)如何相互作用。 共识层与执行层交互

  • 图表显示,EL 首先从 CL 获取信标状态,然后将其与 EL 状态同步,使用 EVM 处理来自 TX Mempool 的交易,更新 EL 状态,并通过 RPC 将其发送到 CL。
  • 根据 EL 的结果,CL 创建新的信标区块,证明并最终确定它们,并将结果记录在主共识链中。
  • 两个层级都形成了一个点对点网络并并行运行。每个层级都有其客户端(分别为 EL 网络客户端和 CL 网络客户端),每种客户端都有其网络栈。

EL 网络客户端通过点对点网络分发交易区块数据,而 CL 网络客户端分发信标区块数据。这种数据分发仅在通过内置机制验证后才会在网络中开始,我们稍后将讨论这些机制。

如图所示,两个层级通过 RPC 请求交换信息。一个称为 Engine-API 的 API 定义了两个客户端之间传递的指令。重要的是要理解,共识客户端和执行客户端形成了一个统一的系统,始终并行运行,只是在每个网络层级执行不同的任务。

共识层

让我们退一步。为了验证、达成所有验证者一致并最终确定一个区块,执行层节点会累积来自网络交易的状态更新信息,直到达到区块的 gas 限制,然后将更新状态的信息传输到共识层。本质上,整个算法分为三个主要阶段,我们现在将进行探讨:

[I] 区块创建 [II] 区块见证和分发 [III] 区块最终确定

[I] 区块创建

网络随机选择一个 CL 客户端来处理、验证并在点对点网络中分发一个新区块。只有一个区块提议者,这导致验证者行为的两种可能情况:

[1] 当 CL 客户端是区块提议者时。 [2] 当 CL 客户端不是区块提议者(即是区块见证者)时。

这两种情况各有其任务,我们将从它们开始。首先,让我们考虑情况[1],即 CL 客户端是区块提议者。为了简化理解,让我们看看下面的图表:

img

你可能会问,“这个图表中到底发生了什么?”。它表示了点对点网络和区块提议者本身之间的交互算法,包括 6 个步骤:

  1. 使用RanDAO机制,该机制分配网络验证者的角色,我们将进一步讨论,选择一个区块提议者。
  2. 在 EL 层级,区块提议者被授予访问 EL 状态和 mempool 的权限,并调用“创建区块”方法。
  3. 区块提议者从 mempool 中提取所有“待处理”交易。
  4. 将这些交易应用于当前状态,得到一个新区块及其哈希。
  5. 通过共识层 P2P 分发新区块。
  6. 完成其生命周期。

[II] 区块见证和分发

好的,正如我们所见,选定的客户端已经成功地履行了其角色。但在此期间,其他没有成为区块提议者的共识客户端在做什么呢?他们正在重新检查区块提议者的工作,以尽量减少为整个网络批准虚假信息的风险。这个过程被称为区块见证。让我们看看下面的图表来更好地理解这一点。

img

基于图表,让我们检查一下区块见证者的流程

  1. 在区块提议者通过共识层 P2P 分发新区块后,作为区块见证者的验证者首先在其共识客户端层面进行接收到的数据的预验证。他们检查发送者地址的正确性和发送数据的结构,以确保其与元数据匹配。
  2. 然后,使用相同的 RPC 连接,预验证的区块被发送到执行客户端,在那里证明者重建交易哈希树以检查区块头,并验证交易本身。
  3. 如果一切顺利,区块见证者通过进一步通过点对点网络分发区块,有效地为其投票。如果 2/3 的验证者也这样做(= 达到超级多数),区块进入最终确定阶段。

如图所示,区块见证者的主要任务是独立重新检查和验证区块提议者的工作,防止恶意节点传播虚假信息(这个概念被称为拜占庭容错 )。

[III] 区块最终确定

区块最终确定是确保区块在任何情况下都不能被更改或从链中移除的过程。这对于经济安全至关重要,使网络参与者能够依赖严格准确的记录数据进行活动。最终确定的区块的确定性只有在超过 33%的总质押 ETH 被销毁的情况下才会被破坏,这种情况是不可能的。

然而,为了完全理解最终确定过程,我们将暂时将注意力从网络和共识层转移到探讨信标链和同步委员会的工作原理。之后,我们将回到区块最终确定的讨论。

信标链和同步委员会

现在我们了解了新区块的创建、验证和分发过程,以及每个网络层在这些过程中所扮演的角色,让我们看看作为共识层核心的信标链是如何运作的。

为了防止网络验证者串通并集体将不正确的区块包含在主链中,信标链采用了同步委员会——这是 Altair 硬分叉(于 2021 年 10 月 27 日激活)的“旗舰功能”。为了理解其重要性,让我们首先讨论信标链的架构。该网络的生命周期分为Epoch,其规则如下。

1 Epoch = 32 Slot = 32 * 12 sec = 6.4 min

每个 epoch,RanDAO 机制确保所有活跃的验证者均匀分布在各个 slot 中。

  • Epoch 是一个条件时间单位,在此期间以太坊协议完成其操作的完整周期。每个 epoch,协议处理来自交易的信息,形成一个新块,对其进行证明,并将其包含在主链中,从而确保 epoch 之间的连续性。
  • Slot 是将新块添加到信标链的机会窗口。每 12 秒,假设系统性能最佳,一个新块将被添加到链中。Slot 有点类似于区块时间,但如果验证者未能达成一致或交易处理不理想,slot 也可能是空的。
  • RanDAO 是一种生成伪随机输出的算法,负责在信标链中选择区块提议者(根据其余额值)和区块见证者(根据其在同步委员会中的分布)。所有参与者首先本地选择一个伪随机数,然后每个参与者发送其选择的数字的哈希值。随后,参与者依次揭示其选择的数字,并对揭示的数字执行 XOR 操作,该操作的结果成为协议的输出。

在 slots 内,区块见证者被分配到每个至少有 128 个验证者(最多 512 个)的委员会中。这些委员会被称为同步委员会,它们用于独立验证和确保整个网络状态的变化。使用这些委员会允许轻客户端跟踪信标区块头的链。此外,每个 slot 中的一个验证者被指定为区块提议者,正如我们之前讨论的那样。委员会内的所有验证者对区块进行证明,但严格在其分配的 slot 时间框架内。这个周期在每个 epoch 重复。下面你可以看到这个过程的图示。

img

好了,我们已经介绍了证明新区块的机制。但它们是如何最终确定的呢?让我们通过下面的图表来理解这一点,该图表说明了最终确定新区块的流程

img

如图所示,在正常的网络操作中,每个区块经过三个状态:

  1. 区块提议 | 当考虑中的区块的签名在 Epoch 0 期间被输入到信标链中时,分配此状态。在下一个 epoch,验证者必须为其投票。
  2. 区块见证(证明) | 如果在 Epoch 1 开始时,至少 2/3 的验证者为 Epoch 0 中提议的区块投票,则分配此状态。
  3. 区块最终确定 | 如果 Epoch 1 中提议的区块已达到证明状态,则在 Epoch 2 结束时,将 Epoch 0 中的区块分配为最终确定状态。

一旦区块成功证明并被赋予“最终确定”状态,Gasper 算法就会发挥作用,它是两个组件的组合:

  1. Casper-FFG | 友好的最终性gadget | 将区块更新为最终确定状态,以便新网络参与者可以确保他们正在同步唯一正确的链。
  2. LMD-GHOST | 分叉选择算法 | 使用累积的投票确保节点在区块链中发生分叉时可以轻松选择正确的选项。

我们已经了解了在整个共识层面上区块的处理、验证和最终确定。我们还了解了验证者之间的相互作用。但单个验证者的行为如何呢?它如何进行存款、激活和停用?如果不理解这些方面,我们就无法理解提款。让我们深入探讨一下。

以太坊中的验证者生命周期

为了回答关于验证者如何激活以及他们面临的风险的问题,我们需要研究他们的生命周期,并分析其在 Lido 协议背景下与提款的相互关联。让我们仔细看看他们的激活和停用过程。验证者活动的整个过程可以通过下图来说明。它展示了验证者地址(账户 1)的余额变化以及在验证者本地停用期间(账户 2)资金的分配方式。

在执行层面,大多数操作由存款合约管理,该合约是任何想要激活验证者的人的入口。存款合约接收用户资金,并向共识层发送存款收据和激活新验证者的请求。接下来是我们已经讨论过的内容。

在处理验证者的停用请求时,共识层会计算每个验证者的奖励和惩罚,然后将资金转移到指定地址(账户 2)。

img

如你所见,这个图的大部分内容我们已经很清楚了,只有新验证者从网络的激活和提款过程是盲点。让我们来解决这个问题。

以太坊网络验证者的生命周期分为 6 个主要步骤:

已存款

  • 在此阶段,验证者的存款金额是否足够以及验证者激活期是否尚未设定将被验证。
  • 成功验证后,验证者进入激活队列。

符合激活条件(待定)

  • 在激活之前,会检查验证者的激活权利是否在前一个Epoch中最终确定,并且验证者尚未被分配未来的激活Epoch。
  • 成功验证后,验证者将从队列中移除并分配一个未来的激活Epoch。

已激活

  • 当激活Epoch到来时,每个Epoch,验证者开始承担区块提议者或区块见证者的角色并履行分配的职责。此激活阶段有三种可能的结束场景:
  • [3.A] 如果验证者的行为损害了网络状态,其他验证者会对其进行削减,导致其被强制退出并延迟 36 天返还存款。
  • [3.B] 如果验证者频繁受到网络惩罚且其余额低于最低阈值,则会被强制退出。
  • [3.C] 如果验证者发起停用,在 2¹¹个Epoch(约 9 天)后,可以继续进行。

被削减并退出(已退出)

  • 如[3.A]所述,验证者会被延迟 36 天。
  • 削减 是销毁部分验证者的资金并将其从当前Epoch选择的活跃验证者集中移除。为了避免削减,区块提议者必须避免为一个插槽提议两个冲突的新区块版本,区块见证者必须避免签署两个冲突的证明。
  • 退出 只是将验证者从网络中停用并返还所有奖励。如果验证者违反了网络规则,在退出时会被削减。如果验证者行为诚实,则只会退出并返还奖励。

未削减并退出(已退出)

  • 在[3.B]和[3.C]的情况下,验证者等待约 27 天,然后获得“可提款”状态。

可提款

  • 在此阶段,验证者的存款可供提款,周期结束。

为了更直观地表示,我们建议你根据我们的解释研究下图:

img

在 Lido 协议的背景下,验证者扮演协议的“劳动力”角色,像公司里的普通员工一样产生收入,并在他们离开时,协议接收累积的工作成果,支付验证者的劳动报酬,并将赚取的资金重新分配用于其他目的:在我们的案例中,这包括偿还其他义务和创建新的“劳动力”。

现在,我们已经回顾并重复了深入了解提款过程技术细节所需的一切。

Lido 提款的具体情况

验证者的生命周期总是顺利进行吗?验证者在执行其活动时是否存在任何风险?这些风险是否会以任何方式影响 Lido 协议的运行?事情并不总是那么简单,让我们来探讨一下。

验证者风险

在与信标链交互的过程中,Lido 协议验证者面临某些风险:

双重最终性

  • 这是一个不太可能但严重的情况,其中两个分叉可以同时最终确定,导致链的永久分裂。理论上,这对于愿意冒险 34%总质押以太坊的恶意行为者是可能的。社区将被迫在链外协调行动并同意遵循哪条链,这需要社会层面的力量。

最终性延迟

  • 这种情况阻止网络最终确定链的某些部分。没有最终性,信任建立在以太坊上的金融应用程序将变得困难。最终性延迟攻击的目的是可能破坏以太坊,而不是直接获利,除非攻击者有一些战略性的空头头寸。

区块重组

  • 恶意重组可以保证某些区块的包含或排除,允许双重花费或通过 MEV 提取利润。
  • 重组还可以用于防止某些交易被包含在规范链中——一种审查形式。最极端的重组形式是“最终性逆转”,即之前已最终确定的区块被移除或替换。这只有在攻击者销毁超过 1/3 的总质押以太坊时才可能。

Lido 尽可能地解决这些风险,以确保从协议中提款的程序正确进行。但它究竟是如何做到的呢?让我们在下一节中探讨。

Lido 提款注意事项

几个关键解决方案负责风险管理:退出守护进程Lido 缓冲区Oracle 报告延迟。让我们分别检查这些。

使用退出守护进程

  • 该组件用于通知需要从现有退出请求中选择的 Lido 验证者的移除。其目的是通过智能合约事件保护和传播此类报告。
  • 退出守护进程有其自己的生命周期,不需要与 Lido 的一般 Oracle 报告协调。

使用 Lido 缓冲区

  • 协议努力以尽可能少的时间在缓冲区中存放以太坊,并且在激活队列中也尽可能少的时间。这一策略最大化了资本使用效率。
  • 缓冲区作为一个中介模块,积累来自用户存款、执行层奖励和提款金库资金的资金,然后用它们完成提款请求或在激活新的信标链验证者时重新质押。下图直观地描绘了这一过程。

img

  • 提款金库是接收资金的合约。
  • 执行层奖励是验证者参与证明和提议新网络区块的奖励。
  • 用户存款是直接从用户钱包发送到缓冲区的存款金额。

Oracle 报告延迟

  • 需要注意的是,只有当 Oracle 形成关于网络状态的新报告时,请求的履行才会发生。这种延迟是由于无法实时监控从共识层到协议层的更新。
  • 此外,Oracle 报告必须同时提供 beacon balancewithdrawals vault balance 的数据,以防止双重记账,因为 beacon balance 的数据无法直接从执行层访问。
  • 你可能还会问——“为什么提款请求不能立即执行?”。即时执行会使不法参与者能够避免因验证者被削减而导致的财务损失,从而对协议的资本效率产生负面影响。因此,协议首先支付验证者的罚款,将这些财务损失计入其余额,然后满足提款请求。这保持了高水平的资本效率。

Lido 提款场景

加速退出(通过协议缓冲区 - protocol buffer)

Lido 协议设计为在缓冲区中积累资金,同时一个链下 Oracle 决定它们在用户提款和创建新验证者过程之间的分配。

在加速退出的情况下,假设缓冲区中有足够的资金,协议可以加快返还存款的过程。

然而,如果缓冲区资金不足,则启动标准退出过程,这涉及从 Beacon Chain 提取验证者以确保有足够的资金。

标准退出(通过网络广播)

为此,协议根据预定顺序确定下一个退出的验证者,并通知相应的节点运营商这一决定。随后,确定验证者从 Beacon Chain 提款所需的时间以及用户在 stETH 代币中的份额将转换回 ETH 的赎回率。在这种情况下,用户面临的时间延迟从 6.5 到 50.5 小时不等,此外还有加速退出的时间。

为了做出这些决定,协议需要来自共识层的信息,这些信息无法直接从执行层获得。当前版本的协议依赖于一个 Oracle 委员会,该委员会为协议在执行层的操作提供这些缺失的信息,尽管这种解决方案存在与 MEV 攻击相关的问题。

实际上,Oracle 委员会的成员还负责信号通知下一个将退出的验证者。每 N 个 epoch,Oracle 参与者分析新出现的提款请求,使用 Lido DAO 批准并在 Oracle 代码中实现的算法计算下一个将被驱逐的验证者列表,并在 Oracle 智能合约中发布该列表。该算法必须处理验证者移除过程中的故障和延迟。

延迟退出(在 bunker 模式下)

在 bunker 模式下,提款请求被暂停,直到负面事件得到解决。

对于导致长时间停机的事件,影响数万到数十万验证者,预期延迟为 1 天,最大延迟为 7 天。

在大规模削减事件中,预期延迟为 18 天,最大延迟为 36 天。

影响提款完成时间的因素

  • 提款队列中的 stETH 数量
  • 验证者池的性能
  • Beacon Chain 中验证者退出队列的大小
  • 提款需求和供应的整体市场变化

我们还应该提到,stETH 是一种 rebase 代币,这意味着质押奖励会累积(减去 10% 的费用归 Lido),你的 stETH 余额会随着时间增加。

现在,最后一步是将所有三种场景整合成一个全面的图景——研究提款流程。

提款流程

让我们回顾一下,在本系列的第一篇文章中,我们定义了用户从协议中提款的简化算法。

这是你已经熟悉的描述 Lido 提款过程的图表。现在,我们将通过添加一系列技术细节来扩展对它的理解。

img

让我们看看从 Lido 提款的高级算法,考虑我们已经研究的材料。但首先,让我们分解一下提款基础设施包括什么。

*提款基础设施* — 在我们的图表中,这是负责正确处理提款请求的链下和链上组件的组合。它包括:*

提款队列

  • 该合约负责管理验证者退出队列。它在验证者退出前后保持其余额资金,然后将资金转移到提款金库。

Lido 缓冲区

  • 如前所述,该合约从两种类型的金库和用户存款中积累资金,然后在两个主要任务之间重新分配:覆盖提款请求的义务和通过存款合约激活新的 CL 验证者。
  • 在提款的背景下,重要的是要理解缓冲区在验证者退出最终确定之前持有已停用验证者的存款。

驱逐守护程序

  • 在提款的背景下,驱逐守护程序由节点运营商托管。它监控 LidoOracle 合约的事件日志,并在必要时将验证者停用请求的签名发送到共识节点。
  • 在接收到请求的签名后,共识节点停用它们,并通过共识层 P2P 分发关于验证者退出的消息。

验证者退出总线

  • 为了防止驱逐守护程序在每次迭代中需要停用每个验证者,设计了退出总线。
  • 它是所有已签名停用请求的编号列表,允许一次性退出所有必要的验证者。
  • 该组件还很方便,因为它允许驱逐守护程序轻松从一个地方获取其操作所需的所有信息。

驱逐 Oracle

  • 我们将在下一部分更详细地讨论 Oracle,但在提款过程中,驱逐 Oracle 负责收集和传播关于共识层 Lido 验证者的信息,基于此,驱逐守护程序决定下一个退出的验证者。
  • 更重要的是,该组件负责预测在最后一个验证者提款请求(协议已提交且无法取消)执行后可用的 ETH 数量。这对于使协议在当前需要的验证者数量退出是必要的,否则由于缓冲区中的闲置,资本将被低效使用。

提款金库

  • 让我们再重复一遍,所有验证者的存款在停用请求最终确定后从缓冲区发送到这里。

EL 奖励金库

  • Lido 协议验证者因参与证明和创建新区块而获得的奖励被送到这里。
  • 该金库的资金以及提款金库的资金用于覆盖提款请求的义务和激活新验证者。现在我们已经了解了提款算法所涉及的基础设施,让我们看看算法本身,考虑到本文这一部分的所有补充内容。
  1. 用户提交提款请求。铸造一个 ERC721 代币,确认持有者有权领取带有奖励的存款。它可以转移到任何地址(以及随之而来的领取重基 ETH 的权利)。领取资金后,NFT 代币被销毁。
  2. 在提款基础设施内,从所有提款请求中形成一个提款队列。
  3. 在提款基础设施内,退出守护程序根据余额选择下一个退出的验证者。
  4. 弹射 Oracle 检查协议运行的模式(turbo/bunker)。

如果协议处于 turbo 模式:

  • 使用协议缓冲区中的 ETH 执行请求。
  • 如果此金额不足以满足所有请求,弹射 Oracle 会根据未完成的存款提款请求列表注册验证者退出信标链。
  • 从信标链经典退出:Lido 发送退出消息,每个验证者收到一个退出Epoch,达到后,质押的资金进入提款库。
  • 资金返回合约后,为每个提款人计算奖励。
  • 弹射 Oracle 将新提款的信息传递给会计 Oracle,然后会计 Oracle 为整个协议发布更新报告。
  • 资金可供最终提款。

如果协议处于 bunker 模式:

  • 提款请求被推迟,直到触发“bunker 模式”的事件的后果得到解决。

提款执行流程

在图表上,你可以看到我们讨论的整个过程,但在合约交互的层面上。箭头上方是调用的方法和输入。

img

Bunker 流程

我们将在系列的第 3 部分中更详细地讨论 bunker 模式,在 oracles 的上下文中。然而,目前重要的是要知道 bunker 模式是由于 Lido 验证者中不健康数量的削减而引起的协议状态。bunker 模式由 oracle 委员会批准,并暂时暂停从协议中提款的能力,直到该模式被停用。

img

完整流程

在这里,你可以看到包含所有模块和组件的协议完整流程。与我们的图表的主要区别在于,我们将流程分为 3 个大组,以简化对整个图景的理解。

img

结论

因此,我们已经分部分检查了这个庞大的系统,并将其组装成一个统一的图景。现在让我们得出结论!

我们已经了解了以太坊 2.0 的工作原理,分析了验证者在与其交互时的风险,了解了 Lido 如何处理这些风险,以及从协议中提款的整个过程是如何进行的。

然而,为了有一个完整的图景,我们仍然需要深入了解 Lido 如何获得资金以完成这些请求,以及由链上和链下组件组成的 Oracle 基础设施是如何参与的。

在下一篇文章中,我们将更多地讨论这两个方面:

[1] 存款与质押 [2] Oracle 基础设施

参考文献

I. 提款

[link] — “以太坊上的 Lido 提款”

[link] — “提款:自动化 Lido 验证者退出”

[link] — “提款:关于验证者退出顺序”

[link] — “Lido 提款设计与 Bunker 模式”

[link] — “启用提款的协议会计”

[link] — “启用提款的 Lido 协议。审计范围”

[link] — “以太坊上的 Lido - 提款 ”

[link] — “使用 Lido 协议的以太坊提款速度有多快”

II. 共识

[link] — “ETH2 之书 - 共识”

[link] — “以太坊信标链解释”

[link] — “Gasper”

点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Oxorio
Oxorio
专注于智能合约、zk-SNARK解决方案和咨询的区块链安全公司