0. 回顾
- 保护 Solana 生态系统 (1) — Hello Solana
- 保护 Solana 生态系统 (2) — 程序间调用
- 保护 Solana 生态系统 (3) — 程序升级
- 保护 Solana 生态系统 (4) — 账户验证
- 保护 Solana 生态系统 (5) — 多重签名
1. 概述
在上一篇文章中,我们讨论了多重签名的实现。然而,该实现假设可以链下同时收集多个用户的签名。在本文中,我们介绍了一个更通用的多重签名程序,该程序允许用户在链上完成签名。
2. 测试程序设计
多重签名程序允许有效的签名者分开对提议者进行签名,并且一旦提议获得批准(收集到足够多的签名),任何人都可以执行该提议。所有测试代码可以在这里找到。
3. 代码审查
本程序引入了两个额外的结构体:TransactionAccount 和 Transaction。TransactionAccount 结构体用于记录提议交易使用的账户信息。Transaction 结构体用于记录提议的信息。请注意,signers 属性用于记录有效签名的数量。did_execute 和 is_initialized 确保执行和初始化只能进行一次。

该程序提供了五种不同的指令。AllocatePDA 指令旨在创建一个唯一的 PDA 账户,并将其用作 multisig 账户。它将记录所有有效签名者的信息。在 InitializeMultisig 指令中,我们设置了执行指令所需的签名数量,以及有效签名者的公钥数组。CreateTransaction 指令用于创建提议,而签名者可以通过 approve 指令批准提议。一旦批准数量达到 multisig 中设置的阈值,就可以调用 ExecuteTransaction 指令来执行交易。

要提交提议,用户可以调用 createTransaction() 指令。它需要三个账户,即创建的 transaction 账户,以及用于目标交易的后两个账户。为了防止账户被恶意用户重新初始化,我们检查 is_initialized 属性(第 161-163 行)。之后,我们使用指定的数据初始化 TransactionAccount 结构体,并将其序列化到数据账户中(第 188 行)。

在 Approve() 函数中,我们首先检查 Transaction 账户和 multisig 账户是否由程序拥有。请注意,如果没有检查,来自其他程序的账户可能会被恶意用户使用。接下来,我们将签名者的公钥与 multisig 账户中存储的密钥进行匹配。如果匹配成功,将验证您的签名,并相应地将值更改为 true。

在 ExecuteTransaction() 指令中,我们计算有效签名的数量。如果数量未达到阈值,程序将回滚。

之后,我们使用指定的属性初始化目标 Instruction,并通过 invoke_signed() 函数调用目标程序的指令。最后,我们将 did_execute 属性设置为 true,以防止提议被重复执行。

我们将程序部署到了测试网上,可以在以下链接找到:
https://explorer.solana.com/address/CPzn7ptnJntjUB4NGKqQGRai8NFLNwFaspmJ7nEGbMHe?cluster=testnet
4. 发送交易
部署完成后,我们首先创建 multisig 账户,并在初始化 config 账户时将其设置为 config 账户的管理员。相关交易如下所示,顺序为:createMultisig()(在 General-Multisig 中)-> 部署 PriviligeOwner 程序 -> Allocate()(在 PrivligeOwner 中)-> InitializeConfig()(在 PrivligeOwner 中)。
https://explorer.solana.com/tx/2vXHmwbCsARstx8wi4eLACbrb6PuZZMktsqU8VnJLp64fvrpaE62QSTn5QLczzxnTvxRLWMSR3dKLGYXZasGMn69?cluster=testnet https://explorer.solana.com/tx/2EMq9y6HNnXq1n2XsqrBkJd8RGL27PCj5T4JyJ71ZoA3ipUggT6dF6S6uDv4TtxGGKk8BmiAJHS7BFRgZqWjkWVb?cluster=testnet https://explorer.solana.com/tx/3UhXKsTubUiPqRtLyNYskxvbyrTKHsbeptxuAfJQ348AU4b8gQET2HAMaqxwud6Wo3MKTYHWBneqa9z2WhCpwV6t?cluster=testnet https://explorer.solana.com/tx/5NA7Yw23uRf48Q3BYM21dtS7gD9YMECij43ZaRLMPe7svt3bsv2TPWwbCRP5akDmttjLEHWZtpqrZrVLNr9QLyJY?cluster=testnet
接下来,我们调用 InitializeMultisig() 指令。我们传入四个账户,它们是 multisig 账户和三个有效签名者的账户。我们将 m 的值设置为 2,这意味着需要三个签名者中的两个签名才能执行特权函数。

在 CreateTransaction() 函数中,我们传入创建的 Transaction 账户、目标程序(PrivilegeOwner)的公钥以及 config 账户的公钥(第 306 - 307 行)。此外,我们还应将 _data 设置为 3,这对应于 PrivilegeOwner 程序中的 unlock() 指令。

对于第一次测试,只有一个签名者批准了创建的提议。在这种情况下,ExecuteTransaction() 由于收集的签名不足而失败。控制台打印出以下输出。

另一位签名者批准了创建的提议并调用 ExecuteTransaction()。签名的总数已达到阈值,因此提议可以成功执行。
https://explorer.solana.com/tx/55Qy93RxybsT7c5v9AFgN8Dt1h3AVJfbsosLbstYVB6paY1wmau5sdtLfGpfryXnZTsBNRauvwLSmAu2nABFxVCe?cluster=testnet https://explorer.solana.com/tx/4XF4MUhL4oftkDt4sn7NoREmGqcDMVP6HGypvJQMtiAbBKiCuy4B98vhQKtvm4mPv7SprrDDVsiwgb6pNwgJcTwz?cluster=testnet
4. 总结
在本文中,我们介绍了 Solana 中多重签名的通用实现。该实现利用了 PDA 的特性,使得程序在有效签名数量满足要求时,可以自动以 PDA 的身份签署交易。请继续关注,我们将在接下来的文章中分享更多内容。
阅读本系列其他文章:
- 保护 Solana 生态系统 (1) — Hello Solana
- 保护 Solana 生态系统 (2) — 程序间调用
- 保护 Solana 生态系统 (3) — 程序升级
- 保护 Solana 生态系统 (4) — 账户验证
- 保护 Solana 生态系统 (5) — 多重签名
- 保护 Solana 生态系统 (7) — 类型混淆
关于 BlockSec
BlockSec 是一家开创性的区块链安全公司,由一群全球知名的安全专家于 2021 年创立。公司致力于增强新兴 Web3 世界的安全性和可用性,以促进其大规模采用。为此,BlockSec 提供智能合约和 EVM 链安全审计服务,用于主动进行安全开发和阻止威胁的Phalcon平台,用于资金追踪和调查的MetaSleuth平台,以及供 Web3 构建者在加密世界中高效冲浪的MetaSuites扩展。
迄今为止,该公司已为 MetaMask、Uniswap Foundation、Compound、Forta 和 PancakeSwap 等 300 多家尊贵客户提供服务,并通过两轮融资从 Matrix Partners、Vitalbridge Capital 和 Fenbushi Capital 等知名投资者那里获得了数千万美元的资金。
官方 Twitter 账号:https://twitter.com/BlockSecTeam



