本次审计涵盖了op-node, op-batcher, op-proposer, op-chain-ops和op-service组件的三个pull request,共发现12个问题,包括1个中等严重性问题,以及多个低严重性和提示信息,重点关注MantleDA集成和代码质量提升,建议加强QA流程和测试覆盖。
TypeLayer 2TimelineFrom 2024-02-12To 2024-02-28LanguagesGoTotal Issues12 (3 resolved)Critical Severity Issues0 (0 resolved)High Severity Issues0 (0 resolved)Medium Severity Issues1 (1 resolved)Low Severity Issues9 (0 resolved)Notes & Additional Information2 (2 resolved)
我们审计了三个拉取请求,范围包括 op-node
、op-batcher
、op-proposer
、op-chain-ops
和 op-service
组件:
拉取请求 #72,从基础提交 68f2533 到头部提交 bb0ff70。范围包括以下文件:
mantle-v2
├── op-batcher
│ ├── batcher
│ │ ├── batch_submitter.go
│ │ ├── channel_manager.go
│ │ ├── config.go
│ │ ├── driver_da.go
│ │ └── driver.go
│ ├── common
│ │ ├── types.go
│ │ └── utils.go
│ ├── flags
│ │ └── flags.go
│ └── metrics
│ ├── metrics.go
│ └── noop.go
├── op-chain-ops
│ ├── cmd
│ │ ├── check-migration
│ │ │ └── main.go
│ │ ├── op-migrate
│ │ │ └── main.go
│ │ ├── rollover
│ │ │ └── main.go
│ │ └── withdrawals
│ │ └── main.go
│ ├── crossdomain
│ │ ├── encoding.go
│ │ ├── hashing.go
│ │ ├── legacy_abi.go
│ │ ├── legacy_withdrawal.go
│ │ ├── message.go
│ │ ├── migrate.go
│ │ ├── params.go
│ │ ├── withdrawal.go
│ │ ├── withdrawals.go
│ │ └── witness.go
│ ├── eof
│ │ └── eof_crawler.go
│ ├── ether
│ │ ├── addresses.go
│ │ ├── cli.go
│ │ ├── migrate.go
│ │ └── storage.go
│ ├── genesis
│ │ ├── check.go
│ │ ├── config.go
│ │ ├── db_migration.go
│ │ ├── genesis.go
│ │ ├── layer_one.go
│ │ ├── layer_two.go
│ │ └── setters.go
│ ├── immutables
│ │ └── immutables.go
│ └── util
│ └── util.go
├── op-node
│ ├── chaincfg
│ │ └── chains.go
│ ├── cmd
│ │ └── genesis
│ │ └── cmd.go
│ ├── eth
│ │ ├── sync_status.go
│ │ └── types.go
│ ├── flags
│ │ └── flags.go
│ ├── metrics
│ │ └── metrics.go
│ ├── node
│ │ ├── config.go
│ │ └── node.go
│ ├── rollup
│ │ ├── da
│ │ │ └── datastore.go
│ │ ├── derive
│ │ │ ├── attributes.go
│ │ │ ├── calldata_source.go
│ │ │ ├── channel_bank.go
│ │ │ ├── channel_in_reader.go
│ │ │ ├── deposit_log.go
│ │ │ ├── engine_consolidate.go
│ │ │ ├── engine_queue.go
│ │ │ ├── error.go
│ │ │ ├── frame.go
│ │ │ ├── l1_block_info.go
│ │ │ ├── l1_retrieval.go
│ │ │ ├── l2block_util.go
│ │ │ ├── payload_util.go
│ │ │ ├── pipeline.go
│ │ │ └── system_config.go
│ │ ├── driver
│ │ │ ├── driver.go
│ │ │ └── state.go
│ │ ├── sync
│ │ │ ├── config.go
│ │ │ └── start.go
│ │ └── types.go
│ ├── service.go
│ ├── service_mantle.go
│ ├── sources
│ │ └── sync_client.go
│ └── withdrawals
│ └── utils.go
└── op-service
├── crypto
│ └── signature.go
└── txmgr
└── cli.go
拉取请求 #89,从基础提交 5e3886c 到头部提交 76959dd。范围包括以下文件:
mantle-v2
└── op-node
└── rollup
└── derive
├── deposit_log.go
└── l1_block_info.go
拉取请求 #98,从基础提交 0f0861b 到头部提交 365f02a。范围包括以下文件:
mantle-v2
└── op-chain-ops
├── genesis
│ └── config.go
└── immutables
└── immutables.go
Mantle V2 是一种以太坊二层(L2)扩展解决方案,它使用欺诈证明而不是有效性证明来保障安全。 该协议旨在提供低交易费用和高吞吐量,同时保持完全的 EVM 兼容性。 Mantle V2 构建于以太坊之上,使用 OP Stack,因此与 Optimism 有许多相似之处。 op-node
、op-batcher
和 op-proposer
组件共同构成共识层,该共识层保持链的运行并将所有其他一层和二层组件粘合在一起(尽管不存在以太坊理解的共识)。 将执行层 op-geth
添加到此集合中,就构成了 Mantle 网络。
op-node
组件负责派生二层区块链,这意味着它监听特定的一层事件和二层交易,并通过不断将此数据分组到批次中并将其传递到执行客户端以生成二层块来保持链的运行。 反过来,op-batcher
组件监听 op-node
以获取新的批次,将这些批次分组到通道中,压缩它们,将它们拆分为帧,并将帧发布到数据可用性层。
op-proposer
组件监听 op-node
以获取所谓的二层输出根,这些输出根是Merkle根。 然后将这些根发布到一层,以便一层上的智能合约可以接收来自二层的消息。 这包括 ERC-20 代币桥接以及通用消息传递。 op-chain-ops
组件是一种工具,有助于链的管理。 op-service
组件包含代码库其他部分使用的通用实用程序。
下面介绍按拉取请求和组件分组的范围内组件的变更摘要。
op-node
SystemConfig
合约中设置,然后作为每个 L2 块的第一个交易的一部分以及其他 SystemConfig
参数传递到执行层。requestsChannelBufferSize
常数从 128 增加到 1024,并且更改了处理相应通道的逻辑。unsafeL2PayloadsChannelBufferSize
常数从 10 增加到 4096,并且更改了处理相应通道的逻辑。op-batcher
op-proposer
op-chain-ops
GasPriceOracle
合约的支持。op-service
op-service
组件的更新包括支持以太坊操作中的 Google Cloud Platform (GCP) 的密钥管理服务 (KMS)。 如果期望使用 Cloud HSM,则引入了新的配置参数以简化流程。op-node
op-batcher、op-proposer、op-chain-ops 和 op-service
op-chain-ops
L1_MNT_ADDRESS
常数。op-node、op-batcher、op-proposer 和 op-service
在此次参与中,MantleDA 被视为一个黑盒,因为我们没有获得对系统文档、测试或开发实例的访问权限。 同样,我们也假设范围内代码正确使用 MantleDA。
话虽如此,MantleDA 是一项新兴技术,因此出现错误的几率更高。 从 MantleDA 中断或故障中恢复的当前方法是停止排序器,在配置文件中将数据可用性切换到以太坊 calldata,然后再次启动排序器。 这意味着没有自动回退机制,并且如果发生此类中断,Mantle 区块链将会失去活性,直到使用新配置重新启动排序器。
op-batcher
组件使用私钥与 MantleDA 合约交互,该合约定义了应使用哪些 MantleDA blob 来派生二层链。
OP-Node 的 RetrievalFramesFromDa
函数实现了从 Mantle DA 检索帧的逻辑。 它需要一个 dataStoreId
值,该值经过检查以验证它是否等于或小于 0。 由于 calldata_source
使用dataStoreId
减 1 调用 RetrievalFramesFromDa
,因此无法尝试使用等于 1 的 dataStoreId
从 Mantle DA 检索数据。
考虑删除 RetrievalFramesFromDa
函数中的检查以允许处理值为 0 的 dataStoreId
。 此外,由于 dataStoreId
的类型为 uint32
,因此不能小于 0,因此该检查变得不必要。
更新: 在拉取请求 #117 中已解决。
RequestL2Range
不会返回错误如果通道已满RequestL2Range
函数对一系列 L2 块进行排队,并且如果通道已满则提前返回。 但是,在这种情况下,它不会返回错误,这意味着将处理部分数据。
考虑在通道已满的情况下返回错误,以便调用者了解情况。
更新: 已确认,未解决。 Mantle 团队表示:
不是有效的问题。
OP-Chain-Ops 的 ReadWitnessData
函数利用 bufio
的 NewReader
迭代文件并检索所有条目。 为了读取每一行,该函数采用 ReadString
,该函数读取直到遇到新行。 但是,这种方法存在一个问题 - 如果文件的最后一行缺少新行字符(文本文件 witness.txt
就是这种情况),则读取器将触发 EOF
错误, 导致提前跳出循环,未能读取最后一行。
考虑重新设计函数逻辑,以便即使最后一行没有以新行结尾,也可以正确读取最后一行。
更新: 已确认,未解决。 Mantle 团队表示:
已确认,仅用于升级,不会修复。
OP-Chains-Ops 的 NewWithdrawal
函数返回一个填充了值的 Withdrawal
结构体。 类型为 hexutil.Bytes
的 Data
字段被赋值为类型为 []byte
的 data
。 但是,赋值的值应首先使用 hexutil.Bytes
函数转换为正确的类型。
考虑将 data
参数转换为 hexutil.Bytes
类型。
更新: 未解决。 Mantle 团队表示:
不是有效的问题。
测试套件没有彻底覆盖提议的更改。 此外,有多个测试失败,使得难以确认实现的正确性。 以下组件需要额外的测试:
考虑审查上述组件的测试套件以提高代码质量。
更新: 未解决。
类型为 big.Int
的 BaseFee
参数检查是否为 nil
。 但是,big.Int
可以是负数,这对于 BaseFee
来说没有意义,因为它应该始终为正数。
考虑检查 BaseFee
参数是否为 nil
以及是否为正数,就像其他 big.Int
参数一样(例如,链 ID 经过验证是否大于 0 且不等于 0)。
更新: 已确认,将解决。
启动 OP-Batcher 后,状态已清除,但 Mantle DA 状态未清除。
考虑调用 clearMantleDAStatus
函数来清除 Mantle DA 状态。
更新: 已确认,未解决。
使用 sleep 等待 0.1 ms
以使 sequencerCh
和 stepReqCh
准备就绪。 虽然这可能会缓解测试环境中的问题,但它在生产环境中的行为可能会有所不同,在生产环境中,负载可能会有所不同,因此 sleep 时间可能无法提供所需的效果。
考虑重构代码以避免使用 sleep,而是使用更可靠的机制来同步通道。
更新: 未解决。 Mantle 团队表示:
不是有效的问题。
已实现的到 Mantle DA 的连接缺少定义的超时选项。 当服务器接受连接但未能响应调用时,这可能会导致问题。 存在以下到 Mantle DA 的连接:
getFramesByDataStoreId
中到 Mantle DA 的连接getFramesFromIndexerByDataStoreId
中到 Mantle DA Indexer 的连接callEncode
中到 Mantle DA Disperser 的连接考虑将超时机制添加到以上列出的连接。
更新: 已确认,将解决。
已实现的到 Mantle DA 的连接是未加密的。 在生产环境中,通常建议加密连接。 存在以下到 Mantle DA 的未加密连接:
getFramesByDataStoreId
中到 Mantle DA 的连接getFramesFromIndexerByDataStoreId
中到 Mantle DA Indexer 的连接callEncode
中到 Mantle DA Disperser 的连接考虑改用加密连接。
更新: 已确认,将解决。
在整个代码库中,发现了几个排版错误:
TxConfirmDataSubmiited
应为 TxConfirmDataSubmitted
。openend
应为 opened
。注释
应为 L1_MANTLE_TOKEN
,而不是 L1_MANTLE_TOEKN
。考虑解决上述排版错误。
更新: 在拉取请求 #124 中已解决。
在整个代码库中,发现了几个冗余和不清晰的代码实例:
datastore.go
中定义的 NewMantleDataStore
函数始终将 error
作为 nil
返回。 因此,没有必要返回它并稍后检查它。NewMantleDataStoreConfig
函数返回一个配置和一个错误。 但是,错误始终为 nil
,这使得返回错误变得不必要。MockDataStoreConfig
变量未在任何地方使用,应将其删除。marshalDepositVersion1
函数未在任何地方使用,可以将其删除。getFramesByDataStoreId
函数中,从回复中检索数据两次。 考虑调用 GetData
一次,然后在 log.Debug
和 return 语句中使用它。getFramesFromIndexerByDataStoreId
函数中,从回复中检索数据两次。 考虑调用 GetData
一次,然后在 log.Debug
和 return 语句中使用它。if
语句 检查 BaseFee
是否不等于 0
。 考虑将第二个 if
语句移动到第一个 if
语句块中,并删除不必要的检查。ds.cfg.MantleDaSwitch
if
语句 使用仅具有 true 和 false 分支的 if
语句可能会更容易阅读,其中 true 分支包含用于处理 MantleDA 的代码,而 else
分支包含用于以太坊 calldata
的代码。MNTValue
和 ETHValue
。 正确的编码以 MNTValue
参数开始,后跟 ETHValue
参数。 但是,在多个位置,结构的初始化顺序相反。 虽然这不会引起问题,因为使用了参数名称,但它确实会阻碍可读性。 考虑在 Decode
和 WithdrawalTransaction
函数中更改 MNTValue
和 ETHValue
参数的顺序。更新: 在拉取请求 #125 中已解决。
此次审计发现了一个中等严重性的问题,以及其他几个较低严重性的问题。 我们提供了各种建议来增强代码库的质量和文档。 我们还强烈建议 Mantle 在上线之前实施更广泛的 QA 程序和测试,以防止潜在的未发现的漏洞被利用。 在代码的测试有限的区域(例如与 Mantle DA 的集成)中,这一点尤其重要。 在整个审计期间,Mantle 团队非常支持,并及时回答了问题。
- 原文链接: blog.openzeppelin.com/ma...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!