---
title: "如何创建 Solana 钱包：技术指南"
description: "介绍 Solana 钱包基础知识，并讲解如何配置基础钱包和智能钱包。"
---

# 如何创建 Solana 钱包：技术指南

在过去几年里，Solana 成为最活跃的区块链网络之一，日均超过 [120 万活跃用户](https://coincentral.com/solana-outperforms-ethereums-early-stage-with-2-85b-revenue/)，[每天完成 6000 万\+笔交易\(非投票\)](https://blockworks.com/analytics/solana/solana-onchain-activity?ref=blog.quicknode.com)。这一活跃度由 DeFi、DePIN、机构、企业等共同驱动，一切都以极快的速度和每笔交易几分之一美分的成本进行。

如果你想在 Solana 上构建应用、接入这个热门且快速增长的生态，从钱包入手是一个不错的切入点。钱包是与任何链交互的入口：签署交易、持有资产、为应用提供支持。

在本指南中，我们将带你使用 Alchemy 的 [可靠 RPC 端点](https://www.alchemy.com/solana) 创建一个普通的 Solana 钱包，实现无缝的网络连接，然后对比普通钱包和智能钱包。让我们开始吧，先从 devnet 开始，这样你可以测试而不用花费真实的 SOL。

## Solana 上的钱包：基础知识

在 Solana 上，钱包与你在 Ethereum 上习惯的方式并不完全相同。Solana 没有严格区分用户控制的[外部拥有账户\(EOA\)和智能合约](https://www.alchemy.com/docs/ethereum-accounts)，而是将一切都视为[账户](https://solana.com/docs/core/accounts)，即区块链上的数据存储单元。这里的"钱包"通常只是一个密钥对\(公钥和私钥\)，让你能够控制一个或多个账户。账户可以持有 SOL 代币、其他资产，甚至是[程序](https://solana.com/docs/core/programs)\(Solana 版本的智能合约\)的可执行代码。

这种统一的方式带来了一些有意思的特性，比如程序派生地址\(PDA\)，程序可以生成地址，甚至可以在无需用户私钥的情况下代表用户签署交易。

相比 Ethereum 的模式——EOA 仅用于签名，合约单独处理逻辑——这是一种更灵活的设置。关于 Solana 账户模型的更多内容，请参阅 [Solana 官方关于账户和钱包的文档](https://solana.com/docs/core/accounts#accounts-and-wallets)。

Solana 钱包大致分为两类：

- **普通钱包\(基于密钥对\)**：这是最直接的加密密钥对，用于签署交易和管理账户。它们适合脚本或测试使用，但你需要手动处理密钥和费用。
- **智能钱包\(带账户抽象\)**：通过隐藏密钥管理等繁琐细节来提升体验。智能钱包支持社交认证\(例如用邮箱或 passkey 登录而不是助记词\)、gas/rent 赞助\(由他人支付交易费用\)、批量交易\(一次完成多个操作\)，甚至由可编程逻辑驱动的自动化行为。Solana 的设计让这些特性在应用中格外强大，超出了 Ethereum [ERC-4337](https://www.alchemy.com/overviews/how-do-smart-contract-wallets-work) 专注于体验优化的范围。想深入了解 Solana 的账户抽象，可参阅 [Solana Cookbook 中关于钱包管理的内容](https://solana.com/developers/cookbook/wallets/create-keypair)以及[关于 ERC-4337 在 Solana 上的深度解析](https://solana.com/developers/evm-to-svm/erc4337)。

在本教程中，我们将使用 Alchemy 的 RPC 端点构建一个普通钱包，让你无需搭建自己的节点就能可靠地访问 Solana 网络。如果需要社交登录等智能钱包功能，可以将钱包提供商与 Alchemy 的基础设施搭配使用。

## 前置条件：搭建你的 Devnet 环境

在进入代码之前，先确认你已准备就绪。本教程假设你已经掌握基础的 JavaScript，但我们会在过程中解释相关概念，方便所有人跟上进度。你需要准备以下内容：

- **Node.js\(v16 或更高版本\)和 npm/yarn**：这是在浏览器之外运行 JS 代码的运行环境。如果还没有安装，可以从 [nodejs.org](https://nodejs.org/) 下载。
- **像 [VS Code](https://www.alchemy.com/dapps/vs-code) 或 Cursor 这样的代码编辑器**：用于编写和调试代码。VS Code 是免费的，并且有很多适合区块链开发的插件，可以[在这里](https://code.visualstudio.com/)安装。Cursor 则像是一个更酷、内置 AI 的 VS Code，可以[在这里](https://cursor.com/agents)体验。
- **基础的 JavaScript 知识**：示例使用 Node.js 和 Solana web3.js。
- **一个 Alchemy 账户**：在 [dashboard.alchemy.com](https://dashboard.alchemy.com/) 免费注册。创建一个新应用，选择 Solana\(测试用 devnet，生产用 mainnet\)，获取你的 API key。顺便可以启用一个 EVM 链，比如 Sepolia，如果你需要混合支持——这对跨链应用很有用。
- **普通钱包所需**：安装 [Solana web3.js 库](https://www.npmjs.com/package/@solana/web3.js)，它负责密钥生成、连接和交易处理。这个库是与 Solana 程序交互的首选工具。

  `npm install @solana/web3.js`

提示：先在 devnet 上构建一切。这是主要的测试环境，能完美模拟 mainnet 部署，让你测试合约、走通流程、确保一切正常运作。等你确信无误、部署到 testnet 并充分测试后，部署到 mainnet 只需替换 RPC URL 即可。无需修改代码，切换即可。

## 理解 Solana 的钱包结构

在生成钱包之前，先退一步，快速了解一下 Solana 钱包的工作原理。这有助于你理解接下来步骤的逻辑，尤其是如果你之前使用过 Ethereum。

- **账户与钱包**：在 Solana 中，钱包本质上是一个*拥有*账户的密钥对。账户就像存放数据的容器：可以存储你的 SOL 余额、代币或程序代码。与 Ethereum 中 EOA\(用户地址\)与合约地址分离不同，Solana 模糊了这条界限：一切都是账户。这意味着你可以随时创建账户，单独为它们注资，甚至让程序通过 [PDA](https://solana.com/docs/core/pda) 来控制它们。生成密钥时不会自动创建账户，需要注资才能初始化。更深入的内容请参阅 [Solana 的核心概念](https://solana.com/docs/core)。
- **用 rent 代替动态 gas 费用**：Solana 不像 Ethereum 那样为每个计算单元收取 gas 费：交易采用固定费用\(非常低，截至 2025 年平均约为 0.00025 美元\)，但如果账户余额低于某个阈值\(约每 KB 0.00089 SOL\)，账户需要支付"rent"来维持其数据存储在链上。这类似于存储押金：要么预先支付，要么保持足够的 SOL 以豁免。这样可以通过清除不活跃账户来保持网络精简。交易仍然需要支付费用，但 rent 是持久化存储方面的独特设计。可以将其与 Ethereum 的 gas 做对比，后者按操作收费，在网络拥堵时可能飙升。而 Solana 的模型优先保证速度。更多内容请参阅 [Solana 的 rent 文档](https://solana.com/docs/core/fees#rent)。
- **PDA 与可编程性**：程序可以派生出[「程序派生地址」](https://solana.com/docs/core/pda)，它们看起来像普通地址，但由代码而非密钥控制，这使得像自动签名这样的智能钱包功能成为可能。相比 Ethereum 的合约钱包，这种机制更深度地融入了 Solana 的核心架构。

理解这些概念有助于你明白为什么 Solana 钱包天生就显得更"可编程"。这一切都源于灵活账户这个概念。

## 如何创建普通的 Solana 钱包：分步指南

普通钱包是你的入门级设置：一个用于签署交易的简单密钥对。它们非常适合后端脚本、测试，或者当你想要完全控制而不需要抽象层时使用。在本教程中，我们将使用 `@solana/web3.js` 来生成密钥对。

然后我们会使用 Alchemy 的 RPC 连接到网络；没有 RPC 连接，你的钱包就无法查询余额或发送交易。

### 第一步：生成密钥对

在 Solana 上生成钱包意味着创建一对全新的加密密钥，本质上是一对数学上相互关联、协同工作的密钥。公钥成为你在 Solana 上的钱包地址，你可以自由地分享给任何需要向你发送资金或与你账户交互的人。私钥\(也称为 secret key\)用来证明你拥有该地址，并允许你签署交易。

这里有一个与 Ethereum 的重要区别：在 Ethereum 上，当你生成一个外部拥有账户\(EOA\)时，它立即处于"就绪"状态并存在于区块链上。而在 Solana 上，生成密钥对只是创建了加密密钥，区块链上真正的账户在有人给该地址注资之前并不存在。这是 Solana 账户模型的一部分，账户需要有 rent 豁免余额才能在链上持久存在。

创建一个新的 JS 文件\(比如 regular-wallet.js\)，运行以下代码片段：

<CodeSnippet language="javascript" code={`import { Keypair } from '@solana/web3.js';

const wallet = Keypair.generate();
console.log('Public Key (Wallet Address):', wallet.publicKey.toString());
console.log('Secret Key:', wallet.secretKey); // Secure this immediately! Never log in production.`} />
用 node.js 运行这段脚本，搞定——你现在有了一个钱包。

你应该得到如下返回结果：

- **公钥\(钱包地址\)**：这是一个 base58 编码的字符串，看起来类似于 `7xj9WkvP6Az8vG5nXJh4Fq3qY8kPqT9wXVZN2xMqGnD4`。这是你在想要接收资金、连接[应用](https://www.alchemy.com/dapps/top/defi-dapps)或查询余额时分享给别人的内容。可以把它想象成你的银行账号，公开分享是安全的。
- **Secret Key**：这是以 `Uint8Array` 形式返回的\(一个 64 字节的数组\)。这是你的私钥，是证明你控制该钱包的加密凭证。任何拥有该 secret key 的人都可以签署交易并转移你钱包中的资金。永远不要分享它，也不要将其提交到版本控制系统中。

关于 secret key 的关键安全实践：

- **切勿在生产环境中打印它**：我们示例中的 `console.log` 适合本地测试，但在部署任何实际应用之前必须移除。
- **使用环境变量**：将其存储在添加到 `.gitignore` 中的 `.env` 文件里。在代码中通过 `process.env.PRIVATE\_KEY` 访问。
- **考虑使用硬件钱包**：对于处理大额资金的生产应用，集成像 [Ledger](https://www.alchemy.com/dapps/ledger) 或 [Trezor](https://www.alchemy.com/dapps/trezor) 这样的硬件钱包，把私钥隔离在安全硬件中。
- **如需存储请加密**：如果必须将 secret key 存储在数据库或文件中，先用强加密库对其加密。

关于安全最佳实践，请参阅 [Solana 的安全指南](https://solana.com/learn/staying-safe-on-solana)。

### 第二步：通过 Alchemy RPC 连接到网络

现在，使用 RPC 端点将你的钱包连接到 Solana devnet。这个"connection"对象让你的代码能够与区块链通信，获取余额、提交交易等。Alchemy 的 RPC 就像连接 Solana 节点的增强版代理，负责负载均衡，让你的应用保持响应。

将以下内容添加到你的脚本中\(将 \<YOUR_API_KEY\> 替换为你从 [Alchemy dashboard](https://dashboard.alchemy.com/) 获取的 key\)：

<CodeSnippet language="javascript" code={`import { Connection } from '@solana/web3.js';

const connection = new Connection(
'https://solana-devnet.g.alchemy.com/v2/<YOUR_API_KEY>', // Devnet for testing
'confirmed' // Commitment level: 'confirmed' for speed with some finality
);

async function checkBalance(publicKey) {
const balance = await connection.getBalance(publicKey);
console.log('Balance:', balance / 1e9, 'SOL'); // Convert lamports (1 SOL = 1e9 lamports)
}

await checkBalance(wallet.publicKey);`} />
这个连接可以让你检查钱包是否已注资，并与应用交互。运行脚本；如果未注资，响应会显示 0 SOL。完整的 RPC 方法请参阅 [Solana 的 RPC 文档](https://solana.com/docs/rpc)或我们的 [Alchemy Solana RPC 指南](https://www.alchemy.com/docs/reference/solana-api-quickstart)。

### 第三步：为钱包注资并与之交互

连接建立后，让我们开始进行链上交互。这里才是真正有意思的部分：通过 airdrop\(仅限 devnet\)注资、签署交易等。这些基础操作能让你转账 SOL、调用程序或构建简单的工具。

#### 请求 airdrop\(在 devnet 上注资\)

Devnet 会提供免费的 SOL 用于测试，让你在账户为空时为其注资，但要注意每个 IP 地址每天限额约为 24 SOL。

你需要为账户注资，以支付 rent 豁免所需的费用。这个方法仅适用于 devnet。在生产环境中，费用需要用真实的 SOL\(而不是测试 SOL\)支付，你需要通过 Coinbase 等交易所购买/注资账户。参阅 [Solana 的 Devnet Sol 指南](https://solana.com/developers/guides/getstarted/solana-token-airdrop-and-faucets)。

<CodeSnippet
  language="javascript"
  code={`const airdropSignature = await connection.requestAirdrop(
wallet.publicKey,
1e9 // 1 SOL in lamports
);
await connection.confirmTransaction(airdropSignature);
console.log('Airdrop complete! Check balance again.');`}
/>
以下是每一步的说明：

- **请求 airdrop**：`connection.requestAirdrop\(\)` 向 devnet 请求测试 SOL。它接收你钱包的公钥和以 lamports 为单位的金额\(`1e9` = 1 SOL\)，然后返回一个交易签名，即该交易的唯一标识符。
- **确认交易**：`await connection.confirmTransaction\(\)` 等待网络处理你的 airdrop。这一步至关重要，如果不等待确认，即使 airdrop 已被请求，你的余额可能仍然显示为 0 SOL。Solana 异步处理交易，因此需要等待。
- **成功**：确认后，再次运行 `checkBalance\(\)`，你应该会在钱包中看到 1 SOL。

#### 签署并发送交易

让我们向另一个地址转账 0.1 SOL。这个示例演示了交易签名，你的私钥通过加密方式授权该交易，证明你拥有发送方钱包。我们将构建一笔交易，用你的密钥对签署它，然后通过 RPC 将其广播到网络。交易费用\(约 0.000005 SOL\)会自动从你的余额中扣除。对于更复杂的操作，比如多指令交易或程序调用，可以参阅 [Solana 的交易基础](https://solana.com/docs/core/transactions)文档。

运行以下代码来发送 SOL：

<CodeSnippet language="javascript" code={`import { Transaction, SystemProgram, PublicKey, sendAndConfirmTransaction } from '@solana/web3.js';

const recipient = new PublicKey('recipient_address_here'); // Replace with a real address\`

const tx = new Transaction().add(
SystemProgram.transfer({
fromPubkey: wallet.publicKey,
toPubkey: recipient,
lamports: 1e8 // 0.1 SOL
})
);

// Simplest approach - handles blockhash and confirmation automatically
const signature = await sendAndConfirmTransaction(
connection,
tx,
[wallet] // Signers
);

console.log('Transfer signature:', signature);`} />
以下是每一步的说明：

- **创建接收方**：`new PublicKey\(\)` 将一个 base58 编码的地址字符串转换为 Solana 可以处理的 PublicKey 对象。将 `'recipient\_address\_here'` 替换为实际的 Solana 地址\(你甚至可以用自己钱包的公钥来测试给自己转账\)。
- **构建交易**：`new Transaction\(\).add\(\)` 创建一笔交易并添加一个转账指令。`SystemProgram.transfer\(\)` 调用指定了发送方\(`fromPubkey`\)、接收方\(`toPubkey`\)以及以 lamports 为单位的金额\(1e8 = 0.1 SOL\)。
- **发送并确认**：`sendAndConfirmTransaction\(\)` 是一个帮助函数，一次性处理三个步骤：获取最新的 blockhash\(所有 Solana 交易都需要\)、用你的钱包密钥对签署交易、将其发送到网络并等待确认。`\[wallet\]` 数组包含所有签署方，本例中只有你的钱包。
- **交易签名**：返回的签名是执行的凭证，是该笔交易在区块链上的唯一标识符。
- **安全提示**：切勿硬编码 secret key，而应使用 `process.env.PRIVATE\_KEY`。在生产环境中，集成硬件钱包以减少其他攻击面。关于密钥安全管理的更多内容，请参阅[我们的密钥管理与安全最佳实践](https://www.alchemy.com/docs/best-practices-for-key-security-and-management)。

如果一切顺利，你应该会得到一个成功的交易签名！该签名证明这笔交易已在 Solana 区块链上被处理。你可以在 [Solana Explorer](https://explorer.solana.com/?cluster=devnet) 上查询它，查看完整详情：发送方、接收方、支付的费用以及区块确认信息。

这就是在 devnet 上与一个简单的 [Solana 钱包](https://www.alchemy.com/overviews/solana-wallets)交互的核心内容：生成密钥对、通过 RPC 连接、注资、签署交易。这些基础构建模块——密钥对生成、网络连接、余额查询和交易签名——是所有 Solana 开发工作的基础。

我们刚刚交互过的这些基于普通密钥对的钱包，非常适合需要程序化控制的后端脚本、测试与开发、偏好直接管理自己密钥的人员，以及基础转账和程序交互等简单场景。但你也可以看出它们各有取舍：用户必须自行管理密钥、支付自己的费用，并处理区块链交互的技术复杂性。对于注重用户体验的消费级应用来说，这种摩擦可能是致命的。

这正是智能钱包的用武之地。它们抽象掉了复杂性，同时为你提供社交登录、无 gas 交易和 session key 等强大功能。

## 普通钱包与智能钱包：快速对比

为了帮助你根据使用场景做出选择，下表列出了 Solana 上不同钱包类型的关键区别，并说明在项目中应分别在什么情况下使用它们。

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 200, title: "", dataType: "object" },
      { key: "2", width: 200, title: "Regular Wallet", dataType: "object" },
      { key: "3", width: 200, title: "Smart Wallet", dataType: "object" },
    ],
    data: [
      {
        "1": { title: "<p><strong>Structure</strong></p>", tooltip: "", icon: "" },
        "2": { title: "<p>Simple keypair (EOA-like)</p>", tooltip: "", icon: "" },
        "3": { title: "<p>Abstracted via AA; uses PDAs for programmable control</p>", tooltip: "", icon: "" },
        id: 0,
      },
      {
        "1": { title: "<p><strong>Features</strong></p>", tooltip: "", icon: "" },
        "2": { title: "<p>Basic signing, manual fee handling</p>", tooltip: "", icon: "" },
        "3": { title: "<p>Social login, batching, sponsorship, automation</p>", tooltip: "", icon: "" },
        id: 1,
      },
      {
        "1": { title: "<p><strong>Complexity</strong></p>", tooltip: "", icon: "" },
        "2": { title: "<p>Low, direct key management</p>", tooltip: "", icon: "" },
        "3": { title: "<p>Medium, Complex setup abstracted by SDK</p>", tooltip: "", icon: "" },
        id: 2,
      },
      {
        "1": { title: "<p><strong>Use Cases</strong></p>", tooltip: "", icon: "" },
        "2": { title: "<p>Scripts, bots, testing setups</p>", tooltip: "", icon: "" },
        "3": { title: "<p>User-facing apps, seamless onboarding</p>", tooltip: "", icon: "" },
        id: 3,
      },
      {
        "1": { title: "<p><strong>vs. Ethereum</strong></p>", tooltip: "", icon: "" },
        "2": { title: "<p>Uniform accounts; PDAs add flexibility</p>", tooltip: "", icon: "" },
        "3": { title: "<p>Solana-specific rent handling + EVM compatibility via SDK</p>", tooltip: "", icon: "" },
        id: 4,
      },
      {
        "1": { title: "<p><strong>Alchemy Role</strong></p>", tooltip: "", icon: "" },
        "2": { title: "<p>RPC for reliable connections</p>", tooltip: "", icon: "" },
        "3": { title: "<p>SDK + RPC for full AA features</p>", tooltip: "", icon: "" },
        id: 5,
      },
    ],
  }}
/>

## 最佳实践：构建过程中需要牢记的要点

在构建 Solana 钱包时，以下是一些最佳实践和技巧，帮助确保它安全、可扩展且易于使用。

- **安全第一**：对于普通钱包，在 mainnet 上始终使用硬件钱包\(如 Ledger 或 Trezor\)，让密钥保持离线状态。对于智能钱包，使用钱包提供商的 passkey 或多因素认证，通过避免助记词来降低钓鱼风险。切勿在代码中暴露密钥，使用加密存储。用类似 [Solana 的安全指南](https://solana.com/learn/staying-safe-on-solana)这样的工具审计你的配置。
- **充分测试**：始终从 devnet 或 testnet 开始迭代，无需成本。使用 Alchemy 的 dashboard 监控 RPC 使用情况、交易失败和性能指标，就像是为你的区块链调用内置的调试器。模拟网络拥堵等边界情况，确保重试机制正常工作。
- **错误处理与可靠性**：将 RPC 调用包裹在 try-catch 块中，并添加指数退避重试\(例如通过 p-retry 等库\)。Solana 的速度可能导致竞态条件，因此为了最大程度的安全，应使用 'finalized' commitment 来确认交易。这能让你的应用更稳健，尤其是对于高并发应用而言。
- **可扩展性考量**：Alchemy 的基础设施会针对高负载自动扩展，因此你不会在 RPC 层遇到瓶颈。对于智能钱包，尽可能批量处理以减少交易数量。监控 rent 豁免情况，避免意外成本。像 [Solscan explorer](https://solscan.io/) 这样的工具有助于追踪这些情况。
- **深入学习资源**：持续关注 [Alchemy 的 Solana 文档](https://www.alchemy.com/docs/reference/solana-api-quickstart)获取 SDK 更新，并查阅 [Solana 官方 react wallet adapter](https://solana.com/developers/cookbook/wallets/connect-wallet-react)以了解 UI 集成方式。

## 总结：开始在 Solana 上构建

到这里，你已经掌握了如何借助 Alchemy 搭建一个普通的 Solana 钱包，以及智能钱包与之相比的差异。无论你是编写简单的转账脚本，还是构建具备无 gas 登录的强大 dApp，Solana 的生态都为创新做好了准备。现在正是时候开始动手实践。更多内容请查看我们的[完整 Solana 开发者资源](https://www.alchemy.com/docs/reference/solana-api-quickstart)以及 [Solana 文档](https://solana.com/developers)。祝你开发顺利——如果遇到问题，请访问 [Alchemy 支持中心](https://www.alchemy.com/support)。让我们一起创造一些链上的精彩吧！

## 常见问题

### 什么是 Solana 钱包？

Solana 钱包是一个密钥对\(公钥和私钥\)，让你能够控制 Solana 区块链上的账户，这些账户可以持有 SOL 代币、其他资产或可执行代码。与 Ethereum 的 EOA 模型不同，Solana 将一切都视为账户，结构更加灵活、可编程。

### 创建 Solana 钱包需要付费吗？

不需要，生成密钥对是免费的，但 Solana 上的账户需要支付 rent\(约每 KB 0.00089 SOL\)才能在链上持久存在，交易费用平均为 0.00025 美元。在 devnet 上你可以通过 airdrop 获取免费测试 SOL，但 mainnet 需要购买 SOL。

### 普通 Solana 钱包与智能 Solana 钱包有什么区别？

普通钱包是基础密钥对，你需要手动管理密钥并支付费用，适合脚本和测试使用。智能钱包利用账户抽象提供社交登录、gas 赞助、批量交易和可编程逻辑，非常适合面向用户的应用。

### 我可以用社交登录代替助记词吗？

可以，许多智能钱包提供商允许用户通过邮箱、Google 或 passkey 进行身份验证，而不必管理助记词。这消除了传统密钥管理给用户带来的摩擦。

### 如何在 devnet 上为我的 Solana 钱包注资？

使用 `connection.requestAirdrop()` 在 devnet 上获取免费测试 SOL\(每个 IP 每天限额约 24 SOL\)。对于 mainnet，你需要通过 [Coinbase](https://www.alchemy.com/dapps/coinbase) 等交易所购买 SOL。

### Solana 上的 rent 是什么？

Rent 是一种存储押金机制，账户必须维持最低 SOL 余额\(约每 KB 0.00089 SOL\)才能在链上保持活跃。它与 Ethereum 的 gas 费用不同，通过清除不活跃账户来帮助保持网络高效。

### 智能钱包可以为用户赞助交易费用吗？

可以，一些智能钱包提供商支持 gas 和 rent 赞助。这让你的应用能够代付用户费用，实现无 gas 体验，从而提升转化率并简化入门流程。

### 我需要自己运行 Solana 节点吗？

不需要，我们的 RPC 端点提供对 Solana 网络的可靠访问，无需运行自己的节点。该服务负责负载均衡、扩展，并提供 HTTP 和 WebSocket 连接以支持实时更新。
