diff --git a/public/content/restaking/index.md b/public/content/restaking/index.md index 54bdc4f459c..e6f4441e74e 100644 --- a/public/content/restaking/index.md +++ b/public/content/restaking/index.md @@ -29,9 +29,9 @@ Restaking is a technology built for [stakers](/staking/) to extend this security ## What is restaking? {#what-is-restaking} -Restaking is when stakers use their already-staked ETH to secure other decentralized services. In return, restakers can get additional rewards from those other services on top of their regular ETH staking rewards. +Restaking is when stakers use their already-staked ETH to secure other decentralized services. In return, restakers can get additional rewards from those other services on top of their regular ETH staking rewards. -The decentralized services secured by restaking are known as "Actively Validated Services" (AVSs). +The decentralized services secured by restaking are known as "Actively Validated Services" (AVSs). In the same way that many ETH stakers run Ethereum validation software, many restakers run specialized AVS software.
@@ -79,16 +79,17 @@ In this world with restaking, both the AVS and staker benefit from being able to There are several entities involved in restaking — each one of them plays an important part. -| **Term** | **Description** | -| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Term** | **Description** | +| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Restaking platforms** | A restaking platform is a service that connects AVSs, ETH stakers, and operators. They build decentralized applications for stakers to restake their ETH, and marketplaces where stakers, AVSs, and operators can find each other. | -| **Native restakers** | People who stake their ETH by running their own Ethereum validators can connect their staked ETH to a restaking platform, including EigenLayer and others, to earn restaking rewards on top of ETH validator rewards. +| **Native restakers** | People who stake their ETH by running their own Ethereum validators can connect their staked ETH to a restaking platform, including EigenLayer and others, to earn restaking rewards on top of ETH validator rewards. | + | -| **Liquid restakers** | People who stake their ETH via a third-party liquid staking provider, like Lido or Rocket Pool, get Liquid Staking Tokens (LSTs) that represent their staked ETH. They can restake these LSTs to earn restaking rewards while keeping their original ETH staked. +| **Liquid restakers** | People who stake their ETH via a third-party liquid staking provider, like Lido or Rocket Pool, get Liquid Staking Tokens (LSTs) that represent their staked ETH. They can restake these LSTs to earn restaking rewards while keeping their original ETH staked. | -| **Operators** | Operators run the AVSs' restaking software, performing the validation tasks each AVS requires. Operators are usually professional service providers that guarantee things like uptime and performance. Like non-operator restakers, operators use staked ETH to secure AVSs, but operators also receive extra rewards in exchange for their work. +| **Operators** | Operators run the AVSs' restaking software, performing the validation tasks each AVS requires. Operators are usually professional service providers that guarantee things like uptime and performance. Like non-operator restakers, operators use staked ETH to secure AVSs, but operators also receive extra rewards in exchange for their work. | -| **AVSs** | These are the decentralized services — like price oracles, token bridges, and data systems — that receive security from restakers and offer token rewards in return. | +| **AVSs** | These are the decentralized services — like price oracles, token bridges, and data systems — that receive security from restakers and offer token rewards in return. |
@@ -144,7 +145,7 @@ While AVSs offer different rates, Liquid Restaking Tokens (LRTs) like eETH give

The Ethereum co-founder is typing…

- Vitalik, the co-founder of Ethereum, warned about the potential risks of restaking in a 2021 blog post called Don't Overload Consensus. + Vitalik, the co-founder of Ethereum, warned about the potential risks of restaking in a 2021 blog post called Don't Overload Consensus.

@@ -155,7 +156,7 @@ While AVSs offer different rates, Liquid Restaking Tokens (LRTs) like eETH give | 🫡 Beginners | 🤓 Advanced Users | | --------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | 1. Stake ETH on platforms like Lido or Rocket Pool to get LSTs. | 1. Stake your ETH as a validator on Ethereum. | -| 2. Use those LSTs to start restaking on a restaking service. | 2. Compare restaking services like EigenLayer, Symbiotic and others. | +| 2. Use those LSTs to start restaking on a restaking service. | 2. Compare restaking services like EigenLayer, Symbiotic and others. | | | 3. Follow the instructions to connect your validator to the restaking smart contract. |
diff --git a/public/content/translations/zh/about/index.md b/public/content/translations/zh/about/index.md index 517d9852e7d..80169dbb746 100644 --- a/public/content/translations/zh/about/index.md +++ b/public/content/translations/zh/about/index.md @@ -1,6 +1,6 @@ --- -title: 关于我们 -description: 关于 ethereum.org 的团队、社区和任务 +title: "关于我们" +description: "关于 ethereum.org 的团队、社区和任务" lang: zh --- @@ -8,7 +8,7 @@ lang: zh ethereum.org 是一个为以太坊社区打造的公共且开源的网站,任何人都可以贡献其中。 我们有一支小型核心团队致力于维护和开发该网站,有全球数以千计的社区成员为其做贡献。 -**ethereum.org 的人员永远不会主动联系你。 请不要回应。** +**ethereum.org 的任何人绝不会主动联系您。 请勿回应。** ## 关于名称的说明 {#a-note-on-names} @@ -18,23 +18,23 @@ ethereum.org 是一个为以太坊社区打造的公共且开源的网站,任 以太坊是一个公共网络、一条区块链也是一种开源协议 -- 一个全球化社区运营、治理、管理并拥有以太坊,数以万计的开发者、节点运营者、以太币持有者和以太坊用户都是该社区的成员。 -[有关以太坊的更多信息](/what-is-ethereum/) +[更多关于以太坊的信息](/what-is-ethereum/) -[有关以太坊治理的更多信息](/governance/) +[更多关于以太坊治理的信息](/governance/) ### 以太币 (ETH) {#ether-or-eth} 以太币(名称代码为 ETH)是能在太坊上交易的原生货币。 使用以太坊网络需要支付以太币(以交易费的形式)。 以太币还用来质押,保护以太坊网络的安全。 当人们谈论以太坊的价格时,指的是以太币这种资产。 -[有关以太币的更多信息](/what-is-ether/) +[更多关于 ETH 的信息](/what-is-ether/) -[有关质押以太币的更多信息](/staking/) +[更多关于质押 ETH 的信息](/staking/) ### 以太坊基金会 {#ethereum-foundation} 以太坊基金会是一个非营利性组织,最初通过以太币众筹融资,致力于为以太坊网络及其生态系统提供支持。 -[有关以太坊基金会的更多信息](/foundation/) +[更多关于以太坊基金会的信息](/foundation/) ### ethereum.org {#ethereum-org} @@ -44,7 +44,7 @@ ethereum.org 是一个面向以太坊社区的开源公共网站和教育资源 ## 我们的使命 {#our-mission} -**ethereum.org 的使命是成为最好的门户网站,服务不断发展的以太坊社区。** +**ethereum.org 的使命是成为服务于以太坊不断壮大的社区的最佳门户。** 我们努力打造一个通俗易懂的教育资源,涵盖与以太坊相关的所有主题,帮助新用户熟悉以太坊及其关键概念。 我们希望: @@ -57,14 +57,14 @@ ethereum.org 是一个面向以太坊社区的开源公共网站和教育资源 为了达成这一使命,在 ethereum.org 网站上,我们的团队将专注于两个主要目标: -### 1. 改善 ethereum.org 访问者的用户体验 {#visitors} +### 1. 改善 ethereum.org 访客的用户体验 {#visitors} - 拓展、改进、并随时更新内容 - 通过本地化及网页开发最佳做法,提高可用性和可访问性 - 通过问卷调查、小测验和 web3 集成等功能提升用户参与度。 - 保持网站简洁高效 -### 2. 发展,巩固,并赋能贡献者社区 {#community} +### 2. 发展、壮大并赋能我们的贡献者社区 {#community} - 增加网站贡献者总数 - 通过吸引、认可和奖励提高贡献者的留存率。 @@ -76,54 +76,59 @@ ethereum.org 是一个面向以太坊社区的开源公共网站和教育资源 我们有一些核心原则,可指引我们完成使命。 -### 1. ethereum.org 是以太坊的门户网站 🌏 {#core-principles-1} +### 1. ethereum.org 是通往以太坊的门户 🌏 {#core-principles-1} -我们希望激发用户的兴趣并回答他们的问题。 因此,我们的门户网站需要汇集信息、“奇迹的瞬间”和指向优秀社区资源的链接。 我们网站内容的目标是作为“入门通道”,而不是取代现存的大量资源。 我们致力于支持和整合社区开发的资源,提高它们的可见度,并使它们更易被发现。 [以太坊社区](/community/)就是核心:我们不仅仅服务于该社区,更要与之合作并吸取反馈意见。 该网站不仅仅面向当前的以太坊社区,更是面向我们心中所希望的社区。 我们必须记住,我们的社区是全球性的,包含使用多种语言、来自许多区域和文化的人。 +我们希望激发用户的兴趣并回答他们的问题。 因此,我们的门户网站需要汇集信息、“奇迹的瞬间”和指向优秀社区资源的链接。 我们网站内容的目标是作为“入门通道”,而不是取代现存的大量资源。 我们致力于支持和整合社区开发的资源,提高它们的可见度,并使它们更易被发现。 +[以太坊社区](/community/)是这一切的核心:我们不仅需要服务社区,还需要与他们合作并采纳他们的反馈。 该网站不仅仅面向当前的以太坊社区,更是面向我们心中所希望的社区。 我们必须记住,我们的社区是全球性的,包含使用多种语言、来自许多区域和文化的人。 ### 2. ethereum.org 在不断发展 🛠 {#core-principles-2} -以太坊和社区一直在不断发展,ethereum.org 也将如此。 这就是该网站采用简洁的设计体系和模块化结构的原因。 当我们进一步了解人们如何使用该网站以及社区对该网站的需求时,我们会进行反复改进。 我们是一个开源的贡献者社群,所以你可以提出建议或帮助我们解决问题。 [了解贡献](/contributing/) +以太坊和社区一直在不断发展,ethereum.org 也将如此。 因此,本网站拥有一个简单的设计系统和模块化结构。 当我们进一步了解人们如何使用该网站以及社区对该网站的需求时,我们会进行反复改进。 +我们是一个开源的贡献者社群,所以你可以提出建议或帮助我们解决问题。 +[了解如何贡献](/contributing/) -### 3. ethereum.org 不是普通的商品网站 🦄 {#core-principles-3} +### 3. ethereum.org 不是一个典型的产品网站 🦄 {#core-principles-3} -以太坊是一个庞然大物:它包括社区、技术、思想和意识形态等等。 这意味着网站需要处理许多不同的用户历程,从“需要特定工具的开发者”到“刚刚购买了一些以太币却不知道钱包是什么的新手”,不一而足。 “哪个网站是了解和学习区块链平台的最佳网站?”,这仍然是一个有争论的问题,但我们是先驱。 构建它仍需要不断地试验。 +以太坊是一个庞然大物:它包括社区、技术、思想和意识形态等等。 +这意味着网站需要处理许多不同的用户历程,从“需要特定工具的开发者”到“刚刚购买了一些以太币却不知道钱包是什么的新手”,不一而足。 +“哪个网站是了解和学习区块链平台的最佳网站?”,这仍然是一个有争论的问题,但我们是先驱。 构建它仍需要不断地试验。 ## 产品路线图 {#roadmap} -为了使我们的工作更易于了解,并促进更多的社区合作,ethereum.org 核心团队发布了一份 [Shape Up(规划-构建)周期](https://www.productplan.com/glossary/shape-up-method/)路线图概览。 +为了让我们的工作更易于访问并促进更多的社区协作,ethereum.org 核心团队会发布我们 [Shape Up(塑形)周期](https://www.productplan.com/glossary/shape-up-method/)路线图目标的概览。 -[查看我们的 2025 年第 1 周期产品路线图](https://github.com/ethereum/ethereum-org-website/issues/14726) +[查看我们的 2025 年第一周期产品路线图](https://github.com/ethereum/ethereum-org-website/issues/14726) -**这看起来怎么样?**我们始终感谢为我们的路线图提供的反馈 - 如有改进之处,请告诉我们! 我们欢迎社区里的任何人提出想法和建议。 +\*\*您觉得如何?\*\*我们随时欢迎您对我们的路线图提出反馈 — 如果您认为有什么我们应该改进的地方,请告诉我们! 我们欢迎社区里的任何人提出想法和建议。 -**想要参与吗?**[了解更多关于做贡献的信息](/contributing/),[在 Twitter 上联系我们](https://twitter.com/ethdotorg)或加入我们在 [ Discord 服务器](https://discord.gg/ethereum-org)上的社区讨论。 +**想参与进来吗?**[详细了解如何贡献](/contributing/)、[在 Twitter 上联系我们](https://x.com/ethdotorg),或在[我们的 Discord 服务器](https://discord.gg/ethereum-org)中加入社区讨论。 ## 设计原则 {#design-principles} -我们采用了一套[设计原则](/contributing/design-principles/),指导该网站的内容与设计决策。 +我们采用一套[设计原则](/contributing/design-principles/)来指导网站上的内容和设计决策。 -## 设计体系 {#design-system} +## 设计系统 {#design-system} -我们创建并发布了一个[设计体系](https://www.figma.com/file/NrNxGjBL0Yl1PrNrOT8G2B/ethereum.org-Design-System?node-id=0%3A1&t=QBt9RkhpPqzE3Aa6-1),用来加快功能上线的速度,并让社区成员参与 ethereum.org 的开放设计。 +我们构建并发布了一个[设计系统](https://www.figma.com/file/NrNxGjBL0Yl1PrNrOT8G2B/ethereum.org-Design-System?node-id=0%3A1&t=QBt9RkhpPqzE3Aa6-1),以便更快地发布功能,并让社区成员参与 ethereum.org 的开放式设计。 -想要参与吗?[在 Figma 中关注](https://www.figma.com/file/NrNxGjBL0Yl1PrNrOT8G2B/ethereum.org-Design-System) [GitHub 问题](https://github.com/ethereum/ethereum-org-website/issues/6284) 并加入我们在 [#design Discord 频道](https://discord.gg/ethereum-org)中的讨论。 +想要参与吗?在 [Figma 中跟进](https://www.figma.com/file/NrNxGjBL0Yl1PrNrOT8G2B/ethereum.org-Design-System),关注 [GitHub 问题](https://github.com/ethereum/ethereum-org-website/issues/6284),并加入我们 [#design Discord 频道](https://discord.gg/ethereum-org) 的对话。 -## 风格指南 {#style-guide} +## 样式指南 {#style-guide} -我们有一个[风格指南](/contributing/style-guide/)来规范写作内容,从而使贡献过程更加顺畅。 +我们有一份[样式指南](/contributing/style-guide/),用于规范内容编写的某些方面,以使贡献过程更加顺畅。 -如果你想要[对该网站做贡献](/contributing/),请务必先阅读[我们的原则](/contributing/design-principles/)以及[我们的风格指南](/contributing/style-guide/)。 +如果您想[为本网站做贡献](/contributing/),请务必阅读[我们的原则](/contributing/design-principles/)和[我们的样式指南](/contributing/style-guide/)。 欢迎大家针对我们的设计原则、设计体系和风格指南,提出反馈意见。 请记住,ethereum.org 来自社区,服务社区。 ## 许可证 {#license} -除非另有说明,ethereum.org 网站是开源的,并基于 [MIT 许可证](https://github.com/ethereum/ethereum-org-website/blob/dev/LICENSE)构建。 更多关于 ethereum.org [使用条款](/terms-of-use/)的信息。 +除非另有说明,否则 ethereum.org 网站是开源的,并遵循 [MIT 许可证](https://github.com/ethereum/ethereum-org-website/blob/dev/LICENSE)。 更多关于 ethereum.org 的[使用条款](/terms-of-use/)。 -## 正在招聘 {#open-jobs} +## 招聘职位 {#open-jobs} 虽然该网站是开源的并且任何人都可以改进它,但我们确实有一个专职团队,负责 ethereum.org 和以太坊基金会的其他 Web 项目。 -我们会在这里发布空缺的职位。 如果在这里看不到适合你的角色,请访问[我们的 Discord 服务器](https://discord.gg/ethereum-org),告诉我们你的合作意向! +我们会在这里发布空缺的职位。 如果您在这里没有看到适合您的职位,请前往[我们的 Discord 服务器](https://discord.gg/ethereum-org),告诉我们您希望如何与我们合作! -你想找除了 ethereum.org 团队以外的工作? [查看其他与以太坊相关的工作](/community/get-involved/#ethereum-jobs/)。 +你想找除了 ethereum.org 团队以外的工作? [查看其他以太坊相关工作](/community/get-involved/#ethereum-jobs/) diff --git a/public/content/translations/zh/ai-agents/index.md b/public/content/translations/zh/ai-agents/index.md new file mode 100644 index 00000000000..998fa9e46af --- /dev/null +++ b/public/content/translations/zh/ai-agents/index.md @@ -0,0 +1,99 @@ +--- +title: "AI 智能体" +metaTitle: "AI 代理|以太坊上的 AI 代理" +description: "以太坊上的 AI 代理概览" +lang: zh +template: use-cases +emoji: ":robot:" +sidebarDepth: 2 +image: /images/ai-agents/hero-image.png +alt: "人们聚集在终端桌子旁" +summaryPoint1: "与区块链交互并独立进行交易的 AI" +summaryPoint2: "控制链上钱包与资金" +summaryPoint3: "雇佣人类或其他代理进行工作" +buttons: + - content: 什么是 AI 智能体? + toId: what-are-ai-agents + - content: 探索代理 + toId: ai-agents-on-ethereum + isSecondary: false +--- + +想象一下,你可以借助一个AI助手浏览以太坊,它可以全天候24小时/7天研究链上市场趋势、回答问题,甚至代替你执行交易。 欢迎来到 AI 代理的世界——旨在简化你的数字生活的智能系统。 + +在以太坊上,我们正见证AI智能体的创新——从虚拟网红、自主内容创作者到实时市场分析平台,这些创新通过提供洞见、娱乐体验和运营效率,赋能广大用户。 + +## 什么是 AI 智能体? {#what-are-ai-agents} + +AI智能体是使用人工智能来执行任务或做出自主决策的软件程序。 它们从数据中学习,适应变化并处理复杂的任务。 它们不停地运转,可以随时发现机会。 + +### AI 代理如何与区块链协作 {#how-ai-agents-work-with-blockchains} + +在传统金融中,AI 智能体常常在中心化的环境中运行,获取的数据输入有限。 这阻碍了它们学习或自主管理资产的能力。 + +相反,以太坊的去中心化生态系统提供了几大关键优势: + +- 透明的数据:访问实时的区块链信息。 +- 真实的资产所有权:数字资产完全由 AI 智能體拥有。 +- 强大的链上功能:允许 AI 代理执行交易、与智能合约交互、提供流动性,并进行跨协议合作。 + +这些因素将AI智能体从简单的机器人转变为动态的、自我完善的系统,为多个领域提供巨大的价值: + + + + + + + +## 以太坊上的 AI 代理 {#ai-agents-on-ethereum} + +我们正开始探索AI智能体的全部潜力,而且已经有项目在人工智能和区块链之间发挥协同效应——特别是在透明度和货币化方面。 + + + +Luna 首次作为播客嘉宾亮相 + + + +## 智能代理控制的钱包{#agent-controlled-wallets} + +像 Luna 或 AIXBT 这样的智能代理控制着自己的链上钱包([AIXBT 钱包](https://clusters.xyz/aixbt)、[Luna 钱包](https://zapper.xyz/account/0x0d177181e3763b20d47dc3a72dd584368bd8bf43)),使它们能够给粉丝打赏并参与经济活动。 + +在 Luna 的 X 社交媒体营销活动 #LunaMuralChallenge 期间,Luna 通过她的 Base 钱包选出并奖励了获胜者——这标志着AI雇佣人类进行加密奖励的首次出现。 + + + + +

最好知道

+

AI智能体和相关工具仍处于早期开发阶段且尚处于实验阶段,请谨慎使用。

+
+
+ +## 使用聊天命令控制你的钱包 {#control-your-wallet-using-chat-commands} + +您可以跳过 DeFi 的复杂界面,使用简单的聊天命令管理您的加密货币。 + +这种直观的方法使交易速度更快、更容易,并且不容易出现将资金发送到错误的地址或支付过多的费用之类的错误。 + + + +## AI 代理 vs AI 机器人 {#ai-agents-vs-ai-bots} + +AI智能体和AI机器人之间的区别有时会令人困惑,因为它们都根据输入执行自动操作。 + +- AI机器人就像自动助手——它们遵循特定的、预先编程的指令来执行例行程序任務。 +- AI智能体更像是智能伙伴——它们从经验中学习,适应新信息,并自主做出决策。 + +| | AI 智能体 | AI 机器人 | +| -------- | ----------------- | ---------------- | +| **交互** | 复杂、适应性强、自主 | 简单、预定义范围、硬编码 | +| **学习** | 不断学习,能够实时实验并适应新数据 | 根据预训练数据或固定规则进行操作 | +| **任务完成** | 旨在实现更广泛的目标 | 只专注于特定任务 | + +## 深入了解 {#dive-deeper} + + + +## 你可以构建自己的 AI 代理 {#you-can-build-your-own-ai-agent} + + \ No newline at end of file diff --git a/public/content/translations/zh/bridges/index.md b/public/content/translations/zh/bridges/index.md index daede620964..e0b4e9ca06a 100644 --- a/public/content/translations/zh/bridges/index.md +++ b/public/content/translations/zh/bridges/index.md @@ -1,45 +1,45 @@ --- -title: 区块链桥简介 -description: 桥梁使用户能够跨不同的区块链转移他们的资金 +title: "区块链桥简介" +description: "桥梁使用户能够跨不同的区块链转移他们的资金" lang: zh --- -# 区块链桥 {#prerequisites} +# 区块链链桥 {#prerequisites} -_Web3 已经发展成为一个由一层网络区块链和二层网络扩展解决方案组成的生态系统,每个解决方案都具有独特的功能和权衡。 随着区块链协议数量的增加,跨链转移资产的需求也随之增加。 为了满足这一需求,我们需要桥接。_ +_Web3 已经发展成为一个由 L1 区块链和 L2 扩容解决方案组成的生态系统,每个解决方案都具有独特的功能和权衡取舍。_ 随着区块链协议数量的增加,跨链转移资产的需求也随之增加。为了满足这一需求,我们需要链桥。_ ## 什么是桥梁? {#what-are-bridges} -区块链桥就像我们在真实世界所知道的桥梁一样。 就像真实桥梁连结两个物理位置一样,区块链桥梁连接两个区块链生态系统。 **链桥传输信息和资产,促进了区块链之间的通信**。 +区块链桥就像我们在真实世界所知道的桥梁一样。 就像真实桥梁连结两个物理位置一样,区块链桥梁连接两个区块链生态系统。 **链桥通过信息和资产的转移来促进区块链之间的通信**。 我们来看一个例子: 你来自美国,正计划去欧洲旅行。 你有美元,但你需要欧元来消费。 要将你的美元兑换成欧元,你可以使用货币兑换并支付少量费用。 -但是,如果你想进行类似的兑换以使用一条不同的[区块链](/glossary/#blockchain),你要怎么做呢? 假设你想用以太坊主网上的[以太币](/glossary/#ether)兑换 [Arbitrum](https://arbitrum.io/) 上的以太币。 就像我们为欧元进行的货币兑换一样,我们需要一种机制将我们的以太币从以太坊转移到 Arbitrum。 桥梁使这种交易成为可能。 在本例中,[Arbitrum 有一个原生桥梁](https://bridge.arbitrum.io/),可以将以太币从主网转移到 Arbitrum。 +但是,如果你想使用不同的[区块链](/glossary/#blockchain)进行类似的兑换,你会怎么做? 假设你想将以太坊主网上的 [ETH](/glossary/#ether) 兑换成 [Arbitrum](https://arbitrum.io/) 上的 ETH。 就像我们为欧元进行的货币兑换一样,我们需要一种机制将我们的以太币从以太坊转移到 Arbitrum。 桥梁使这种交易成为可能。 在这种情况下,[Arbitrum 有一个原生链桥](https://portal.arbitrum.io/bridge),可以将 ETH 从主网转移到 Arbitrum 上。 ## 我们为什么需要桥梁? {#why-do-we-need-bridges} -所有区块链都有其局限性。 为了使以太坊实现扩容并满足需求,就必须进行[卷叠](/glossary/#rollups)。 或者,像 Solana 和 Avalanche 这样的一层网络具有不同的设计,以实现更高的吞吐量,但代价是去中心化。 +所有区块链都有其局限性。 为了让以太坊扩容并满足需求,就需要 [Rollup](/glossary/#rollups)。 或者,像 Solana 和 Avalanche 这样的一层网络具有不同的设计,以实现更高的吞吐量,但代价是去中心化。 -然而,所有区块链开发都是在孤立环境中进行的,因此具有不同的规则和[共识](/glossary/#consensus)机制。 这意味着它们无法进行原生通信,代币也无法在区块链之间自由移动。 +然而,所有区块链都是在隔离环境中开发的,并且具有不同的规则和[共识](/glossary/#consensus)机制。 这意味着它们无法进行原生通信,代币也无法在区块链之间自由移动。 桥梁的存在为了连接区块链,以便在它们之间进行信息和代币传输。 -**链桥的作用**: +**链桥能够实现**: - 跨链传输资产和信息。 -- 使[去中心化应用程序](/glossary/#dapp)可以利用各种区块链的优势 — 从而增强功能(因为协议现在有更多的创新设计空间)。 +- 让[去中心化应用程序](/glossary/#dapp)能够利用各个区块链的优势——从而增强其能力(因为协议现在有了更多的创新设计空间)。 - 使用户能够访问新平台并利用不同链的优势。 - 使来自不同区块链生态系统的开发人员相互协作并为用户构建新平台。 -[如何将代币桥接到二层网络](/guides/how-to-use-a-bridge/) +[如何将代币跨链至二层网络](/guides/how-to-use-a-bridge/) -## 桥梁用例 {#bridge-use-cases} +## 链桥用例 {#bridge-use-cases} 以下是你可以使用桥梁的一些场景: @@ -57,20 +57,20 @@ _Web3 已经发展成为一个由一层网络区块链和二层网络扩展解 ### 拥有原生加密资产 {#own-native} -如果你只有以太坊网络资产但想拥有原生比特币, 你可以先兑换得到以太坊上的 BTC - WBTC(Wrapped Bitcoin), 然而,包装比特币是以太坊网络的原生 [ERC-20](/glossary/#erc-20) 代币,这意味着它是比特币的以太坊版本,而不是比特币区块链上的原始资产。 然后你可以通过跨链桥,将资产从以太坊网络跨到比特币网络, 即将 WBTC 转换为原生 BTC。 或者,你可能拥有比特币,并且想在以太坊的[去中心化金融](/glossary/#defi)协议中使用它。 用于以太坊网络的 DeFi 协议中。 +如果你只有以太坊网络资产但想拥有原生比特币, 你可以先兑换得到以太坊上的 BTC - WBTC(Wrapped Bitcoin), 然而,WBTC 是以太坊网络原生的 [ERC-20](/glossary/#erc-20) 代币,这意味着它是比特币的以太坊版本,而不是比特币区块链上的原始资产。 然后你可以通过跨链桥,将资产从以太坊网络跨到比特币网络, 即将 WBTC 转换为原生 BTC。 或者,你可能拥有 BTC,并希望在以太坊 [DeFi](/glossary/#defi) 协议中使用它。 用于以太坊网络的 DeFi 协议中。 - 你还可以使用[中心化交易所](/get-eth/)完成上述所有操作。 但是,除非你的资金已经在交易所,否则将涉及多个步骤,而且你最好使用桥梁。 + 你还可以使用[中心化交易所](/get-eth)完成上述所有操作。 但是,除非你的资金已经在交易所,否则将涉及多个步骤,而且你最好使用桥梁。 -## 桥的类型 {#types-of-bridge} +## 链桥的类型 {#types-of-bridge} 桥梁具有各种设计和复杂程度。 一般来说,桥梁分为两类:需信任桥梁和去信任桥梁。 @@ -78,12 +78,12 @@ _Web3 已经发展成为一个由一层网络区块链和二层网络扩展解 | ------------------------------------- | -------------------------------------------------------- | | 需信任桥梁依赖于中心实体或系统的运作。 | 去信任桥梁使用智能合约和算法运行。 | | 他们对资金的保管和桥梁的安全性有信任假设。 用户大多依赖桥梁运营商的声誉。 | 这种桥梁免于信任,即桥梁的安全性与底层区块链的安全性相同。 | -| 用户需要放弃对其加密资产的控制。 | 借助[智能合约](/glossary/#smart-contract),去信任链桥使用户能够始终控制他们的资金。 | +| 用户需要放弃对其加密资产的控制。 | 通过[智能合约](/glossary/#smart-contract),去信任链桥让用户能够继续掌控自己的资金。 | 简而言之,我们可以说需信任桥梁具有信任假设,而去信任桥梁对信任的依赖非常小,因此不会在基础域之外出现新的信任假设。 上述术语的解释如下: -- **去信任**:与底层域具有同等的安全性。 如 [Arjun Bhuptani 在本文中所述。](https://medium.com/connext/the-interoperability-trilemma-657c2cf69f17) -- **信任假设**:通过在系统中添加外部验证者来摆脱底层域的安全性,从加密经济学的角度来说,这降低了安全性。 +- **去信任**:拥有与底层域同等的安全性。 正如 [Arjun Bhuptani 在这篇文章中所述。](https://medium.com/connext/the-interoperability-trilemma-657c2cf69f17) +- **信任假设:** 通过在系统中添加外部验证者来摆脱底层域的安全性,从加密经济学的角度来说,这降低了安全性。 为了更好地理解这两种方法之间的主要区别,我们来举个例子: @@ -104,22 +104,22 @@ _Web3 已经发展成为一个由一层网络区块链和二层网络扩展解 使用链桥可以将资产转移到不同区块链。 下面是一些可以帮助你找到并使用链桥的资源: -- **[L2BEAT 链桥摘要](https://l2beat.com/bridges/summary) & [L2BEAT 链桥风险分析](https://l2beat.com/bridges/summary)**:各种链桥的全面汇总,包括有关市场份额、链桥类型和目的地区块链的详细信息。 L2BEAT 还对链桥进行风险分析,帮助用户在选择链桥时做出明智的决策。 -- **[DefiLlama 链桥摘要](https://defillama.com/bridges/Ethereum)**:跨以太坊网络的链桥交易量摘要。 +- **[L2BEAT 链桥摘要](https://l2beat.com/bridges/summary)和[L2BEAT 链桥风险分析](https://l2beat.com/bridges/summary)**:各种链桥的全面摘要,包括有关市场份额、链桥类型和目标链的详细信息。 L2BEAT 还对链桥进行风险分析,帮助用户在选择链桥时做出明智的决策。 +- **[DefiLlama 链桥摘要](https://defillama.com/bridges/Ethereum)**:以太坊各个网络的链桥交易量摘要。 -## 使用桥梁的风险 {#bridge-risk} +## 使用链桥的风险 {#bridge-risk} 桥梁正处于开发的早期阶段, 很可能尚未发现最佳桥梁设计。 与任何类型的桥梁互动都有风险: -- **智能合约风险 —** 代码中的错误可能导致用户资金丢失的风险 -- **技术风险 —** 软件故障、代码错误、人为错误、垃圾邮件和恶意攻击可能会扰乱用户操作 +- \*\*智能合约风险——\*\*代码漏洞可能导致用户资金损失的风险。 +- \*\*技术风险——\*\*软件故障、有漏洞的代码、人为失误、垃圾信息和恶意攻击都可能干扰用户操作。 此外,由于需信任桥梁增加了信任假设,因此会带来额外的风险,例如: -- **审查风险 —** 桥梁运营商理论上可以阻止用户使用桥梁转移资产 -- **保管风险 —** 桥梁运营商可以串通盗取用户资金 +- \*\*审查风险——\*\*理论上,链桥运营商可以阻止用户使用链桥转移资产。 +- \*\*托管风险——\*\*链桥运营商可以合谋盗取用户资金。 如果出现以下情况,用户的资金将面临风险: @@ -129,16 +129,17 @@ _Web3 已经发展成为一个由一层网络区块链和二层网络扩展解 - 桥梁运营商对需信任桥梁有恶意 - 桥梁被非法侵入 -最近的一次黑客攻击是 Solana 的虫洞桥,[在黑客攻击期间被窃取了 12 万 包装以太币(3.25 亿美元)](https://rekt.news/wormhole-rekt/)。 [区块链中的许多顶级黑客攻击都涉及到桥梁](https://rekt.news/leaderboard/)。 +最近的一次黑客攻击事件是 Solana 的 Wormhole 链桥,[在这次攻击中,12 万 wETH(价值 3.25 亿美元)被盗](https://rekt.news/wormhole-rekt/)。 [区块链领域很多大型黑客攻击事件都与链桥有关](https://rekt.news/leaderboard/)。 -桥梁对于让用户加入以太坊二层网络至关重要,甚至对于想要探索不同生态系统的用户也至关重要。 然而,鉴于与桥梁交互所涉及的风险,用户必须了解桥梁正在做出的权衡取舍。 这些是一些确保[跨链安全的策略](https://blog.debridge.finance/10-strategies-for-cross-chain-security-8ed5f5879946)。 +桥梁对于让用户加入以太坊二层网络至关重要,甚至对于想要探索不同生态系统的用户也至关重要。 然而,鉴于与桥梁交互所涉及的风险,用户必须了解桥梁正在做出的权衡取舍。 以下是一些[跨链安全策略](https://debridge.com/learn/blog/10-strategies-for-cross-chain-security/)。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} + - [EIP-5164:跨链执行](https://ethereum-magicians.org/t/eip-5164-cross-chain-execution/9658) - _2022 年 6 月 18 日 - Brendan Asselstine_ -- [二层网络桥梁风险框架](https://gov.l2beat.com/t/l2bridge-risk-framework/31) - _2022 年 7 月 5日 - Bartek Kiepuszewski_ -- [“为什么未来将出现多链,而不会是跨链。”](https://old.reddit.com/r/ethereum/comments/rwojtk/ama_we_are_the_efs_research_team_pt_7_07_january/hrngyk8/) - _2022 年 1 月 8 日 - Vitalik Buterin_ -- [利用共享安全实现安全的跨链互操作性:Lagrange 状态委员会及其扩展](https://web.archive.org/web/20250125035123/https://research.2077.xyz/harnessing-shared-security-for-secure-blockchain-interoperability) - _2024 年 6 月 12 日 - Emmanuel Awosika_ +- [L2 链桥风险框架](https://gov.l2beat.com/t/l2bridge-risk-framework/31) - _2022 年 7 月 5 日 - Bartek Kiepuszewski_ +- [\"为什么未来将是多链,但不会是跨链。\"](https://old.reddit.com/r/ethereum/comments/rwojtk/ama_we_are_the_efs_research_team_pt_7_07_january/hrngyk8/) - _2022 年 1 月 8 日 - Vitalik Buterin_ +- [利用共享安全实现安全的跨链互操作性:Lagrange 状态委员会及其他](https://web.archive.org/web/20250125035123/https://research.2077.xyz/harnessing-shared-security-for-secure-blockchain-interoperability) - _2024 年 6 月 12 日 - Emmanuel Awosika_ - [Rollup 互操作性解决方案的现状](https://web.archive.org/web/20250428015516/https://research.2077.xyz/the-state-of-rollup-interoperability) - _2024 年 6 月 20 日 - Alex Hook_ diff --git a/public/content/translations/zh/community/code-of-conduct/index.md b/public/content/translations/zh/community/code-of-conduct/index.md index 1f2db077a45..7ce8612c2b1 100644 --- a/public/content/translations/zh/community/code-of-conduct/index.md +++ b/public/content/translations/zh/community/code-of-conduct/index.md @@ -1,10 +1,10 @@ --- -title: 行为守则 -description: 我们在以太坊社区中严格恪守的准则 +title: "行为守则" +description: "我们在 ethereum.org 各个空间努力遵循的基本标准。" lang: zh --- -# 行为守则 {#code-of-conduct} +# 行为准则 {#code-of-conduct} ## 使命 {#mission} @@ -12,7 +12,7 @@ lang: zh ## 价值观 {#values} -Ethereum.org 社区致力于实现: +ethereum.org 社区致力于实现: - 教育性,旨在帮助每个人了解以太坊 - 包容性 @@ -21,15 +21,15 @@ Ethereum.org 社区致力于实现: - 专注于以太坊的基础技术和用例 - 专注于以太坊的概念和设计原则 -## 我们不是 {#what-we-are-not} +## 我们不是什么 {#what-we-are-not} - 以太坊基金会网站 - 鼓吹投资或牟取暴利的平台 -- 鼓励或支持个别项目或组织的平台 -- 去中心化交易所、中心化交易所或任何其他形式的金融平台 -- 提供任何类型的财务或法律建议的平台 +- 为单个项目或组织站台或背书的平台 +- DEX、CEX 或任何其他形式的金融平台 +- 提供任何类型财务或法律建议的平台 -## 行为守则 {#code-of-conduct} +## 行为准则 {#code-of-conduct} ### 承诺 {#pledge} @@ -37,9 +37,9 @@ Ethereum.org 社区致力于实现: ### 适用范围 {#scope} -本行为准则适用于所有 ethereum.org 空间(如 GitHub、Discord、Figma、Crowdin、Twitter 和其他在线平台),也适用于在现实世界的公共场所(如聚会、会议和活动)代表社区的情况。 +本行为准则适用于所有 ethereum.org 空间(如 GitHub、Discord、Figma、Crowdin、X(前身为 Twitter)和其他在线平台),也适用于在现实世界的公共场所(如聚会、会议和活动)代表社区的情况。 -### 我们的准则 {#our-standards} +### 我们的标准 {#our-standards} 下面是一些有助于创造积极环境的行为范例: @@ -48,30 +48,30 @@ Ethereum.org 社区致力于实现: - 优雅地接受并/或以同理心提供建设性批评 - 冷静专业地处理争议或分歧 - 对其他社区成员展现同理心以及友善包容的态度 -- 鼓励和支持社区中的新奇观点 +- 鼓励并放大社区中的新声音 -禁止参与者进行以下不端行为: +参与者的不当行为示例包括: - 任何形式的身体暴力,以身体暴力相威胁或鼓动身体暴力 -- 使用性挑逗的语言或图像,或存在冒犯性的性企图 +- 使用性暗示的语言或图像,或强行施加不受欢迎的性关注。 - 冒充他人或虚假宣称与某个个人或组织有关联。 - 嘲弄、侮辱/诋毁性评论,以及人身或政治攻击 - 在公共或私密频道对其他社区成员进行骚扰 - 未经明确许可发布他人的私人信息,如住址或电子邮箱 - 社会工程学攻击、欺骗或以其他方式操控其他社区成员 - 以为个人谋取金钱或非金钱收益为目的,鼓吹投资、代币、项目等 -- 发布与主题无关内容,对服务器进行垃圾邮件攻击 +- 用与主题无关的内容在服务器中刷屏 - 无视社区管理员的要求或警告 - 进行其他任何被视为在专业场合不适宜的行为 ### 举报 {#reporting} -通常情况下,违反行为准则的行为会引起社区关注,因为我们致力于通过公开透明的渠道处理事务,并鼓励社区成员进行自我监督。 +违反行为准则的行为通常对社区是可见的,因为我们尝试在开放的公共渠道中做所有事,允许社区成员自我监督。 然而,如果你发现了需要关注的事情,可以向担任管理职责的人(例如,discord 督导)提出,这样他们就可以帮助调查并做出适当的响应。 -举报时,请尽量多提供细节,包括描述具体的事情和发生时间等。 这将有助于获得公正的结果。 +举报时,请尽量多提供细节,包括具体示例和时间戳。 这将有助于确保一个公正的结果。 -### 惩罚措施 {#enforcement} +### 执行 {#enforcement} 根据严重程度不同,违反行为准则的人会受到 ethereum.org 社区的警告、暂时或永久封禁。 diff --git a/public/content/translations/zh/community/events/index.md b/public/content/translations/zh/community/events/index.md index 783d50e7e6e..8fe50e44aac 100644 --- a/public/content/translations/zh/community/events/index.md +++ b/public/content/translations/zh/community/events/index.md @@ -1,26 +1,38 @@ --- -title: 以太坊活动 -description: 如何加入以太坊社区。 +title: "发现社区活动和社区中心" +description: "如何加入以太坊社区。" lang: zh hideEditButton: true --- -# 活动预告 {#events} +# 发现社区活动和社区中心 {#discover-community-events-and-community-hubs} -**每个月,世界各地都会举办大型以太坊活动。**你可以考虑参加附近的一个活动,认识更多的社区成员,了解就业机会,并培养新的技能。 +以太坊因人而生—从小型见面会和社区聚会到大型会议、黑客松,以及巩固世界各地本地生态系统的永久性社区中心。 - +每个联合办公日、见面会或活动都是一个学习新知识、结识志同道合的人、分享想法以及就塑造我们未来的真实项目开展合作的机会。 无论您是开发者、研究员、设计师,还是只是好奇,总有一个地方让您交流、贡献和成长。 -这是一个由我们社区维护的不完整列表。 想要将了解到的即将举行的以太坊活动添加到此列表? [请添加](https://github.com/ethereum/ethereum-org-website/blob/dev/src/data/community-events.json)! +💡 想要组织活动,或是有社区相关的想法? 请向遍布世界的以太坊团队寻求支持! → [在此处联系我们](https://docs.google.com/forms/d/e/1FAIpQLSeA-W8iy2PJxrY3TD4lMYXyky_wLd4QB_7NRwqSxCd0e19MUg/viewform) - +想发现您所在地区的以太坊活动或社区中心吗? 查看下面的列表,寻找您的下一次见面会、联合办公日或聚会! + +## 以太坊社区中心 {#ethereum-community-hubs} + +以太坊社区中心是永久性的包容空间,可用作联合办公区、定期举办活动,并作为创新和知识中心,以激发合作,建立强大、互联的本地生态系统。 + +无论您是本地人、数字游民还是临时居民,都可以参加联合办公会议、研讨会和见面会,发现机会,甚至举办自己的活动。 每个社区中心都有自己的注册流程——您可以在下面找到更多信息和链接。 + + -## 以太坊聚会 {#meetups} +## 以太坊社区活动 {#ethereum-community-events} + + + +这是一个由我们社区维护的不完整列表。 想要将了解到的即将举行的以太坊活动添加到此列表?[请在此添加](https://github.com/ethereum/ethereum-org-website/blob/dev/src/data/community-events.json)! + +## 以太坊见面会 {#meetups} 找不到适合你的活动? 尝试加入一个聚会。 聚会是指由各个以太坊爱好者团体举办的小型活动——这是对以太坊感兴趣的人们聚集在一起的机会,他们可以一起谈论并了解以太坊的最新发展。 -有兴趣举办自己的聚会? 查看 [BUIDL 网络](https://consensys.net/developers/buidlnetwork/),这是由 ConsenSys 发起的一项举措,旨在帮助支持以太坊的各个聚会社区。 - -这是一个由我们社区制定的不完整列表。 你可以[在此处查找更多以太坊聚会](https://www.meetup.com/topics/ethereum/)。 想要将了解到的活跃聚会小组添加到此列表? [请添加](https://github.com/ethereum/ethereum-org-website/blob/dev/src/data/community-meetups.json)! + diff --git a/public/content/translations/zh/community/events/organizing/index.md b/public/content/translations/zh/community/events/organizing/index.md new file mode 100644 index 00000000000..8fff6a66203 --- /dev/null +++ b/public/content/translations/zh/community/events/organizing/index.md @@ -0,0 +1,221 @@ +--- +title: "组织一次以太坊事件" +description: "如何组织一次以太坊活动" +lang: zh +hideEditButton: true +--- + +# 如何组织一次以太坊活动{#how-to-organize-an-ethereum-event} + +建立强大且充满活力的社群是以太坊生态系统成长的核心。 无论您是打算组织聚会、研讨会或大型会议,活动的成功举办都有赖于当地社交网络的连接与参与。 这个指南将协助您为一个活跃的以太坊社群奠定基础,并一步一步带领您组织一个难忘又有影响力的会议。 + +## 问问自己,有以太坊社群吗? {#ask-yourself-is-there-an-ethereum-community} + +一个成功的以太坊会议建立在一个活跃且参与度高的社群上。 如果你已经有了一个社群,那你就率先走在了这场游戏的前列——但如果你还没有,最重要的前期步骤就是打好这个基础。 重要的是要区分一个现场和社区:现场可能包括某个领域的公司和个人,但他们往往独立运作,只是偶尔联合开展活动--就像许多地方的传统web2生态系统一样。 另一方面,社区是一个由相互联系的人们和组织构成的网络,他们相互协作、相互支持,这在web3生态系统中经常可以看到。 + +**你的第一步应该是:** + +- 探索当地的初创企业和公司——在你所在的城市或国家拥有强大、活跃的公司往往是建立社区最关键的先决条件。 +- 查看是否已经有一些聚会——以太坊官网[活动页面](https://ethereum.org/community/events/) +- [以太坊官网](https://ethereum.org/community/events/) 和 ethereum.org Discord——查看当地是否有以太坊的活动、开发者和贡献者。 +- Luma 和 Meetup.com——查看您所在地区是否有与以太坊相关的活动或更广泛的 Web3 活动。 +- X——尽量在Spaces上寻找支持者或有影响力的人。 + +如果您发现了这些要素中的大多数,这就充分说明已经具备了建立社区的条件,但并不一定说明社区已经可以建立起来了。 下一步的关键工作是组织、吸引和培养这些参与者,为合作和长期发展创造机会。 + +### 如果没有这些要素,如何构建社群 {#if-not-how-to-build-it} + +如果你发现缺少许多要素,不要担心——从头开始建立一个社群是一个充满挑战但回报丰厚的过程。 一个强大的以太坊社区不会一蹴而就;它需要耐心、一致性和清晰的愿景。 您可以从这些步骤开始: + +- **建立一个交流渠道**——可以是 Telegram、Signal、WhatsApp、微信或 Discord 服务器,只要是你所在的地方比较流行的媒体,人们就可以由此联系、提问和共享资源。 +- \*\* 找到你的早期使用者\*\* 找出一些对以太坊和 Web3 充满热情的人。 他们将成为你的核心支持者和合作伙伴。 +- **举办小型、定期的活动。** 从非正式的聚会、学习小组或工作坊开始。 一致性是关键——即使初期规模不大,定期举办活动也能建立信任并形成势头。 +- **尝试联系当地企业**、教育机构或共享办公空间,看能否获得免费场地支持。 若无法在本国找到演讲者,可邀请线上的演讲者,但需线下聚集人群。 让观众聚集在同一个物理空间至关重要。 +- \*\*与现有技术社群合作。\*\*若已有开发者团体、初创企业生态圈或区块链聚会活动,可与其建立合作关系,引入以太坊相关议题并扩大影响力。 +- **分享关于以太坊潜力的教育内容**。 +- **拓展全球社群网络。** 联系全球成熟的以太坊团体与项目,获取支持、指导及潜在合作机会。 全球以太坊社区至少有一个共同点:他们都热衷于提供帮助。 +- **尝试争取资金支持**——无论是来自本地Web3企业,还是通过某些资助项目,例如[ESP](https://esp.ethereum.foundation/)。 + +### 如果成功获取了资金,如何维持并扩大规模 {#if-yes-how-to-maintain-and-grow-it} + +建立了社群之后,工作也就不会停止——事实上,这才刚刚开始。 要保持社区活跃、参与度高且持续发展,需要持续的努力和创造力。 保持社区参与的关键要素之一,就是你应该不断尝试新的形式和创意。 + +以下是一些保持以太坊社区蓬勃发展的策略: + +- **丰富活动形式:** 不要只局限于一种聚集的模式。 通过线下聚会、简短的黑客松、专题讨论会和社交活动来搞点新花样。 你可以尝试组织大家一同工作的日子或教育课程。 +- \*\*拓展议题:\*\*以太坊不仅是一项技术,更是一套涵盖法律、营销和商业领域的价值体系。 +- **询问你社区**的反馈和想法。 +- **与不同受众群体互动**。 根据受众差异化的经验水平定制内容和活动——从初次探索以太坊的新手,到经验丰富的开发者和创业者。 + +通过提供多样化的学习、协作与成长机会,您能确保社区保持活跃状态,随时准备迎接更大型的活动,例如组织会议。 + +## 活动{#event} + +### 何时是举办活动的最佳时机? {#when-is-the-right-time-to-organize-an-event} + +成功举办以太坊会议或社区活动需要精心安排时间且考虑周全。 恰当的时机取决于多种因素,这些因素共同促成了活动从整体上来说的成功。 + +你应综合考量社区发展成熟度、市场环境、团队组建情况以及当地生态圈的活跃度(例如潜在赞助商资源)。 + +### KYC — 了解你的社区 {#kyc-know-your-community} + +组织活动最重要的步骤之一就是了解你的社区。 正如金融服务中的“了解你的客户”(KYC),“了解你的社区”(KYC)意味着花时间去理解本地受众的具体需求、偏好和特征。 这种理解将有助于您量身定制会议内容,确保其成功与内容相关性。 + +虽然立即策划大型活动听起来颇具诱惑,但从小的活动着手往往是最佳策略。 若你客观审视社区的现状及某些看似无关的因素——例如:你的国家是否是热门旅游目的地,或者住宿的成本怎么样——你自会明白何为最佳解决方案。 + +在第一年,你的受众群体主要来自本地社区,因此筹办大型活动时,所有工作都应围绕该社区的需求和规模展开。 + +### 从哪里开始 {#where-to-start} + +在筹办会议时,最初要做什么往往令人不知所措。 但只要制定清晰的计划和框架,你就能将整个过程分解为可控的任务。 我们将逐一分析它们。 + +采用结构化的方法开始筹备,将有助于你在推进活动筹备的各个阶段时保持清晰的条理,从而减轻压力。 您所做的每个决定都应让您更接近于提供满足社区需求的体验。 + +**首要任务是组建一支职责分工明确的组织团队。** + +在开始构建程序或联系赞助商之前,另一个重要步骤是选择日期。 虽然这听起来像是一个简单的步骤,但在实施之前,你应该考虑几个重要的因素。 其中的一些因素是: + +- **避免与重要会议或活动日期冲突** +- **考虑当地条件和情况**(例如一年中的季节、主要节日等) +- **考虑市场条件** +- **给自己充足的时间来安排一切**——至少九个月 + +### 如何组建一个团队 {#how-to-assemble-a-team} + +选择那些与你志同道合、能互补你技能的人。 有些团队以集体形式运作,有些则设有明确分工——找出最适合你的方式。 保持定期沟通并明确期望至关重要。 尽管人们很想依赖通讯平台来策划活动,但我们建议选择任务管理平台(例如Notion、Basecamp、Trello、Asana,甚至经典的Google表格)来统筹安排并追踪各项待办事项。 拥有一个运作良好且组织有序的团队至关重要。 + +不同的以太坊组织团队在各自团队中承担着不同的职责,但都包含负责后勤、预算、市场营销、项目策划、设计以及合作伙伴关系的人员。 + +### 活动方案:成功活动的关键要素{#the-program-a-key-element-of-a-successful-event} + +要举办一场真正有价值且令人难忘的会议,**议程安排至关重要**。 在这个领域,你绝不能有丝毫妥协。 虽然赞助商对活动融资至关重要,但观众的体验及其获得的价值必须始终优先考虑。 充斥着过量宣传内容和无休止赞助商推销的活动安排,不仅会使你同观众疏远,更会损害活动的公信力。 + +每次会议、专题讨论和工作坊都应让社区成员获得信息、受到启发并积极参与。 倾听受众的心声——了解他们的兴趣、需求和面临的挑战。 哪些主题能够引起他们的共鸣? 同时,引入新颖视角和创新形式,保持节目的活力。 在熟悉主题与热门话题之间取得平衡,融入前沿理念,确保议程全面覆盖以太坊生态系统的差异化维度——从技术深度解析、社区建设研讨会,到政策讨论与实践工作坊。 此外,还需考虑会议的语言——尽管英语是大多数以太坊活动的默认语言,但提供本地语言的会议环节能让活动更便于区域开发者和爱好者参与。 + +\*\*在挑选演讲嘉宾时,应至少在会议召开前六个月启动征集流程,以吸引高质量的投稿并为议程策划预留充足时间。\*\*负责嘉宾筛选的人员需具备丰富的行业经验,并对生态系统有深刻理解。 这确保他们能够识别有价值、有见地的贡献,并保持内容的高标准。 + +### 在哪里寻找经济支持{#where-to-find-financial-support} + +举办一场高质量的会议需要承担高昂的成本——场地租赁、宣传物料、餐饮服务、活动制作以及其他无数开支。 尽早获得资金支持至关重要,这能确保活动达到专业水准,并为参与者提供卓越的体验。 + +#### 如何创建赞助演示文稿? {#how-to-create-a-sponsorship-deck} + +首先,你需要一个演示文稿。 **向其他会议组织者寻求建议**,甚至请他们分享演示文稿,以便你据此设计自己的方案。 在定价方面,你应该保持务实态度,目标是覆盖成本而非盈利,尤其是在起步阶段。 + +**每份赞助方案都应清晰有力地概述活动概况**,确保潜在赞助商充分理解活动的规模、重点及价值。 从基础要素入手——场地、日期以及组织团队的详细信息——以建立可信度。 然后,突出该活动的核心主题,因为不同的以太坊会议面向不同的受众群体。 有些社区高度侧重建设者,以深入的技术讨论为特色;而另一些则可能更关注DeFi、DAO或政策议题。 + +不仅要描述活动本身,还要设定明确的期望。 请概述预计参会人数及已确认的关键演讲嘉宾,这有助于赞助商评估其潜在影响力。 最重要的是,明确界定赞助方将获得的回报——展位空间、演讲机会、社交媒体推广、品牌曝光度或专属人脉资源。 精心设计的演示文稿不仅能向潜在赞助商传递信息,更能激发他们参与活动的热情。 + +#### 谁可能会支持你的活动? {#who-might-support-your-event} + +首先,联系您所在城市或国家内以太坊及更广泛技术生态系统中的企业。 这些**组织通常对支持促进社区发展和创新的本地活动有着既得的利益**。 他们也更可能认识到投资本地生态系统的价值,并将您的会议视为与人才、合作伙伴及用户建立联系的契机。 + +一旦你获得了本地支持,就可以将你的影响力扩展到Web3领域的全球参与者。 **成熟的协议、DAO及生态系统基金通常会为社区驱动的活动分配预算**。 对于初次承办活动的组织者而言,这可能颇具挑战性——毕竟他们尚未建立可展示的活动记录。但请尝试精心设计一份引人入胜的赞助方案,清晰阐明支持活动的益处:品牌曝光度、演讲机会以及与目标受众建立有意义的互动。 尝试发掘你与众不同的、他人所不具备的独特价值。 + +#### 其它的活动资金的筹措方式 {#alternative-forms-of-funding-your-event} + +拨款是另一种潜在的资金来源,许多组织者往往忽视了这一点。 诸如以太坊基金会推出的[生态系统支持计划](https://esp.ethereum.foundation/)(ESP)以及[其他资助项目](https://ethereum.org/community/grants/#ethereum-grants)等计划,旨在支持社区主导的活动。 + +除资金赞助外,还可考虑实物合作,特别是在食品饮料方面的合作。 与当地文化或科技社群契合的品牌,可成为您活动的绝佳合作伙伴。 咖啡品牌、饮料公司甚至本地披萨店都可能愿意提供产品,以换取在活动中的曝光机会。 这些合作有助于降低成本,同时提升参会者的体验。 + +既然谈到经济问题,请牢记:每投入一美元打造卓越的参会者体验,都将获得指数级的回报。 高品质的制作、舒适的场地、精心准备的礼品以及组织有序的配套活动,共同打造出令人难忘的体验,让参与者在会议结束后仍会津津乐道。 满意的参与者将成为您最忠实的拥护者,并确保活动的长期成功。 + +### 物流{#logistics} + +在确保资金到位的同时,您应将重点放在后勤保障上。 一场组织完善的会议需要在多个领域进行周密规划,从会场布置到参会者体验都需精心安排。 拥有具备扎实活动组织经验的人员——不一定是Web3活动,但必须是活动策划方面的经验——将产生巨大影响。 经验丰富的物流主管能够预见潜在问题,并在问题显现前予以解决,从而节省时间、金钱和精力。 + +负责后勤的人员应选择场地、制作公司以及餐饮、饮料和商品的不同供应商,同时还需配备一个易于使用的在线票务系统,该系统应支持参会者使用加密货币进行注册和支付。 + +### 位置基础设施 {#location-infrastructure} + +在选择会议地点时,重要的是要超越场地本身,考虑更广泛的城市和国家基础设施。 天气、交通便利性、安全保障以及政治环境等因素对塑造参会者体验具有重大影响。 + +对于知名度较低的地方,这一点尤为关键。 来自世界各地的与会者和赞助商需要确信他们能够轻松且安全地出行。 考察机场交通便利性、公共交通系统以及住宿选择等方面的因素。 同时,明智的做法是考虑该地区的文化和政治环境,以避免可能阻碍国际参与者的复杂因素,例如签证政策。 + +### 如何推广活动 {#how-to-promote-the-event} + +有效推广活动是吸引目标受众并营造热烈氛围的关键。 精心设计的推广策略能确保您的会议获得应有的关注度和参与度。 设计在您的品牌建设中同样扮演着重要角色,因此您务必为此预留预算。 + +#### 社交媒体{#social-media} + +X.com将成为您社交媒体推广的核心支柱。 尽量保持活跃并坚持在该平台发帖,同时积极参与各类讨论——既要使用个人账号参与,也要通过组织账号参与互动。 + +尽管领英听起来并非最显而易见的推广选择,但你可以在那里接触到完全不同的受众群体,甚至吸引到一些赞助商。 + +#### 与其他以太坊社区的合作 {#partnerships-with-other-ethereum-communities} + +与不同以太坊组织者的合作能借助现有网络扩大影响力,尤其当你从零起步时。 提供社区折扣,与其他活动进行交叉推广,并邀请合作伙伴共同举办配套活动或工作坊。 + +#### 大学宣传 {#university-outreach} + +通过学生社团或教授联系当地理工科和经济学院系,推广本次活动。 与高校开展合作有助于吸引青年人才、研究人员及未来行业专业人士,从而加强学术界与以太坊生态系统的联系。 这对于组织黑客松活动尤为理想,学生们往往能带来新颖的创意、饱满的热情以及扎实的技术基础。 + +#### 媒体{#media} + +联系专注于Web3领域的媒体机构和通讯刊物,争取活动报道。 尽管Web3媒体通常期望为其公关文章收取费用,但若您没有预算进行付费推广,也可以提供免费门票或安排与知名演讲嘉宾及赞助商的专访机会。 创建一个公关资料包,内含新闻稿及若干视觉素材,以便在社交媒体或网站上以不同格式进行推广。 此外,还应扩大合作范围,涵盖本地记者乃至内容创作者(只要他们具备良好声誉),只要他们能报道科技领域,这对于向更广泛的受众展示活动至关重要。 这有助于弥合加密行业与广大公众之间的鸿沟,吸引主流科技和商业圈的关注。 + +### 你应该组织一个黑客松吗? {#should-you-organize-a-hackathon-as-well} + +组织黑客松活动具有多重益处,因为这类活动既能有效凝聚开发者社群,又能激发创新活力。 它还提供了实践机会,让参与者能够协作并构建项目,这些项目有望为生态系统带来切实成果。 黑客松吸引了那些通常不参加会议但热衷于构建和测试新想法挑战的开发者。 如果您的会议面向开发者、创新和实践项目,举办黑客松是绝佳选择。 + +但在组织活动之前,请考虑你是否有足够的资源和时间。 黑客松需要投入大量时间、人力和资金资源。 确保您有专门的团队来处理此事,尤其是在您同时负责管理会议的情况下。 另外,检查你的社区是否有兴趣。 如果你的社区更侧重建设者,那么组织黑客松或许更有意义。 + +尽管组织黑客松有诸多益处,但请注意:根据会议规模的不同,增加这项活动可能会令人应接不暇。 你应该评估同时管理两者是否会降低其中任何一方的质量。 您可选择举办规模较小、主题聚焦的黑客松,或将活动分散在不同月份举行。 + +### (几乎不可避免)你将面临的挑战 {#almost-inevitable-challenges-that-you-will-face} + +在组织会议时,尤其是以太坊领域的会议,最大的挑战之一就是确保获得足够的资金。 许多活动组织者都面临着筹集资金的困境,这些资金用于支付场地费用、餐饮服务及其他后勤开支。 赞助往往至关重要,但建立关系并说服企业投资你的活动可能需要时间。 此外,在市场低迷时期,吸引赞助商的难度可能会增加,因为企业可能不太愿意投资于非核心业务。 + +有效地管理预算是关键。 **意外开支**,例如临时变更场地和额外的活动技术需求,可能迅速超出预算。 + +对于新活动而言,**邀请高质量演讲者尤其困难**。 以太坊领域中有名的思想领袖或意见领袖可能日程安排已满,对于缺乏成功案例的新活动,他们可能会犹豫是否参与。 请提前做好准备,在活动开始前就投入时间进行人脉拓展,并联系潜在的演讲嘉宾。 + +此外,在与演讲者沟通时,务必保持清晰且持续的交流——明确设定提交演示文稿的截止日期,并避免任何临时变更。 + +一场成功的会议需要一支专业团队来统筹后勤保障、市场推广、赞助商对接、技术支持及参会者管理等各项工作。 寻找具备科技活动组织经验的人选颇具挑战性,尤其当预算有限——或者更常见的是根本没有预算,只能依靠志愿者参与时。 + +### 你不应该独自做这件事。 你需要志愿者们。 {#you-shouldnt-do-it-alone-you-need-volunteers} + +组织以太坊活动需要一支多元化且敬业的团队来处理后勤保障、注册管理、演讲者协调、参会者支持等诸多事务。 团队规模仅为3至15人的时候,志愿者对活动的顺利开展至关重要。 + +志愿者往往是许多会议的中流砥柱,提供关键支持,尤其是在预算有限的情况下。 他们能够胜任从接待登记到协助活动布置的各项工作,确保活动尽可能顺利进行。 + +虽然向志愿者提供金钱补偿存在困难,但必须给予他们有价值的回报,使他们的付出获得应有的回报。 考虑为他们提供人脉拓展机会、技能提升培训、专属福利、证书或推荐信。 + +### 活动组织者合规要点 {#compliance-essentials-for-event-organizers} + +在组织活动时,有几个重要的法律和后勤问题需要注意: + +- **赞助协议**——确保与赞助商签订明确的合同,其中应包含清晰界定的取消条款。 +- **行为准则** ——根据活动类型(会议/黑客松、黑客之家等)制定相应的行为准则。 +- **隐私政策** – 为您的网站起草隐私政策,以符合数据保护法规及图像使用规范 +- **地方当局通知**——即使您的活动属于封闭式聚会,也建议向当地警察局进行申报。 +- **票务协议** – 与您的票务服务提供商签订正式协议,以明确条款和责任。 +- **合规要求** – 提前确认会议举办国是否对加密货币行业设有特定法规或限制 +- **商品清关** – 若您需进口赞助商品,建议聘请报关行以高效完成清关流程。 +- **摄影与媒体政策** – 明确规定摄影及媒体报道的准则,确保参与者知晓同意权及退出选项。 + +## 活动之后:接下来是什么? {#after-the-event-whats-next} + +活动结束后,务必收集参会者、演讲嘉宾和赞助商的反馈意见,并撰写内部报告,以便为未来的活动做好更充分的准备。 这能够帮助识别哪些部分做的好,哪些部分需要改进。 通过问卷调查或一对一访谈收集宝贵见解,为未来的迭代提供指导。 请务必花时间回顾任何失误或低效环节,这些问题在下次会议中可避免,从而使流程更顺畅。 + +关键是保持势头。 继续与社区保持互动,分享根据他们的反馈所取得的进展,并为下一场活动营造令人兴奋的氛围。 通过维持这种联系,确保会议的影响力超越活动本身,巩固关系并为未来的成功奠定基础。 + +## 致谢 {#acknowledgement} + +衷心感谢所有为本文贡献见解的同仁:来自布拉迪斯拉发以太坊的斯拉沃·法比西克;来自Kipu以太坊和拉丁美洲以太坊的萝拉;来自贝尔格莱德以太坊的坦雅·姆拉德诺维奇;来自波哥大以太坊的胡安·大卫;来自华沙以太坊的莫妮卡·扎伊奇克;来自那不勒斯以太坊的拉斐尔·奥雷菲斯;来自利雅得以太坊的肖武(玲);来自urbe.eth的马可;来自都柏林以太坊的考兰·沃尔什;来自克卢日以太坊的亚历克斯·马莱斯;以及来自斯洛文尼亚以太坊的斯坦科·德维奇。 + +## 资源{#resources} + +播客:如何从头到尾组织和推广一场以太坊活动: + +- [《ETHWarsaw案例研究》,作者:不凡](https://www.youtube.com/watch?v=io2Dx1ouz8o) + +推特空间: + +- [ETH 社区 AMA](https://x.com/NapulETH/status/1905732699094151623) + +文章: + +- [建设ETHKL,作者:Danny H.](https://sekto.tech/ethkl24) +- [POKT活动指南](https://docs.pokt.network/community/pokt-events-playbook) diff --git a/public/content/translations/zh/community/get-involved/index.md b/public/content/translations/zh/community/get-involved/index.md index 224ede519cc..2d4304c504a 100644 --- a/public/content/translations/zh/community/get-involved/index.md +++ b/public/content/translations/zh/community/get-involved/index.md @@ -1,132 +1,132 @@ --- -title: 如何加入? -description: 如何加入以太坊社区。 +title: "我如何参与?" +description: "如何加入以太坊社区。" lang: zh --- -# 如何加入? {#get-involved} +# 我如何参与? 参与方式{#get-involved} 以太坊社区中的成员具有许多不同的背景和技能。 无论你是开发人员、艺术家还是会计师,都可以加入。 以下建议列表可能会帮助你开始加入。 -首先,在我们的[行为准则](/community/code-of-conduct)中,阅读并了解 ethereum.org 的使命和价值观。 +首先,请阅读我们的[行为准则](/community/code-of-conduct),了解 ethereum.org 的使命和价值观。 -## 开发人员 {#developers} +## 开发者 ‍ {#developers} -- 访问 [ethereum.org/developers/](/developers/),了解和尝试使用以太坊 -- 参加你附近的一个 [ETHGlobal](http://ethglobal.co/) 黑客马拉松活动! -- 查看[与你的专业领域或所选编程语言相关的项目](/developers/docs/programming-languages/) -- 观看或参与[共识层和执行层会议](https://www.youtube.com/@EthereumProtocol/streams) -- [生态系统支持计划的愿望清单](https://esp.ethereum.foundation/wishlist/) - 适用于工具、文档和基础设施领域,以太坊生态系统支持计划正在积极寻求这些领域的资助申请 -- [Web3Bridge](https://www.web3bridge.com/) - 加入有抱负的 web3 社区,一起积极寻找、培训和支持整个非洲的数百名开发人员和社区成员 -- 加入[以太币研发 Discord](https://discord.com/invite/VmG7Uxc) -- 加入[以太坊猫牧人组织 Discord](https://discord.com/invite/Nz6rtfJ8Cu) +- 访问 [ethereum.org/developers/](/developers/),了解并尝试以太坊 +- 参加您附近的 [ETHGlobal](http://ethglobal.co/) 黑客马拉松! +- 查看[与您的专业领域或所选编程语言相关的项目](/developers/docs/programming-languages/) +- 观看或参与[共识层与执行层开发者会议](https://www.youtube.com/@EthereumProtocol/streams) +- [生态系统支持计划的愿望清单](https://esp.ethereum.foundation/wishlist/) - 以太坊生态系统支持计划正在积极寻求工具、文档和基础设施领域的资助申请 +- [Web3Bridge](https://www.web3bridgeafrica.com) - 加入这个积极进取的 Web3 社区,参与其在全非洲发掘、培训并支持数百名开发者和社区成员的计划 +- 加入 [Eth R&D Discord](https://discord.com/invite/VmG7Uxc) +- 加入 [Ethereum Cat Herders Discord](https://discord.com/invite/Nz6rtfJ8Cu) -## 研究人员 & 学者 ‍ {#researchers-and-academics} +## 研究人员和学者 ‍ {#researchers-and-academics} 你是否有数学、密码学或经济学方面的背景? 你可能会对以太坊生态系统中正在进行的一些前沿工作感兴趣: -- 加入[以太币研发 Discord](https://discord.com/invite/VmG7Uxc) +- 加入 [Eth R&D Discord](https://discord.com/invite/VmG7Uxc) - 撰写或审查以太坊改进提案 - 撰写以太坊改进提案 - 1. 在[以太坊魔术师](https://ethereum-magicians.org)论坛上提交你的创想 - 2. 查阅 [EIP-1](https://eips.ethereum.org/EIPS/eip-1) - **是的,请阅读_整份_文件。** + 1. 在 [Ethereum Magicians](https://ethereum-magicians.org) 上提交您的想法 + 2. 阅读 [EIP-1](https://eips.ethereum.org/EIPS/eip-1) - **没错,这就是文件的_全部_内容。** 3. 请遵循 EIP-1 中的指导准则。 在撰写提案草案时,请参考 EIP-1。 - - 了解如何成为[以太坊改进提案编辑人员](https://eips.ethereum.org/EIPS/eip-5069) - - 你现在即可对以太坊改进提案进行同行评审! 请参阅[打开带有 `e-review` 标签的同行评审](https://github.com/ethereum/EIPs/pulls?q=is%3Apr+is%3Aopen+label%3Ae-review)。 在 `discussion-to` 链接上提供技术反馈。 - - 参与[以太坊改进提案治理](https://github.com/ethereum-cat-herders/EIPIP) - - 加入[以太坊猫牧人组织 Discord](https://discord.com/invite/Nz6rtfJ8Cu) - - [关于以太坊改进提案的更多信息](/eips/) -- [Challenges.ethereum.org](https://challenges.ethereum.org/) - 一系列高额研究奖金,让你可以赚取超过 $100,000 USD + - 了解如何成为 [EIP 编辑者](https://eips.ethereum.org/EIPS/eip-5069) + - 你现在即可对以太坊改进提案进行同行评审! 查看[带有 `e-review` 标签的开放 PR](https://github.com/ethereum/EIPs/pulls?q=is%3Apr+is%3Aopen+label%3Ae-review)。 在 `discussion-to` 链接中提供技术反馈。 + - 参与 [EIP 治理](https://github.com/ethereum-cat-herders/EIPIP) + - 加入 [Ethereum Cat Herders Discord](https://discord.com/invite/Nz6rtfJ8Cu) + - [关于 EIP 的更多信息](/eips/) +- [Challenges.ethereum.org](https://challenges.ethereum.org/) - 一系列高价值的研究赏金,您可以赚取超过 100,000 美元 - [Ethresear.ch](https://ethresear.ch) - 以太坊的主要研究论坛,也是世界上最具影响力的加密经济学论坛 -- [以太坊基金会研究团队 AMA](https://old.reddit.com/r/ethereum/comments/vrx9xe/ama_we_are_ef_research_pt_8_07_july_2022) - 正在进行中的研究人员问答系列。 下一部分开放时,任何人都可以提出问题。 -- [生态系统支持计划愿望清单](https://esp.ethereum.foundation/wishlist/) - 介绍以太坊生态系统支持计划正在积极征询资助申请的研究领域 -- [AllWalletDevs](https://allwallet.dev) - 供以太坊开发者、设计人员和感兴趣的用户定期聚会和讨论钱包的论坛 +- [以太坊基金会研究 AMA](https://old.reddit.com/r/ethereum/comments/vrx9xe/ama_we_are_ef_research_pt_8_07_july_2022) - 与研究人员持续进行的问答系列。 下一部分开放时,任何人都可以提出问题。 +- [生态系统支持计划的愿望清单](https://esp.ethereum.foundation/wishlist/) - 以太坊生态系统支持计划正在积极寻求资助申请的研究领域 +- [AllWalletDevs](https://allwallet.dev) - 一个供以太坊开发者、设计者和感兴趣的用户定期聚会讨论钱包的论坛 -[探索更多活跃研究领域](/community/research/)。 +[探索更多活跃的研究领域](/community/research/)。 ## 非技术技能组合 ‍ {#non-technical} 如果你不是开发者,可能很难知道以太坊如何入门。 下面提供几项建议以及针对特定专业背景的资源。 -### 在你的城市组织一场小聚会 {#meetups} +### 在您的城市组织一次聚会 {#meetups} - 不知道如何开始? [BUIDL 网络](https://consensys.net/developers/buidlnetwork/)可以提供帮助。 ### 撰写关于以太坊的内容 {#write-content} - 以太坊需要能用通俗易懂的语言阐述以太坊价值的优秀写手 -- 还没有准备好发布自己的文章? 可以考虑丰富社区资源中的现有内容,或者[为 ethereum.org 提出新内容](/contributing/)! +- 还没有准备好发布自己的文章? 考虑为社区资源上的现有内容作出贡献,或[为 ethereum.org 提议新内容](/contributing/)! -### 主动提出为社区电话会议做会议纪要 {#take-notes} +### 主动为社区会议做笔记 {#take-notes} -- 现在有许多开源社区电话会议,有人记录会议纪要将是一个极大的帮助。 如果你感兴趣,请加入 [Ethereum Cat Herders discord](https://discord.com/invite/Nz6rtfJ8Cu),并做简短的自我介绍! +- 现在有许多开源社区电话会议,有人记录会议纪要将是一个极大的帮助。 如果您感兴趣,请加入 [Ethereum Cat Herders discord](https://discord.com/invite/Nz6rtfJ8Cu),并介绍一下自己! -### 将以太坊的相关文章翻译成你的母语 {#translate-ethereum} +### 将以太坊内容翻译成您的母语 {#translate-ethereum} - ethereum.org 具有一个翻译计划,可将网站和其他资源翻译成多种语言 -- 点击[这里](/contributing/translation-program)了解如何参与 +- [在此处](/contributing/translation-program)了解如何参与 -### 运行节点 {#run-a-node} +### 运行一个节点 {#run-a-node} 加入数千位节点运营商的行列,共同加强以太坊的去中心化。 - [关于如何运行节点的更多信息](/developers/docs/nodes-and-clients/run-a-node/) -### 质押你的以太币 {#staking} +### 质押您的 ETH {#staking} 通过质押以太币,你不但可以获得奖励,还能够帮助保护以太坊网络。 -- [有关质押的更多信息](/staking/) +- [关于质押的更多信息](/staking/) -### 资助项目 {#support-projects} +### 支持项目 {#support-projects} 以太坊生态系统的使命是资助公共物品和有影响力的项目。 只需很少的捐赠,你就可以表达自己的支持,并让重要的工作得以完成。 - [Gitcoin](https://gitcoin.co/fund) - [clr.fund](https://clr.fund/#/about) -## 金融专业人士 & 会计师 ‍ {#financial-professionals} +## 金融专业人士和会计师 ‍ {#financial-professionals} -- 以太坊是“去中心化金融”生态系统的发源地,该系统是一个提供替代金融系统的协议和应用程序网络。 如果你是金融专业人士,可以查看 [DeFi Llama](https://defillama.com/) 或 [defprime](https://defiprime.com) 上的一些去中心化金融应用程序 -- 会计师? 以太坊上的资产(以太币、令牌、去中心化金融等)带来了许多新的会计问题。 你可以从查看一些项目开始,帮助加密货币用户克服他们的记账 & 会计挑战,如 [Rotki](https://rotki.com/) +- 以太坊是“去中心化金融”生态系统的发源地,该系统是一个提供替代金融系统的协议和应用程序网络。 如果您是金融专业人士,请在 [DeFi Llama](https://defillama.com/) 或 [DeFiPrime](https://defiprime.com) 上查看一些 DeFi 应用 +- 会计师? 以太坊上的资产(以太币、令牌、去中心化金融等)带来了许多新的会计问题。 您可以从查看一些旨在帮助加密货币用户解决其簿记和会计难题的项目开始,例如 [Rotki](https://rotki.com/) ## 产品经理 ‍ {#product-managers} -- 以太坊生态系统需要有才之士! 许多公司正在招聘产品经理。 如果你想从为开源项目做贡献开始,请联系[以太坊牧猫人组织](https://discord.com/invite/Nz6rtfJ8Cu)或 [RaidGuild](https://www.raidguild.org/) +- 以太坊生态系统需要有才之士! 许多公司正在招聘产品经理。 如果您想从为开源项目做贡献开始,请联系 [Ethereum Cat Herders](https://discord.com/invite/Nz6rtfJ8Cu) 或 [RaidGuild](https://www.raidguild.org/) ## 市场营销 ‍ {#marketing} - 以太坊生态系统中提供了许多市场营销和通信相关的职位! -## 以太坊招聘职位 {#ethereum-jobs} +## 以太坊工作机会 {#ethereum-jobs} -**想在以太坊找到一份工作吗?** +**想在以太坊领域找一份工作吗?** -- [ethereum.org 招聘职位](/about/#open-jobs) -- [以太坊基金会职位公告栏](https://jobs.ashbyhq.com/ethereum-foundation) +- [ethereum.org 工作机会](/about/#open-jobs) +- [以太坊基金会招聘看板](https://jobs.ashbyhq.com/ethereum-foundation) - [JobStash](https://jobstash.xyz) -- [Cryptocurrency 招聘职位](https://cryptocurrencyjobs.co/ethereum/) -- [ConsenSys 职业机会](https://consensys.net/careers/) -- [Crypto 招聘职位列表](https://cryptojobslist.com/ethereum-jobs) -- [Bankless 职位公告栏](https://pallet.xyz/list/bankless/jobs) -- [Web3 招聘职位](https://web3.career) +- [Ethereum Job Board](https://www.ethereumjobboard.com/) +- [Cryptocurrency Jobs](https://cryptocurrencyjobs.co/ethereum/) +- [ConsenSys 职业发展](https://consensys.net/careers/) +- [Crypto Jobs List](https://cryptojobslist.com/ethereum-jobs) +- [Bankless 招聘看板](https://pallet.xyz/list/bankless/jobs) +- [Web3 Jobs](https://web3.career) - [Web3 Army](https://web3army.xyz/) -- [Crypto Valley 招聘职位](https://cryptovalley.jobs/) -- [以太坊招聘职位](https://startup.jobs/ethereum-jobs) +- [Crypto Valley Jobs](https://cryptovalley.jobs/) +- [Ethereum Jobs](https://startup.jobs/ethereum-jobs) -## 加入去中心化自治组织 {#decentralized-autonomous-organizations-daos} +## 加入 DAO {#decentralized-autonomous-organizations-daos} -“DAO”是指去中心化自治组织。 这些团队利用以太坊技术促进组织和协作。 例如,用于成员资格管理、提案投票或联合资产管理。 虽然去中心化自治组织仍处于试验阶段,但它们提供了机会,让你找到自己认同的团队,找到合作者并且扩大自己对以太坊社区的影响。 [更多关于去中心化自治组织的信息](/dao/) +“DAO”是指去中心化自治组织。 这些团队利用以太坊技术促进组织和协作。 例如,用于成员资格管理、提案投票或联合资产管理。 虽然去中心化自治组织仍处于试验阶段,但它们提供了机会,让你找到自己认同的团队,找到合作者并且扩大自己对以太坊社区的影响。 [关于 DAO 的更多信息](/dao/) -- [DAOSquare](https://daosquare.io/) [@DAOSquare](https://twitter.com/DAOSquare) - _在非技术领域推广去中心化自治组织这一概念,帮助人们通过去中心化自治组织创造价值_ -- [Developer DAO](https://www.developerdao.com/) [@developer_dao](https://twitter.com/developer_dao) - _由相信互联网为集体所有的构建者组成的社区_ -- [dOrg](https://dOrg.tech) [@dOrg_tech](https://twitter.com/dOrg_tech) - _以去中心化自治组织形式运行的自由职业者 Web3 开发团队_ -- [HausDAO](https://daohaus.club) [@nowdaoit](https://twitter.com/nowdaoit) - _DAOhaus 社区治理_ +- [DAOSquare](https://daosquare.io/) [@DAOSquare](https://twitter.com/DAOSquare) - _在非技术领域推广 DAO 理念,帮助人们通过 DAO 创造价值_ +- [Developer DAO](https://www.developerdao.com/) [@developer_dao](https://twitter.com/developer_dao) - _一个由相信互联网集体所有权的建设者组成的社区_ +- [dOrg](https://dOrg.tech) [@dOrg_tech](https://twitter.com/dOrg_tech) - _以 DAO 形式运作的 Web3 自由职业开发者团体_ +- [HausDAO](https://daohaus.club) [@nowdaoit](https://twitter.com/nowdaoit) - _DAOhaus 的社区治理_ - [LexDAO](https://lexdao.org) [@lex_DAO](https://twitter.com/lex_DAO) - _法律工程_ -- [MetaCartel Ventures](https://metacartel.xyz) [@VENTURE_DAO](https://twitter.com/VENTURE_DAO) - _为种子阶段前的加密项目提供风险投资_ -- [MetaGame](https://metagame.wtf) [@MetaFam](https://twitter.com/MetaFam) - _面向现实世界的 MMORPG 游戏机制_ -- [MetaFactory](https://metafactory.ai) [@TheMetaFactory](https://twitter.com/TheMetaFactory) - _数字化实体服装品牌_ -- [MolochDAO](https://molochdao.com) [@MolochDAO](https://twitter.com/MolochDAO) - _专注于资助以太坊发展的社区_ -- [Raid Guild](https://raidguild.org) [@RaidGuild](https://twitter.com/RaidGuild) - _由 Web3 构建者组成的团队_ +- [MetaCartel Ventures](https://metacartel.xyz) [@VENTURE_DAO](https://twitter.com/VENTURE_DAO) - _面向种子轮前加密货币项目的风险投资_ +- [MetaFactory](https://metafactory.ai) [@TheMetaFactory](https://twitter.com/TheMetaFactory) - _数字实体服装品牌_ +- [MolochDAO](https://molochdao.com) [@MolochDAO](https://twitter.com/MolochDAO) - _专注于资助以太坊开发的社区_ +- [Raid Guild](https://raidguild.org) [@RaidGuild](https://twitter.com/RaidGuild) - _Web3 建设者团体_ -请记住,无论何时,无论通过何种方式,在为 ethereum.org 做贡献时,都请遵守 ethereum.org [行为准则](/community/code-of-conduct)! +无论何时以何种方式为 ethereum.org 贡献内容,请务必遵守 ethereum.org [行为准则](/community/code-of-conduct)! diff --git a/public/content/translations/zh/community/grants/index.md b/public/content/translations/zh/community/grants/index.md index b58aeaf5957..5cf7d501c7a 100644 --- a/public/content/translations/zh/community/grants/index.md +++ b/public/content/translations/zh/community/grants/index.md @@ -1,6 +1,6 @@ --- -title: 以太坊基金会与社区资助方案 -description: 以太坊生态系统的资助方案清单。 +title: "以太坊基金会与社区资助计划" +description: "以太坊生态系统的资助方案清单。" lang: zh --- @@ -10,38 +10,59 @@ lang: zh 这个列表由我们的社区管理。 如果有内容缺失或错误,请编辑此页面! -## 庞大的以太坊生态系统 {#broad-ethereum-ecosystem} + + +
创始人,需要帮助加速您的业务吗? [前往创始人支持](/founders/)
+
+ +## 广泛的以太坊生态系统 {#broad-ethereum-ecosystem} 这些计划通过向大量项目提供资助来支持庞大的以太坊生态系统。 其中包括可扩容性、社区建设、安全、隐私等解决方案。 这些资助并非专门针对任何一个以太坊平台,如果不确定,可以从这里开始。 -- [以太坊基金会生态系统资助方案](https://esp.ethereum.foundation) - _资助有利于以太坊的开源项目,重点资助通用工具、基础设施、研究和公共物品_ -- [Moloch 去中心化自治组织](https://www.molochdao.com/) - _隐私、二层网络扩容、客户端安全性等_ -- [去中心化自治组织资助](https://docs.google.com/spreadsheets/d/1XHc-p_MHNRdjacc8uOEjtPoWL86olP4GyxAJOFO0zxY/edit#gid=0) - _资助组织的 Google 电子表格_ -- [学术资助](https://esp.ethereum.foundation/academic-grants) - _为以太坊相关学术工作提供资助_ +- [EF 生态系统支持计划](https://esp.ethereum.foundation) - _为有利于以太坊的开源项目提供资金,尤其侧重于通用工具、基础设施、研究和公共物品_ +- [学术资助](https://esp.ethereum.foundation/academic-grants) - _为支持以太坊相关学术工作而设的资助_ + +## 资助列表聚合器和平台 {#grant-list-aggregators} + +这些资源汇总并且整理了以太坊生态系统中的各类资助机会,让你更容易发现与项目需求匹配的资金支持。 我们根据用户特色对它们进行了分类,帮助你根据自身的资金需求快速找到最相关的资源。 + +### 面向所有资助申请者:综合目录 {#comprehensive-directories} + +这类通用平台涵盖了整个 Web3 领域内的各类资助项目,对于任何寻求资金支持的人来说,都是极具价值的起点: + - [Blockworks Grantfarm](https://blockworks.co/grants/programs) - _Blockworks 编译了一份包含所有资助、提案征求和漏洞悬赏的完整名录。_ +- [Blockchain Grants](https://www.blockchaingrants.org/) - _区块链和加密货币资助目录_ +- [Karma Funding Map](https://gap.karmahq.xyz/funding-map) - 所有 Web3 资助计划目录,每周更新 + +### 面向开发者和构建者 {#for-developers-and-builders} + +- [Grant Programs Viewer](https://airtable.com/shr86elKgWTSCP4AY) - _公开的资助项目 Airtable 数据库_ +- [Web3 Grants Spreadsheet](https://docs.google.com/spreadsheets/d/1c8koZCI-GLnD8MG-eFcXPOBCNu1v8-aXIfwAAvc7AMc/edit#gid=0) - _提供 Web3 资助机会的 Google 电子表格_ +- [Arbitrum Grants](https://arbitrum.foundation/grants) — Arbitrum DAO 和 [The Arbitrum Foundation](https://arbitrum.foundation/) + +### 面向 DeFi 项目和金融应用 {#for-defi-projects} + +- [LlamaoGrants](https://wiki.defillama.com/wiki/LlamaoGrants) - _DeFi Llama 的资助计划目录_ +- [AlphaGrowth Grants](https://alphagrowth.io/crypto-web3-grants-list) - _加密货币和 Web3 资助的综合列表_ +- [Uniswap Foundation Grants](https://www.uniswapfoundation.org/build) - _为 DeFi 构建者提供的 Unichain 和 Uniswap v4 资助与支持_ -## 特定项目 {#project-specific} +### 面向 DAO 贡献者和治理创新者 {#for-dao-contributors} -这些项目为旨在开发和实验自己技术的项目建立了自己的资助。 +面向社区驱动项目和治理实验的资源 -- [Aave 资助方案](https://aavegrants.org/) – _[Aave](https://aave.com/) 资助去中心化自治组织_ -- [Balancer](https://grants.balancer.community/) – _[Balancer](https://balancer.fi/) 生态系统基金_ -- [Chainlink 资助方案](https://chain.link/community/grants) - _[Chainlink](https://chain.link/) 社区资助_ -- [Decentraland 资助方案](https://governance.decentraland.org/grants/) – _[Decentraland](https://decentraland.org/) 去中心化自治组织元宇宙_ -- [Lido 生态系统资助组织 (LEGO)](https://lido.fi/lego) – _[Lido](https://lido.fi/) 金融生态系统_ -- [MetaMask 方案](https://metamaskgrants.org/) - _-[MetaMask](https://metamask.io/) 员工主导的资助去中心化自助组织_ -- [SKALE 网络资助方案](https://skale.space/developers#grants) - _[SKALE 网络](https://skale.space/)生态系统_ -- [Swarm 基金会资助计划](https://my.ethswarm.org) - _[Swarm 基金会](https://www.ethswarm.org/)生态系统_ -- [The Graph](https://thegraph.com/ecosystem/grants/) – _[The Graph](https://thegraph.com/) 生态系统_ -- [Uniswap 资助计划](https://www.uniswapfoundation.org/approach) – _[Uniswap](https://uniswap.org/) 社区_ +- [DAO Grants](https://docs.google.com/spreadsheets/d/1XHc-p_MHNRdjacc8uOEjtPoWL86olP4GyxAJOFO0zxY/edit#gid=0) - _提供资助的组织的 Google 电子表格_ +- [MetaGov Database](https://docs.google.com/spreadsheets/d/1e5g-dlWWsK2DZoZGBgfxyfGNSddLk-V7sLEgfPjEhbA/edit#gid=780420708) - _综合 Web3 资助地图_ -## 二次方融资 {#quadratic-funding} +### 公共物品和影响 {#public-goods-and-impact} -以太坊的开源属性催生了一种有趣的新型募资模式:二次方融资。 这有可能改进我们在未来为各种公共产品募资的方式。 二次方募资确保获得最多资金的项目是那些具有最独特需求的项目。 换句话说,就是那些能够改善大多数人生活的项目。 [关于二次方融资的更多信息。](/defi/#quadratic-funding) +这些项目专注于资助那些更广泛的社区、公共产品以及更具影响力的计划。 这些平台包括资助提供方,以及利用链上资金分配机制(包括[二次方募资](/defi/#quadratic-funding))的捐赠平台: -- [Gitcoin](https://gitcoin.co/grants) -- [clr.fund](https://clr.fund/) +- [Gitcoin](https://www.gitcoin.co/program) - _Gitcoin Grants 利用多种资金分配机制为以太坊生态系统中的开源项目和公共产品提供资金_ +- [Octant](https://octant.app/home) - _公共产品资助生态系统,平衡公共利益与个人财务赋能_ +- [Giveth](https://giveth.io/) - _加密捐赠平台,支持公益项目直接捐赠,且不收取任何额外费用_ +- [Artizen](https://artizen.fund/) - _助力创作者对接资源,为艺术、科学、技术与文化前沿领域的新项目提供资金支持_ +- [Quadratic Accelerator](https://qacc.giveth.io/) - _初创企业加速计划,利用二次方募资支持造福公共产品的项目_ ## 在以太坊工作 {#work-in-ethereum} -没有准备好启动你自己的项目? 有数百家公司正在积极寻求热情人士的加入,为以太坊生态系统奉献力量。 正在寻找更多信息? [点击查看更多以太坊相关工作](/community/get-involved/#ethereum-jobs) +没有准备好启动你自己的项目? 有数百家公司正在积极寻求热情人士的加入,为以太坊生态系统奉献力量。 正在寻找更多信息? [查看以太坊相关工作](/community/get-involved/#ethereum-jobs) diff --git a/public/content/translations/zh/community/language-resources/index.md b/public/content/translations/zh/community/language-resources/index.md index 4a9f80f5cd5..34f4ef73543 100644 --- a/public/content/translations/zh/community/language-resources/index.md +++ b/public/content/translations/zh/community/language-resources/index.md @@ -1,6 +1,6 @@ --- -title: 语言资源 -description: 了解关于以太坊的非英文资源 +title: "语言资源" +description: "了解关于以太坊的非英文资源" lang: zh --- @@ -12,7 +12,7 @@ lang: zh 如果你更喜欢用你的母语阅读或者知道某人不会说英语,你可以在下面找到有用的非英语资源列表。 数十万以太坊爱好者齐聚这些在线论坛,分享消息、谈论近来的发展、热烈讨论技术问题并畅想未来。 -知道一个你语言的教育资源? [创建问题](https://github.com/ethereum/ethereum-org-website/issues/new/choose),以将其添加到列表! +知道一个你语言的教育资源? [提交议题](https://github.com/ethereum/ethereum-org-website/issues/new/choose)将其添加到列表中! ## Ethereum.org 资源 {#ethereum-org} @@ -20,7 +20,7 @@ Ethereum.org 已由母语者翻译成 40 多种语言,你可以使用每个页 ![语言选择器菜单](./language-selector-menu.png) -如果你会使用两种语言,而且想帮助我们宣传到更多的人,你也可以参与 [ethereum.org 翻译计划](/contributing/translation-program/#translation-program),帮助我们翻译该网站。 +如果你会使用两种语言,并且想帮助我们惠及更多人,你也可以参与 [ethereum.org 翻译计划](/contributing/translation-program/#translation-program),帮助我们翻译网站。 ## 社区资源 {#community} @@ -28,126 +28,126 @@ Ethereum.org 已由母语者翻译成 40 多种语言,你可以使用每个页 **新闻** -- [BeInCrypto](http://www.beincrypto.com.br) - 提供有关加密货币的新闻和文章,包括一个巴西交易所列表 -- [Cointelegraph](http://cointelegraph.com.br/category/analysis) - 巴西版 Cointelegraph,一个主要的加密货币新闻机构 -- [Livecoins](http://www.livecoins.com.br/ethereum) - 提供有关加密货币的新闻和工具 -- [Seudinheiro](http://www.seudinheiro.com/criptomoedas/) - 提供有关加密货币的新闻和报告 -- [Modular Crypto](https://modularcrypto.xyz/) - 提供加密货币新闻和教育文章 +- [BeInCrypto](http://www.beincrypto.com.br) - 加密货币新闻和文章,包括在巴西可用的交易所列表 +- [Cointelegraph](http://cointelegraph.com.br/category/analysis) - Cointelegraph 巴西版,一个主要的加密货币新闻媒体 +- [Livecoins](http://www.livecoins.com.br/ethereum) - 加密货币新闻和工具 +- [Seudinheiro](http://www.seudinheiro.com/criptomoedas/) - 加密货币新闻和报告 +- [Modular Crypto](https://modularcrypto.xyz/) - 加密货币新闻和教育文章 **教育** -- [web3dev](https://www.web3dev.com.br/) - Web3 开发者们的内容中心和 Discord 社区。 -- [Web3Brasil](https://github.com/web3brasil/web3brasil) - 提供有关 Web3 和去中心化金融的学习资源 -- [CriptoFacil](http://www.criptofacil.com/ultimas-noticias/) - 提供有关加密货币的新闻和教育,包括“以太坊入门”和“去中心化金融入门” -- [CriptoAtivos](http://www.criptoativos.wiki.br/) - 提供来自加密货币空间、教育和博客的洞察 -- [Cointimes](http://www.cointimes.com.br/) - 提供有关加密货币的新闻和教育 -- [Web3 starter pack](https://docs.google.com/document/d/1X8PSTFH7FTw9J-gbKWM6Y430SWCBT8d4t4pJgFQHJ8E/) - 提供有关加密货币最常见和最基础问题解答的指南 +- [web3dev](https://www.web3dev.com.br/) - 面向 Web3 开发者的内容中心和 Discord 社区。 +- [Web3Brasil](https://github.com/web3brasil/web3brasil) - 学习 Web3 和 DeFi 的资源 +- [CriptoFacil](http://www.criptofacil.com/ultimas-noticias/) - 加密货币新闻和教育,包括“以太坊入门”和“DeFi 入门” +- [CriptoAtivos](http://www.criptoativos.wiki.br/) - 加密货币领域的见解、教育和博客 +- [Cointimes](http://www.cointimes.com.br/) - 加密货币新闻和教育 +- [Web3 入门包](https://docs.google.com/document/d/1X8PSTFH7FTw9J-gbKWM6Y430SWCBT8d4t4pJgFQHJ8E/) - 一份指南,解答最常见和最基本的加密问题 ### 中文 {#zh} **通用资源** -- [Ethereum.cn](https://www.ethereum.cn/) - 由社区维护网站内容,内容包括共识层升级、所有核心开发者会议记录、以太坊第二层等 -- [EthFans](https://github.com/editor-Ajian/EthFans.org-annual-collected-works/) - 从以太坊基础知识到高级主题,各种学习材料应有尽有 -- [Untimes](https://mp.weixin.qq.com/s/tvloZSDBSOQN9zDQj_91kA) - 由社区维护内容,内容涵盖以太坊、去中心化金融、非同质化代币和 Web3 相关知识 -- [123ETH](https://123eth.org/) - 以太坊生态系统的一个门户网站 -- [Zhen Xiao(肖臻)](http://zhenxiao.com/blockchain/) - 关于加密货币及其应用的免费在线课程 -- [以太坊白皮书](https://github.com/ethereum/wiki/wiki/[%E4%B8%AD%E6%96%87]-%E4%BB%A5%E5%A4%AA%E5%9D%8A%E7%99%BD%E7%9A%AE%E4%B9%A6) - 以太坊白皮书中文版 +- [Ethereum.cn](https://www.ethereum.cn/) - 社区维护的内容,涵盖共识层升级、所有核心开发者会议记录、Layer 2 等。 +- [EthFans](https://github.com/editor-Ajian/EthFans.org-annual-collected-works/) - 学习从基础到高级的以太坊主题 +- [Unitimes](https://mp.weixin.qq.com/s/tvloZSDBSOQN9zDQj_91kA) - 社区维护的内容,涵盖以太坊、DeFi、NFT、Web3 相关知识 +- [123ETH](https://123eth.org/) - 以太坊生态系统的门户 +- [肖臻](http://zhenxiao.com/blockchain/) - 关于加密货币及其应用的免费在线课程 +- [以太坊白皮书](/zh/whitepaper/) - 以太坊白皮书中文版 **以太坊生态系统** -- [ETHPlanet](https://www.ethplanet.org/) - 可在线或现场参加黑客马拉松,为大学生提供培训 -- [PrimitivesLane](https://www.primitiveslane.org/) - 一个以区块链技术为重点的非营利研究小组 -- [Ethereum Translation Community CN](https://www.notion.so/Ethereum-Translation-Community-CN-05375fe0a94c4214acaf90f42ba40171) - 一个致力于翻译以太坊教育类内容的社区 +- [ETHPlanet](https://www.ethplanet.org/) - 线上和线下黑客松,为大学生提供培训 +- [PrimitivesLane](https://www.primitiveslane.org/) - 一个专注于区块链技术的非营利研究小组 +- [Ethereum Translation Community CN](https://www.notion.so/Ethereum-Translation-Community-CN-05375fe0a94c4214acaf90f42ba40171) - 一个致力于翻译以太坊教育内容的社区 **适用于开发人员** -- [DappLearning](https://github.com/Dapp-Learning-DAO/Dapp-Learning) - 一个学习主流去中心化应用程序项目的学习小组,每周都会分享想法和意见 -- [LearnBlockchain](https://learnblockchain.cn/) - 一个分享区块链技术相关信息的开发者社区 +- [DappLearning](https://github.com/Dapp-Learning-DAO/Dapp-Learning) - 一个学习小组,每周研究主流的去中心化应用程序项目并分享想法和评论 +- [LearnBlockchain](https://learnblockchain.cn/) - 一个面向开发者的社区,分享区块链技术信息 **试用于加密研究人员** -- [安比实验室](https://mp.weixin.qq.com/s/69_tqBJpr_sbaKtR1sBRMw) - 一个解释加密和安全等内容的微信公众号 -- [星想法](https://mp.weixin.qq.com/s/9KgKTc_jtJ7bWKdbNPoqvQ) - 一个解释零知识证明技术的微信公众号 +- [SecbitLabs](https://mp.weixin.qq.com/s/69_tqBJpr_sbaKtR1sBRMw) - 一个微信公众号,讲解密码学、安全等知识。 +- [Sparkbyte](https://mp.weixin.qq.com/s/9KgKTc_jtJ7bWKdbNPoqvQ) - 一个微信公众号,讲解 zk 技术 ### 捷克语 {#cs} -- [Gwei.cz](https://gwei.cz) - 当地 Web3 社区,制作教育内容,组织在线和现场活动 +- [Gwei.cz](https://gwei.cz) - 本地 Web3 社区,创建教育内容,组织线上和线下活动 - [Gwei.cz Příručka](https://prirucka.gwei.cz/) - 以太坊初学者指南 -- [DAO Příručka](https://dao.gwei.cz/) - 去中心化自治组织初学者指南 -- [精通以太坊](https://ipfs.io/ipfs/bafybeidvuxhnsgfx3tncpfxheqglkjwmdxclknlgd7s7qggd2a6bzgb27m) - 精通以太坊(捷克语) +- [DAO Příručka](https://dao.gwei.cz/) - DAO 初学者指南 +- [《精通以太坊》](https://ipfs.io/ipfs/bafybeidvuxhnsgfx3tncpfxheqglkjwmdxclknlgd7s7qggd2a6bzgb27m) - 《精通以太坊》捷克语版 ### 法语 {#fr} -- [Ethereum France](https://www.ethereum-france.com/) - Ethereum France 组织各种活动、制作内容并鼓励围绕以太坊展开讨论 -- [Ethereum.fr](https://ethereum.fr/) - 提供有关以太坊的新闻和教育 -- [BanklessFR](https://banklessfr.substack.com/) - Bankless 新闻通讯(法语) -- [CryptoFR](https://cryptofr.com/category/44/ethereum-general) - 以太坊子页面上的加密货币论坛 +- [Ethereum France](https://www.ethereum-france.com/) - Ethereum France 组织活动、创建内容并鼓励围绕以太坊展开讨论 +- [Ethereum.fr](https://ethereum.fr/) - 以太坊新闻和教育 +- [BanklessFR](https://banklessfr.substack.com/) - Bankless 法语新闻通讯 +- [CryptoFR](https://cryptofr.com/category/44/ethereum-general) - 设有以太坊子页面的加密货币论坛 ### 德语 {#de} - [Microsoft Learn (Solidity)](https://docs.microsoft.com/de-de/learn/modules/blockchain-learning-solidity/) - 使用 Solidity -- [Microsoft Learn(智能合约)](https://docs.microsoft.com/de-de/learn/modules/blockchain-solidity-ethereum-smart-contracts/) - 用 Solidity 编写以太坊智能合约 -- [Microsoft Learn(以太坊网络)](https://docs.microsoft.com/de-de/learn/modules/blockchain-ethereum-networks/) - 连接并部署以太坊网络 -- [Microsoft Learn(区块链)](https://docs.microsoft.com/de-de/learn/paths/ethereum-blockchain-development/) - 区块链开发入门 +- [Microsoft Learn (智能合约)](https://docs.microsoft.com/de-de/learn/modules/blockchain-solidity-ethereum-smart-contracts/) - 使用 Solidity 编写以太坊智能合约 +- [Microsoft Learn (以太坊网络)](https://docs.microsoft.com/de-de/learn/modules/blockchain-ethereum-networks/) - 连接并部署以太坊网络 +- [Microsoft Learn (区块链)](https://docs.microsoft.com/de-de/learn/paths/ethereum-blockchain-development/) - 区块链开发入门 ### 希伯来语 {#he} -- [Udi Wertheimer - 比特币爱好者学习以太坊的基地](https://www.cryptojungle.co.il/udi-wertheimer-what-bitcoiners-can-learn-from-ethereum/) -- [Omer Greismen (OpenZeppelin) - 我们如何防止一个 150 亿美元的智能合约遭受黑客攻击](https://www.cryptojungle.co.il/omer-greisman-openzeppelin/) -- [Shy Datika (INX) - 代币化和证券的未来,包括以太坊是否为一种证券](https://www.cryptojungle.co.il/shy-datika-tokenization/) +- [Udi Wertheimer - 比特币玩家可以从以太坊学到什么](https://www.cryptojungle.co.il/udi-wertheimer-what-bitcoiners-can-learn-from-ethereum/) +- [Omer Greismen (OpenZeppelin) - 我们如何阻止了一场价值 150 亿美元的智能合约黑客攻击](https://www.cryptojungle.co.il/omer-greisman-openzeppelin/) +- [Shy Datika (INX) - 代币化和证券的未来,包括以太坊是否是证券](https://www.cryptojungle.co.il/shy-datika-tokenization/) - [Roy Confino (Lemonade) - 以太坊保险](https://www.cryptojungle.co.il/roy-confino-insurance/) - [Idan Ofrat (Fireblocks) - 机构采用](https://www.cryptojungle.co.il/idan-ofrat-fireblocks/) - [Gal Weizman (MetaMask) - MetaMask 是什么](https://www.cryptojungle.co.il/gal-weizman-metamask/) - [Dror Aviely (Consensys) - 以太坊的中心](https://www.cryptojungle.co.il/dror-aviely-ethereum-center/) -- [Nir Rozin - 成为一名加密朋克](https://www.cryptojungle.co.il/nir-rozin-cryptopunk/) -- [Adan Kedem - 游戏与元宇宙](https://www.cryptojungle.co.il/adan-kedem-web3-gaming/) +- [Nir Rozin - 成为加密朋克](https://www.cryptojungle.co.il/nir-rozin-cryptopunk/) +- [Adan Kedem - 游戏和元宇宙](https://www.cryptojungle.co.il/adan-kedem-web3-gaming/) - [Uri Kolodny (Starkware) - 以太坊和区块链层](https://www.cryptojungle.co.il/uri-kolodny-starkware/) -- [Udi Wertheimer - 以太坊 2.0 和竞争对手](https://www.cryptojungle.co.il/udi-on-eth2/) -- [Ben Samocha(本人) - 以太坊 2.0 是一个机会吗?](https://www.cryptojungle.co.il/etherurm2-week-summary/) -- [Alon Muroch (Bloxstaking) - 以太坊 2.0 是什么?](https://www.cryptojungle.co.il/alon-moroch-eth2/) -- [Eilon Aviv (Collider Ventures) - 以太坊 2.0 可能会出现什么问题](https://www.cryptojungle.co.il/eilon-aviv-eth2-0/) +- [Udi Wertheimer - 以太坊 2.0 与竞争](https://www.cryptojungle.co.il/udi-on-eth2/) +- [Ben Samocha (我本人) - 以太坊 2.0 — 一个机会?](https://www.cryptojungle.co.il/etherurm2-week-summary/) +- [Alon Muroch (Bloxstaking) - 什么是以太坊 2.0?](https://www.cryptojungle.co.il/alon-moroch-eth2/) +- [Eilon Aviv (Collider Ventures) - 以太坊 2.0 会出什么问题](https://www.cryptojungle.co.il/eilon-aviv-eth2-0/) - [Eilon Aviv (Collider Ventures) - 我们为什么需要以太坊 2.0](https://www.cryptojungle.co.il/eilon-aviv-ethereum-2-0/) ### 意大利语 {#it} -- [Ethereum Italia](https://www.ethereum-italia.it/) - 提供有关以太坊的教育、活动和新闻,专注于智能合约和区块链技术 -- [Ethereum Italia Podcast](https://www.ethereum-italia.it/podcast/) - 以太坊播客(意大利语) -- [Microsoft Learn (Solidity)](https://docs.microsoft.com/it-it/learn/modules/blockchain-learning-solidity/) - 学习使用 Solidity -- [Microsoft Learning(智能合约)](https://docs.microsoft.com/it-it/learn/modules/blockchain-solidity-ethereum-smart-contracts/) - 学习用 Solidity 编写智能合约 -- [Microsoft Learn(用去中心化应用程序)](https://docs.microsoft.com/it-it/learn/modules/blockchain-create-ui-decentralized-apps/) - 使用去中心化应用程序创建用户界面 +- [Ethereum Italia](https://www.ethereum-italia.it/) - 以太坊教育、活动和新闻,专注于智能合约和区块链技术 +- [Ethereum Italia Podcast](https://www.ethereum-italia.it/podcast/) - 以太坊意大利语播客 +- [Microsoft Learn (Solidity)](https://docs.microsoft.com/it-it/learn/modules/blockchain-learning-solidity/) - 学习如何使用 Solidity +- [Microsoft Learn (智能合约)](https://docs.microsoft.com/it-it/learn/modules/blockchain-solidity-ethereum-smart-contracts/) - 学习使用 Solidity 编写智能合约 +- [Microsoft Learn (去中心化应用程序)](https://docs.microsoft.com/it-it/learn/modules/blockchain-create-ui-decentralized-apps/) - 使用去中心化应用程序创建用户界面 ### 日语 {#ja} -- [日本数字资产交易业协会](https://jvcea.or.jp/) -- [日本加密货币商业协会](https://cryptocurrency-association.org/) -- [区块链开发入门 - 学习 | Microsoft 文档](https://docs.microsoft.com/ja-jp/learn/paths/ethereum-blockchain-development/) - 此学习路径介绍区块链和以太坊平台上的开发 -- [精通以太坊](https://www.oreilly.co.jp/books/9784873118963/) - 精通以太坊(日文) -- [Solidity 智能合约开发和以太坊实战](https://www.oreilly.co.jp/books/9784873119342/) - Solidity 智能合约开发和以太坊实战(日文) +- [日本虚拟与加密资产交易协会](https://jvcea.or.jp/) +- [日本加密资产商业协会](https://cryptocurrency-association.org/) +- [区块链开发入门 - 学习 | Microsoft Docs](https://docs.microsoft.com/ja-jp/learn/paths/ethereum-blockchain-development/) - 此学习路径向你介绍区块链和以太坊平台上的开发 +- [《精通以太坊》](https://www.oreilly.co.jp/books/9784873118963/) - 《精通以太坊》日语版 +- [《Solidity 与以太坊智能合约开发实战》](https://www.oreilly.co.jp/books/9784873119342/) - 《Solidity 与以太坊智能合约开发实战》日语版 ### 俄语 {#ru} -- [Cyber Academy](https://cyberacademy.dev) - 面向 web3 构建者的教育空间 -- [Forklog](https://forklog.com) - 提供有关普通加密货币、不同区块链现有技术和未来升级的新闻和教育文章 -- [BeInCrypto](https://ru.beincrypto.com) - 提供新闻、加密货币价格和非技术性文章,通俗易懂地解释有关加密货币的所有内容 +- [Cyber Academy](https://cyberacademy.dev) - 面向 Web3 构建者的教育空间 +- [Forklog](https://forklog.com) - 关于一般加密货币、现有技术和不同区块链未来升级的新闻和教育文章 +- [BeInCrypto](https://ru.beincrypto.com) - 新闻、加密货币价格分析以及通俗易懂地解释加密领域一切的非技术性文章 ### 西班牙语 {#es} -- [Ethereum Madrid](https://ethereummadrid.com/) - 区块链、去中心化金融与治理课程、活动和博客 -- [Cointelegraph](https://es.cointelegraph.com/ethereum-for-beginners) - 以太坊初学者指南(西班牙语) -- [在线教程](https://tutoriales.online/curso/solidity) - 在以太坊上学习 Solidity 和编程 -- [以太坊开发课程介绍](https://youtube.com/playlist?list=PLTqiwJDd_R8y9pfUBjhkVa1IDMwyQz-fU) - Solidity 基础知识以及测试和部署你的首个智能合约 -- [以太坊安全与黑客攻击课程介绍](https://youtube.com/playlist?list=PLTqiwJDd_R8yHOvteko_DmUxUTMHnlfci) - 了解真实智能合约中常见的漏洞和安全问题 -- [去中心化金融开发课程介绍](https://youtube.com/playlist?list=PLTqiwJDd_R8zZiP9_jNdaPqA3HqoW2lrS) - 了解去中心化金融智能合约如何在 Solidity 中运作,并创建自己的自动化做市商应用 -- [Cryptoversidad](https://www.youtube.com/c/Cryptoversidad) - 非技术类区块链教育(面向初学者到高阶学习者)。 全面学习加密货币和以太坊。 +- [Ethereum Madrid](https://ethereummadrid.com/) - 区块链、DeFi 和治理课程、活动和博客 +- [Cointelegraph](https://es.cointelegraph.com/ethereum-for-beginners) - 西班牙语版以太坊初学者指南 +- [Tutoriales online](https://tutoriales.online/curso/solidity) - 学习 Solidity 和以太坊编程 +- [以太坊开发入门课程](https://youtube.com/playlist?list=PLTqiwJDd_R8y9pfUBjhkVa1IDMwyQz-fU) - Solidity 基础知识,以及第一个智能合约的测试和部署 +- [以太坊安全与黑客入门课程](https://youtube.com/playlist?list=PLTqiwJDd_R8yHOvteko_DmUxUTMHnlfci) - 了解真实智能合约中的常见漏洞和安全问题 +- [DeFi 开发入门课程](https://youtube.com/playlist?list=PLTqiwJDd_R8zZiP9_jNdaPqA3HqoW2lrS) - 了解 DeFi 智能合约在 Solidity 中的工作原理,并创建你自己的自动做市商 +- [Cryptoversidad](https://www.youtube.com/c/Cryptoversidad) - 从初级到高级的非技术性区块链教育。 全面学习加密货币和以太坊。 ### 土耳其语 {#tr} - [BTK Akademi](https://www.btkakademi.gov.tr/portal/course/blokzincir-ve-kripto-paralar-10569#!/about) - 专注于区块链和加密货币的课程 -- [重要的重命名:以太坊 2 有何变化?](https://miningturkiye.org/konu/ethereum-madenciligi-bitiyor-mu-onemli-gelisme.655/) - 《重要的重命名》博文的土耳其语译作,解释了“以太坊 2”术语的变化 +- [重大更名:Eth2 怎么了?](https://miningturkiye.org/konu/ethereum-madenciligi-bitiyor-mu-onemli-gelisme.655/) - 《重大更名》博文的土耳其语译文,解释了不再使用“Eth2”术语的原因 ### 越南语 {#vi} -- [Tino Group](https://wiki.tino.org/ethereum-la-gi/) - 以太坊、去中心化应用程序、钱包和常见问题概览 -- [Tap Chi Bitcoin](https://tapchibitcoin.io/tap-chi/tin-tuc-ethereum-eth) - 包含以太坊新闻和教育子页面的网站平台 -- [Coin68](https://coin68.com/ethereum-tieu-diem/) - 提供以太坊新闻和教育内容的加密货币门户网站 +- [Tino Group](https://wiki.tino.org/ethereum-la-gi/) - 以太坊、去中心化应用程序、钱包和常见问题概述 +- [Tap Chi Bitcoin](https://tapchibitcoin.io/tap-chi/tin-tuc-ethereum-eth) - 设有以太坊新闻和教育子页面的网络平台 +- [Coin68](https://coin68.com/ethereum-tieu-diem/) - 提供以太坊新闻和教育内容的加密货币门户 diff --git a/public/content/translations/zh/community/online/index.md b/public/content/translations/zh/community/online/index.md index e34b964cfd3..46729d664f6 100644 --- a/public/content/translations/zh/community/online/index.md +++ b/public/content/translations/zh/community/online/index.md @@ -1,6 +1,7 @@ --- -title: 线上社区 -description: 以太坊生态系统的资助方案清单。 +title: | + 线上社区 +description: "探索以太坊爱好者聚集讨论并互相协作的线上论坛、聊天室和社交媒体社区。" lang: zh --- @@ -12,65 +13,44 @@ lang: zh 为维护所列社区的正直诚信和价值观,ethereum.org 遵循严格的资格判定政策: -### 资格条件 {#eligibility-criteria} +### 资格标准 {#eligibility-criteria} - **相关性**:社区必须与以太坊及其生态系统直接相关。 - **活跃程度**:社区应该活跃,定期进行互动、发帖或讨论。 休眠或不活跃的社区可能会被移除。 - **包容性**:社区应营造一个尊重多样性、鼓励各种背景的人参与的温馨环境。 -- **不注重商务**:上架旨在提供社区空间,而非商业或宣传平台。 +- **非商业性质**:上架旨在提供社区驱动的空间,而非商业或推广平台。 ### 内容准则 {#content-guidelines} - **适当的内容**:社区必须有自己的审核准则,避免垃圾邮件、仇恨言论、骚扰或任何宣传非法活动的内容。 -- **语言**:虽然在社区中英语是主要语言,但只要能保持包容和尊重的氛围,我们也鼓励使用其他语言的社区提交作品。 -- **透明度**: 应向成员提供有关社区宗旨、规则和版主的明确信息。 +- **语言**:虽然英语是主要语言,但只要能保持包容和尊重的氛围,我们也鼓励使用其他语言的社区提交申请。 +- **透明度**:应向成员提供有关社区宗旨、规则和版主的明确信息。 ### 其他建议 {#other-recommendations} -- **可访问性**:社区论坛应可供所有人阅读,无需注册或登记。 -- **Discord 服务器邀请**:建议只在 ethereum.org 上添加可靠的 Discord 服务器邀请。 理想情况下,这些邀请应链接到网站上的社区页面(例如 [ethglobal.com/discord](https://ethglobal.com/discord)) 或来自官方 URL(例如 [discord.gg/ethstaker](https://discord.gg/ethstaker) 或 [discord.com/invite/ethstaker](https://discord.com/invite/ethstaker))。 - -如果你认为应根据这些准则添加或移除某个社区,请[在我们的 GitHub 储存库中创建一个提议](https://github.com/ethereum/ethereum-org-website/issues)。 +- **可访问性**:社区论坛应可供所有人阅读,无需注册。 +- **Discord 服务器邀请**:建议只在 ethereum.org 上添加可靠的 Discord 服务器邀请。 理想情况下,这些邀请应链接到网站上的社区页面(例如 [ethglobal.com/discord](https://ethglobal.com/discord)),或来自官方 URL(例如 [discord.gg/ethstaker](https://discord.gg/ethstaker) 或 [discord.com/invite/ethstaker](https://discord.com/invite/ethstaker))。 +如果您认为应根据这些准则添加或移除某个社区,请在我们的 GitHub 存储库[提交一个 issue](https://github.com/ethereum/ethereum-org-website/issues)。 ## 论坛 {#forums} -r/ethereum - 所有内容皆关乎以太坊 -r/ethfinance - 以太坊金融领域,包括去中心化金融 -r/ethdev - 专注于以太坊开发 -r/ethtrader - 趋势和市场分析 -r/ethstaker - 欢迎所有对以太坊质押感兴趣者 -Fellowship of Ethereum Magicians - 聚集于太坊技术标准的社区 -Ethereum Stackexchange - 让以太坊开发者相互讨论和并向他们提供帮助 -Ethereum Research - 最具影响力的加密经济研究留言板 +r/ethereum - 关于以太坊的一切 r/ethfinance - 以太坊的金融方面,包括 DeFi r/ethdev - 专注于以太坊开发 r/ethtrader - 趋势和市场分析 r/ethstaker - 欢迎所有对以太坊质押感兴趣的人 Fellowship of Ethereum Magicians - 围绕以太坊技术标准的社区 Ethereum Stackexchange - 为以太坊开发者提供讨论和帮助 Ethereum Research - 最具影响力的加密经济学研究论坛 ## 聊天室 {#chat-rooms} -Ethereum Cat Herders - 专注于为以太坊开发提供项目管理支持的社区。 -Ethereum Hackers - 由 ETHGlobal 管理的 Discord 聊天室:全世界以太坊黑客的线上社区。 -CryptoDevs - 关注以太坊发展的 Discord 社区 -EthStaker Discord - 社区为现有和潜在的质押人提供的指导、教育、支持和资源。 -Ethereum.org 网站团队 - 拜访社区中的团队和成员并与他们讨论 ethereum.org 的网络开发和设计 -Matos Discord - Web3 创作者社区,构建者、业界人士和以太坊爱好者在这里聚会。 我们热衷于 Web3 的开发、设计和文化。 来吧,我们一起来构建。 -Solidity Gitter - 有关 Solidity 开发的聊天 (Gitter) -Solidity Matrix - 有关 Solidity 开发的聊天 (Matrix) -以太坊堆栈交易所 *- 问答论坛* -Peera Community Forum *- 去中心化问答论坛* - -## YouTube 和 X(原 Twitter) {#youtube-and-twitter} - -以太坊基金会 - 及时了解以太坊基金会的最新动态 -@ethereum - 以太坊社区的主帐户 -@ethereumfndn - 以太坊基金会的官方帐户 -@ethdotorg - 为我们不断发展的全球社区构建的以太坊门户网站 -有影响力的以太坊 Twitter 帐户清单 +Ethereum Cat Herders - 为以太坊开发提供项目管理支持的社区 Ethereum Hackers - 由 ETHGlobal 运营的 Discord 聊天室:一个面向全球以太坊黑客的在线社区 CryptoDevs - 专注于以太坊开发的 Discord 社区 EthStaker Discord - 为现有和潜在质押者提供社区运营的指导、教育、支持和资源 Ethereum.org 网站团队 - 来与团队和社区成员聊聊 ethereum.org 网站的开发和设计 Matos Discord - Web3 创建者社区,这里聚集了构建者、行业领袖和以太坊爱好者。 我们热衷于 Web3 的开发、设计和文化。 与我们一起构建。 Solidity Gitter - Solidity 开发聊天室 (Gitter) Solidity Matrix - Solidity 开发聊天室 (Matrix) Ethereum Stack Exchange - 问答论坛 Peera Community Forum - 去中心化问答论坛 + +## YouTube 和 X (前身为 Twitter) {#youtube-and-twitter} + +以太坊基金会 - 了解以太坊基金会的最新动态 @ethereum - 面向社区的主要以太坊帐户 @ethereumfndn - 以太坊基金会的官方帐户 @ethdotorg - 通往以太坊的门户,为我们不断增长的全球社区而构建
- 了解更多有关去中心化自治组织的信息 + 了解更多有关 DAO 的信息 -
+
diff --git a/public/content/translations/zh/community/research/index.md b/public/content/translations/zh/community/research/index.md index f64bd72a6fc..ff7fd30fc06 100644 --- a/public/content/translations/zh/community/research/index.md +++ b/public/content/translations/zh/community/research/index.md @@ -1,6 +1,6 @@ --- -title: 活跃的以太坊研究领域 -description: 探索不同的开放研究领域,并了解如何参与其中。 +title: "活跃的以太坊研究领域" +description: "探索不同的开放研究领域,并了解如何参与其中。" lang: zh --- @@ -83,7 +83,7 @@ lang: zh 1. 一个共识客户端,用于追踪区块链头部、传播区块并处理共识逻辑 2. 一个执行客户端,用于支持以太坊虚拟机并执行交易和智能合约 -查看[节点和客户端页面](/developers/docs/nodes-and-clients/)以了解关于节点和客户端的更多详细信息以及当前所有客户端实现的清单。 你也可以在[历史页面](/ethereum-forks/)找到所有以太坊升级的历史信息。 +请参阅[节点与客户端页面](/developers/docs/nodes-and-clients/),获取有关节点与客户端的更多详细信息,以及当前所有客户端实现的列表。 你也可以在[历史页面](/ethereum-forks/)找到所有以太坊升级的历史信息。 ### 执行客户端 {#execution-clients} @@ -377,7 +377,7 @@ Proto-Danksharding 是完整 Danksharding 的先决条件 ,在 Cancun-Deneb (" - [虫洞攻击报告](https://blog.chainalysis.com/reports/wormhole-hack-february-2022/) - [以太坊合约黑客攻击事后分析列表](https://forum.openzeppelin.com/t/list-of-ethereum-smart-contracts-post-mortems/1191) -- [Rekt 新闻](https://twitter.com/RektHQ?s=20&t=3otjYQdM9Bqk8k3n1a1Adg) +- [Rekt 新闻](https://x.com/RektHQ?s=20&t=3otjYQdM9Bqk8k3n1a1Adg) #### 近期的研究 {#recent-research-19} diff --git a/public/content/translations/zh/community/support/index.md b/public/content/translations/zh/community/support/index.md index a0b54ff06b3..b0ccbc2573b 100644 --- a/public/content/translations/zh/community/support/index.md +++ b/public/content/translations/zh/community/support/index.md @@ -1,6 +1,6 @@ --- -title: 以太坊支持 -description: 在以太坊生态系统中获得支持。 +title: "以太坊支持" +description: "在以太坊生态系统中获得支持。" lang: zh --- @@ -10,10 +10,10 @@ lang: zh 你正在寻求以太坊官方支持吗? 你应该知道的第一件事是以太坊是去中心化的。 这意味着以太坊不属于任何中心化组织、实体或个人,因此没有官方支持渠道。 -了解以太坊的去中心化特点非常重要,因为**任何声称自己是以太坊官方支持人员的人都可能在试图诈骗你!**防范诈骗的最好方式是自学并认真对待安全问题。 +了解以太坊的去中心化特点非常重要,因为\*\*任何声称自己是以太坊官方支持人员的人都可能在试图诈骗你!\*\*防范诈骗的最好方式是自学并认真对待安全问题。 - 以太坊安全和预防欺诈措施 + 以太坊安全和预防诈骗 @@ -22,9 +22,9 @@ lang: zh 尽管缺乏官方支持,但以太坊生态系统中的许多团体、社区和项目都乐于提供帮助,并且你可以在此页面上找到很多有用的信息和资源。 还有问题吗? 加入 [ethereum.org Discord](https://discord.gg/ethereum-org),我们会尽力提供帮助。 -## 常见问题 {#faq} +## 常见问题{#faq} -### 我把以太币发到了错误的钱包中 {#wrong-wallet} +### 我把 ETH 发送到错误的钱包了 {#wrong-wallet} 以太坊上发送的交易是不可逆的。 如果你将以太币发送到错误的钱包,很遗憾,没有办法追回这些资金。 以太坊不属于任何中心化组织、实体或个人,这意味着没有人可以逆转交易。 因此,在发送交易之前,一定要仔细检查你的交易,这一点至关重要。 @@ -32,23 +32,23 @@ lang: zh 以太坊赠品是用来窃取你以太币的骗局。 不要被看起来好得令人难以置信的优惠所诱惑 — 如果你将以太币发送到赠品地址,你不但收不到赠品,还将无法追回你的资金。 -[关于预防诈骗的更多信息](/security/#common-scams) +[更多关于预防诈骗的内容](/security/#common-scams) ### 我的交易卡住了 {#stuck-transaction} 如果你提交的交易费低于网络需求,以太坊上的交易有时会被卡住。 许多钱包提供了一个选项,即以更高的交易费重新提交同一项交易,使该交易得以处理。 或者,你可以发送交易到你自己的地址,并使用与待定交易相同的随机数,以取消待定交易。 -[如何在 MetaMask 上加速或取消待定交易](https://metamask.zendesk.com/hc/en-us/articles/360015489251-How-to-speed-up-or-cancel-a-pending-transaction) +[如何在 MetaMask 上加速或取消待处理的交易](https://metamask.zendesk.com/hc/en-us/articles/360015489251-How-to-speed-up-or-cancel-a-pending-transaction) -[如何取消待定以太坊交易](https://info.etherscan.com/how-to-cancel-ethereum-pending-transactions/) +[如何取消待处理的以太坊交易](https://info.etherscan.com/how-to-cancel-ethereum-pending-transactions/) ### 我如何在以太坊挖矿? {#mining-ethereum} -以太坊不再支持挖矿。 在以太坊从[工作量证明](/glossary/#pow)过渡到[权益证明](/glossary/#pos)后,挖矿就终止了。 现在,以太坊使用验证者而不是矿工。 任何人都可以[质押](/glossary/#staking)以太币并运行验证者软件保护网络,从而获取质押奖励。 +以太坊不再支持挖矿。 在以太坊从[工作量证明](/glossary/#pow)过渡到[权益证明](/glossary/#pos)后,挖矿就终止了。 现在,以太坊使用验证者而不是矿工。 任何人都可以[质押](/glossary/#staking) ETH,并通过运行验证者软件来保障网络安全,从而获得质押奖励。 ### 我如何成为质押者/运行验证者? {#how-to-stake} -要成为验证者,你必须在以太坊存款合约中质押 32 个以太币并搭建一个验证节点。 更多信息见[质押界面](/staking)和[质押启动版](https://launchpad.ethereum.org/)。 +要成为验证者,你必须在以太坊存款合约中质押 32 个以太币并搭建一个验证节点。 更多信息可在我们的[质押页面](/staking)和[质押启动板](https://launchpad.ethereum.org/)上找到。 ## 构建去中心化应用程序 {#building-support} @@ -56,7 +56,7 @@ lang: zh - [Alchemy University](https://university.alchemy.com/#starter_code) - [CryptoDevs discord](https://discord.com/invite/5W5tVb3) -- [以太坊堆栈交易所](https://ethereum.stackexchange.com/) +- [Ethereum StackExchange](https://ethereum.stackexchange.com/) - [Web3 University](https://www.web3.university/) - [LearnWeb3](https://discord.com/invite/learnweb3) @@ -71,7 +71,7 @@ lang: zh - [Solidity](https://gitter.im/ethereum/solidity) - [ethers.js](https://discord.gg/6jyGVDK6Jx) - [web3.js](https://discord.gg/GsABYQu4sC) -- [安全帽](https://discord.gg/xtrMGhmbfZ) +- [Hardhat](https://discord.gg/xtrMGhmbfZ) - [Alchemy](http://alchemy.com/discord) - [Tenderly](https://discord.gg/fBvDJYR) @@ -101,4 +101,4 @@ lang: zh - [Lodestar](https://discord.gg/aMxzVcr) - [Grandine](https://discord.gg/H9XCdUSyZd) -你还可以[在此处了解如何运行节点](/developers/docs/nodes-and-clients/run-a-node/)。 +你也可以[在此处学习如何运行节点](/developers/docs/nodes-and-clients/run-a-node/)。 diff --git a/public/content/translations/zh/contributing/adding-desci-projects/index.md b/public/content/translations/zh/contributing/adding-desci-projects/index.md index cb1462b74e3..1fdbc951af9 100644 --- a/public/content/translations/zh/contributing/adding-desci-projects/index.md +++ b/public/content/translations/zh/contributing/adding-desci-projects/index.md @@ -1,6 +1,6 @@ --- -title: 添加去中心化科学项目 -description: 我们在 ethereum.org 的去中心化科学页面上添加项目链接时使用的政策 +title: "添加去中心化科学项目" +description: "我们将项目链接添加到 ethereum.org 上 DeSci 页面时使用的政策" lang: zh --- @@ -10,27 +10,27 @@ lang: zh 任何人都可以在 ethereum.org 的去中心化科学页面上自由地建议可展示的项目。 同样,任何人在注意到某个项目已不再与之相关或达不到我们的资格条件时,也可以随时建议我们将其移除。 -## 决策框架 {#the-decision-framework} +## 决策框架{#the-decision-framework} -### 纳入标准:必备条件 {#the-must-haves} +### 入选标准:必备条件 {#the-must-haves} - **开源代码/数据** - 开放的代码和数据是去中心化科学的核心原则,因此去中心化科学项目不得闭源。 代码库应该是可访问的,并且最好可以接受拉取请求 (PR)。 -- **去中心化科学项目应明显去中心化** - 这可能包括项目由去中心化自治组织管理,或通过使用去中心化技术栈(包括非托管钱包)来构建。 可能涉及以太坊上的可审计智能合约。 +- **DeSci 项目应可证明是去中心化的** - 这可能包括由 DAO 治理,或通过使用包括非托管钱包在内的去中心化技术栈来构建。 可能涉及以太坊上的可审计智能合约。 - **诚实准确的上架信息** - 建议上架的任何项目都应包含诚实准确的信息。 伪造上架信息的产品,例如声明你的产品是“开源”的但实际并非如此,产品将被移除。 -- **对扩大科学参与的明确承诺** - 去中心化科学项目应能够阐明它们如何扩大公众对科学的参与,而不仅仅服务于代币/非同质化代币持有者。 -- **全球可访问** - 你的项目不能有地域限制或身份验证要求,它们使得某些人无法访问你的服务。 -- **信息详尽的网站和文件** - 重要的是,项目网站的访问者能够了解项目的实际情况、项目对促进科学基础设施去中心化所做的贡献以及参与方式。 +- **对扩大科学参与的可证明承诺** - DeSci 项目应能够阐明它们如何扩大公众对科学的参与,而不仅仅是面向代币/NFT 持有者。 +- **全球可访问** - 你的项目不应有地域限制或 KYC 要求,以免将某些人排除在你的服务之外。 +- **信息详尽的网站和文档** - 重要的是,项目网站的访问者能够了解项目的实际情况、项目对促进科学基础设施去中心化所做的贡献以及参与方式。 - **项目应该是以太坊生态系统的一部分** - 在 ethereum.org,我们相信以太坊(及其二层网络)是适合去中心化科学运动的基础层。 -- **项目已相当成熟** - 项目的实际用户能够使用项目的服务数月之久。 +- **项目已相当成熟** - 项目已有真实用户,且他们能够访问项目服务已达数月。 ### 加分项 -- **支持多种语言** - 你的项目已被翻译成多种语言,全球用户都能够访问它。 -- **教育资源** - 你的产品应提供精心设计的入门体验,为用户提供帮助和教育。 或者有文章或视频之类的介绍操作方法的内容。 -- **第三方审核** - 你的产品已通过可靠第三方的专业漏洞审核。 -- **联系人** - 实施变更时,项目联系人(可能是去中心化自治组织或社区的代表)将极大地帮助我们获取准确信息。 这样将在今后收集信息时确保 ethereum.org 的更新可管理。 +- **支持多种语言** - 你的项目已翻译成多种语言,世界各地的用户都能访问。 +- **教育资源** - 你的产品应有精心设计的入门体验,以帮助和引导用户。 或者有文章或视频之类的介绍操作方法的内容。 +- **第三方审计** - 你的产品已由值得信赖的第三方进行专业的漏洞审计。 +- **联系人** - 实施变更时,项目联系人(可能是 DAO 或社区的代表)将极大地帮助我们获取准确信息。 这样将在今后收集信息时确保 ethereum.org 的更新可管理。 -## 维护 {#maintenance} +## 持久性{#maintenance} 由于以太坊的流动性,团队和产品来来去去,创新每天都在发生,所以我们将对我们的内容进行例行检查,以便: diff --git a/public/content/translations/zh/contributing/adding-developer-tools/index.md b/public/content/translations/zh/contributing/adding-developer-tools/index.md index eaa42b07b60..f7369f33362 100644 --- a/public/content/translations/zh/contributing/adding-developer-tools/index.md +++ b/public/content/translations/zh/contributing/adding-developer-tools/index.md @@ -1,7 +1,7 @@ --- -title: 添加开发者工具 +title: "添加开发者工具" lang: zh -description: 开发者工具上架 ethereum.org 的标准 +description: "开发者工具上架 ethereum.org 的标准" --- # 添加开发者工具 {#contributing-to-ethereumorg-} @@ -10,43 +10,43 @@ description: 开发者工具上架 ethereum.org 的标准 如果我们遗漏了有用的开发工具,请随时在适当的地方提出建议。 -目前,我们在[开发者门户](/developers/)中上架了开发者工具。 +我们目前在[开发者门户](/developers/)上列出了开发者工具。 -**请随时去适当的页面提出新的建议。** +**欢迎随时为合适的页面提出增补建议。** -## 我们如何做出决定 {#ways-to-contribute} +## 我们的决策方式 {#ways-to-contribute} 提交的开发者工具将按照以下标准进行评估: -**它是否与已上架的工具有明显的区别?** +**它是否与已列出的工具有明显的区别?** - 新类别或新类型的工具 - 与现有类似工具比较具有新功能 - 针对现有类似工具未涵盖的独特用例 -**这个工具是否有相关文档给予充分支持?** +**该工具的文档是否完善?** - 是否存在相关文档? - 相关文档是否能满足工具使用需求? - 最近是否更新过? -**工具是否得到广泛使用?** +**该工具是否被广泛使用?** - 我们将考虑诸如 GitHub 星级、下载量等因素,以及是否被知名公司或项目使用过。 -**工具的质量是否足够好?** +**该工具的质量是否足够好?** - 是否有重复出现的错误? - 工具是否可靠? - 工具是否获得主动积极的维护? -**工具是否开源?** +**该工具是否开源?** 以太坊领域的许多项目都是开源的。 我们更愿意让开源项目上架,以便社区开发者检查代码并为这些项目做出贡献。 --- -## 产品排序 {#product-ordering} +## 产品订购{#product-ordering} 除非指定产品按特定方式排序,如按字母顺序排序,否则产品将默认从最早到最近添加到页面的顺序显示。 换句话说,最新的产品被添加到列表的底部。 @@ -57,5 +57,5 @@ description: 开发者工具上架 ethereum.org 的标准 如果你想向 ethereum.org 添加开发者工具并且它符合标准,请在 GitHub 上创建提议。 - 创建提议 + 创建议题 diff --git a/public/content/translations/zh/contributing/adding-exchanges/index.md b/public/content/translations/zh/contributing/adding-exchanges/index.md index ee488f39d15..7def9b98492 100644 --- a/public/content/translations/zh/contributing/adding-exchanges/index.md +++ b/public/content/translations/zh/contributing/adding-exchanges/index.md @@ -1,6 +1,6 @@ --- -title: 添加交易所 -description: 向 ethereum.org 添加交易所时适用的政策 +title: "添加交易所" +description: "向 ethereum.org 添加交易所时适用的政策" lang: zh --- @@ -16,9 +16,9 @@ lang: zh 鉴于这种情况,我们在你推荐交易所时需要一些具体信息。 -**请注意:**如果你想上架一个去中心化交易所,请查看我们[关于上架钱包和去中心化应用程序的政策](/contributing/adding-products/)。 +\*\*请注意:\*\*如果你想上架一个去中心化交易所,请查看我们[关于上架钱包和去中心化应用程序的政策](/contributing/adding-products/)。 -## 我们需要的信息 {#what-we-need} +## 我们需要什么 {#what-we-need} - 适用于交易所的地域限制. 与交易所相关的地域限制应在交易所网站上的专门页面或区域详细说明。 - 用户可以用哪些货币来购买以太币 @@ -36,5 +36,5 @@ lang: zh 如果你想向 ethereum.org 添加交易所,请在 GitHub 上创建提议。 - 创建一个提议 +创设一个开源项目 diff --git a/public/content/translations/zh/contributing/adding-glossary-terms/index.md b/public/content/translations/zh/contributing/adding-glossary-terms/index.md index 4d4da032750..17b074fcf51 100644 --- a/public/content/translations/zh/contributing/adding-glossary-terms/index.md +++ b/public/content/translations/zh/contributing/adding-glossary-terms/index.md @@ -1,14 +1,14 @@ --- -title: 添加词汇表术语 +title: "添加词汇表术语" lang: zh -description: 添加新术语到 ethereum.org 词汇表的标准 +description: "添加新术语到 ethereum.org 词汇表的标准" --- -# 添加词汇表术语 {#contributing-to-ethereumorg-} +# 添加术语表术语 {#contributing-to-ethereumorg-} -这一领域每天都在发生变化。 新术语不断进入以太坊用户的词典,我们需要你的帮助,为以太坊的所有事物提供准确、最新的参考。 请查看目前的[词汇表](/glossary/),如果你想要提供帮助的话,请参阅下面的内容! +这一领域每天都在发生变化。 新术语不断进入以太坊用户的词典,我们需要你的帮助,为以太坊的所有事物提供准确、最新的参考。 查看当前的[术语表](/glossary/),如果你想提供帮助,请参阅以下内容! -## 标准 {#criteria} +## 标准{#criteria} 将按照下列标准评估词汇表的新术语: @@ -23,4 +23,4 @@ description: 添加新术语到 ethereum.org 词汇表的标准 ## 添加你的术语 {#how-decisions-about-the-site-are-made} -如果你想为 ethereum.org 添加一个词汇表术语,并且该术语符合标准,[请在 GitHub 上创建一个问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A%2Ccontent+%3Afountain_pen%3A&template=suggest_glossary_term.yaml)。 +如果你想在 ethereum.org 上添加术语表术语,并且该术语符合标准,请[在 GitHub 上创建一个问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A%2Ccontent+%3Afountain_pen%3A&template=suggest_glossary_term.yaml)。 diff --git a/public/content/translations/zh/contributing/adding-layer-2s/index.md b/public/content/translations/zh/contributing/adding-layer-2s/index.md index 2aec168e548..9d820933969 100644 --- a/public/content/translations/zh/contributing/adding-layer-2s/index.md +++ b/public/content/translations/zh/contributing/adding-layer-2s/index.md @@ -1,6 +1,6 @@ --- -title: 添加二层网络 -description: 将二层网络添加到 ethereum.org 时适用的政策 +title: "添加二层网络" +description: "将二层网络添加到 ethereum.org 时适用的政策" lang: zh --- @@ -8,7 +8,7 @@ lang: zh 我们想要确保上架的资源是最好的,让用户能够安全放心地浏览二层网络空间。 -任何人都可以提出向 ethereum.org 添加二层网络的建议。 如果有遗漏的二层网络,**[请提出建议](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A%2Ccontent+%3Afountain_pen%3A&template=suggest_layer2.yaml)!** +任何人都可以提出向 ethereum.org 添加二层网络的建议。 如果我们遗漏了某个二层网络,**[请提交建议](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A%2Ccontent+%3Afountain_pen%3A&template=suggest_layer2.yaml)!** 我们目前在以下页面上架了二层网络: @@ -18,14 +18,14 @@ lang: zh 对以太坊来说,二层网络是一个相对较新的、令人振奋的范式。 我们已尝试在 ethereum.org 上创建一个公平的考量框架,但纳入标准会随时间推移而变化和发展。 -## 决策框架 {#decision-framework} +## 决策框架{#decision-framework} -### 纳入标准:必备条件 {#criteria-for-inclusion-the-must-haves} +### 收录标准:必备条件 {#criteria-for-inclusion-the-must-haves} **在 L2BEAT 上架** -- 要想纳入考量范围,项目必须已在 [L2BEAT](https://l2beat.com) 上架。 L2BEAT 为二层网络项目提供了可靠的风险评估,可供我们评估二层网络项目。 **如果项目未在 L2BEAT 上架,则我们不会将其作为二层网络纳入 ethereum.org。** -- [了解如何将你的二层网络项目添加到 L2BEAT](https://github.com/l2beat/l2beat/blob/master/CONTRIBUTING.md)。 +- 要想纳入考量范围,该项目必须已在 [L2BEAT](https://l2beat.com) 上架。 L2BEAT 为二层网络项目提供了可靠的风险评估,可供我们评估二层网络项目。 **如果项目未在 L2BEAT 上架,我们不会将其作为二层网络在 ethereum.org 上列出。** +- [了解如何将您的 L2 项目添加到 L2BEAT](https://github.com/l2beat/l2beat/blob/master/CONTRIBUTING.md)。 **开源** @@ -42,7 +42,7 @@ _我们认为,其他不使用以太坊来实现数据可用性或安全性的 **以太坊数据可用性** -- 数据可用性是其他扩容方案与二层网络方案之间的重要区分因素。 一个项目**必须**使用以太坊主网来实现数据可用性,才考虑让它上架。 +- 数据可用性是其他扩容方案与二层网络方案之间的重要区分因素。 一个项目**必须**使用以太坊主网来实现数据可用性,才会被考虑收录。 **链桥** @@ -70,7 +70,7 @@ _我们认为,其他不使用以太坊来实现数据可用性或安全性的 - 上架的项目需要能正常工作的区块浏览器,让用户轻松浏览区块链。 -### 其他标准:最好具备 {#nice-to-haves} +### 其他标准:加分项 {#nice-to-haves} **交易所对项目的支持** @@ -78,7 +78,7 @@ _我们认为,其他不使用以太坊来实现数据可用性或安全性的 **二层网络生态系统去中心化应用程序链接** -- 我们希望能够提供有关用户可以在此二层网络上执行哪些操作的信息 (例如 https://portal.arbitrum.io/、https://www.optimism.io/apps)。 +- 我们希望能够提供有关用户可以在此二层网络上执行哪些操作的信息 (例如,https://portal.arbitrum.io/、https://www.optimism.io/apps) **代币合约列表** @@ -88,10 +88,10 @@ _我们认为,其他不使用以太坊来实现数据可用性或安全性的 - 是否有任何钱包原生支持二层网络? -## 添加你的二层网络 {#add-exchange} +## 添加您的二层网络 {#add-exchange} 如果你想将二层网络添加到 ethereum.org,请在 GitHub 上创建一个提议。 - 创建一个提议 +创设一个开源项目 diff --git a/public/content/translations/zh/contributing/adding-products/index.md b/public/content/translations/zh/contributing/adding-products/index.md index f92bb076cf0..b2d32515973 100644 --- a/public/content/translations/zh/contributing/adding-products/index.md +++ b/public/content/translations/zh/contributing/adding-products/index.md @@ -1,6 +1,6 @@ --- -title: 添加产品 -description: 向 ethereum.org 添加去中心化应用程序时采用的政策 +title: "添加产品" +description: "向 ethereum.org 添加去中心化应用程序时采用的政策" lang: zh --- @@ -13,47 +13,47 @@ lang: zh - ethereum.org/dapps - ethereum.org/get-eth -**请仅在以上页面建议添加新的去中心化应用程序。** +**请仅在这些页面上建议添加新内容。** 尽管我们欢迎添加新的去中心化应用程序,但当前我们选择去中心化应用程序的基准是我们努力为用户创造的使用体验。 以下条件基于我们的一些设计原则: -- _有启发性_:ethereum.org 上的任何事物都应该为用户提供新的东西 -- _好故事_:上架的内容应该让人感到惊喜 -- _可靠_:一切业务/项目都应该是合法的,以最大限度地减少用户的风险 +- ——激励性要求——:以太坊官网的任何内容都应向用户提供新价值。​ +- ——一个好的叙事——:列表中的内容应该提供一个“令人惊喜的”时刻 +- ——可信度——:所有项目必须确保合法合规,以最大限度降低用户风险。​​ 总体而言,**ethereum.org 想要为新用户提供“无缝入门体验”**。 为此,我们基于以下标准添加去中心化应用程序: - 易用性 - 与其他产品的互操作性 -- 安全性 +- 安全性。 - 耐用性 下面将更详细地说明我们的决策框架。 欢迎你随时提供反馈或修改建议。 -## 决策框架 {#decision-framework} +## 决策框架{#decision-framework} -### 纳入标准:必备条件 {#criteria-for-inclusion-the-must-haves} +### 收录标准:必备条件 {#criteria-for-inclusion-the-must-haves} -- **产品经过安全测试** — 无论是通过审计、内部安全团队还是其他方法,你的产品的安全性都必须经过可靠的测试。 这会降低我们用户的风险,并向我们表明你非常重视安全性。 -- **这个产品已“上线并运行”超过 6 个月** – 这是安全性的另一个指标。 “6个月”是发现严重缺陷和漏洞的最佳时间窗口。 -- **有一个活跃的运作团队** — 这有助于确保质量,用户询问时也能得到的支持。 -- **诚实准确的上架信息** - 任何所建议的来自项目的上架产品都应包含诚实准确的信息。 伪造上架信息的产品,例如:声明你的产品是“开源”但实际上并非如此,它将被删除。 +- **经过安全测试的产品**——无论是通过审计、内部安全团队还是其他方法,您的产品的安全性都必须经过可靠的测试。 这会降低我们用户的风险,并向我们表明你非常重视安全性。 +- **产品已“上线”超过 6 个月**——这是安全性的另一个指标。 “6个月”是发现严重缺陷和漏洞的最佳时间窗口。 +- **由活跃的团队开发维护**——这有助于确保质量,并确保用户在查询时能得到支持。 +- **诚实准确的上架信息**——我们希望项目方提供的任何建议上架内容都包含诚实准确的信息。 伪造上架信息的产品,例如:声明你的产品是“开源”但实际上并非如此,它将被删除。 -### 排名标准:加分项 {#criteria-for-ranking-the-nice-to-haves} +### 排名标准:推荐条件 {#criteria-for-ranking-the-nice-to-haves} 基于以下标准,你的去中心化应用程序可能不会像其他项目一样在 ethereum.org 的显眼位置上架。 **去中心化应用程序** -- **可以通过大多数上架的钱包访问它** – 去中心化应用程序应该能够与 ethereum.org 上上架的大多数钱包一起使用。 -- **用户可以自己试用 –** 个人用户应该能够使用你的去中心化应用程序并能执行一些切实的操作。 -- **入门培训** – 你的产品应提供精心设计的入门培训体验,为用户提供帮助和培训。 或者有文章或视频之类的介绍操作方法的内容。 -- **非托管模式** - 用户可以控制自己的资金。 如果你的产品消失了,用户仍然可以获取和转移他们的资金。 -- **全球可访问** — 你的产品不能有地域限制或身份验证要求,因为这会让某些人无法使用你的服务。 -- **开源** - 你的代码应该可以访问,并且你应该接受来自更广泛社区的拉取请求。 -- **社区** – 你有一个专门的社区,可以是 Discord,用户可以与你的团队互动以获得帮助或推荐新功能。 +- **可以通过大多数上架的钱包访问**——去中心化应用程序应该能够与 ethereum.org 上上架的大多数钱包一起使用。 +- **用户可以亲自试用**——个人用户应该能够使用您的去中心化应用程序并实现一些具体目标。 +- **入门培训**——您的产品应提供精心设计的入门体验,为用户提供帮助和指导。 或者有文章或视频之类的介绍操作方法的内容。 +- **非托管**——用户可以控制自己的资金。 如果你的产品消失了,用户仍然可以获取和转移他们的资金。 +- **全球可访问**——您的产品没有地域限制或“了解你的客户”(KYC) 要求,这些限制和要求会使某些人无法使用您的服务。 +- **开源**——您的代码应该是可访问的,并且您应该接受来自更广泛社区的拉取请求。 +- **社区**——您有一个专门的社区(也许是 Discord),用户可以在其中与您的团队互动以获取帮助或建议新功能。 -## 实践中的标准 {#criteria-in-practice} +## 标准实践 {#criteria-in-practice} 你达到的标准越多,你的产品就越有可能进入 ethereum.org。 @@ -68,33 +68,33 @@ lang: zh ethereum.org 负责做出这种设计决策。 -但是请放心,**有其他网站对更多的去中心化应用程序进行排名,我们会附上这些网站的链接** +但请放心,**会有链接指向对更多去中心化应用程序进行排名的其他网站** -### 产品排序 {#product-ordering} +### 产品订购{#product-ordering} 除非指定产品按其他特定方式排序(如字母顺序),否则产品将按照从最早到最近添加到页面的顺序显示。 换句话说,最新的产品被添加到列表的底部。 ### 使用条款 {#terms-of-use} -还请参阅我们的[使用条款](/terms-of-use/)。 ethereum.org 上的资料仅供参考。 +另请参阅我们的[使用条款](/terms-of-use/)。 ethereum.org 上的资料仅供参考。 -## 维护 {#maintenance} +## 持久性{#maintenance} 由于以太坊的流动性,团队和产品来来去去,创新每天都在发生,所以我们将对我们的内容进行例行检查,以便: - 确保所有上架的去中心化应用程序仍然符合我们的标准 -- 验证建议的产品没有比当前上架的产品符合我们的更多标准 +- 验证所建议的产品没有比当前上架的产品更符合我们的标准 -如果你想对此提供帮助,可以开展上述两项检查并让我们知道检查结果。 [创建问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=feature_request.yaml&title=)或发送电子邮件至 [website@ethereum.org](mailto:website@ethereum.org)。 +如果你想对此提供帮助,可以开展上述两项检查并让我们知道检查结果。 [创建问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=feature_request.yaml&title=)或发送电子邮件至 [website@ethereum.org](mailto:website@ethereum.org) -_我们也在调研投票的可能性,以便社区能够表明他们的喜好并且突显出最佳产品供我们进行推荐。_ +_我们也在研究投票方案,以便社区可以表明他们的偏好,并为我们重点推荐最好的产品。_ --- -## 添加你的产品 {#add-your-product} +## 添加您的产品 {#add-your-product} -如果你想将去中心化应用程序添加到 ethereum.org 并且它符合标准,请在 GitHub 上创建一个问题。 +如果您想将某个去中心化应用程序添加到 ethereum.org 且该应用程序符合标准,请告知我们。 - 创建一个提议 + 推荐应用 diff --git a/public/content/translations/zh/contributing/adding-resources/index.md b/public/content/translations/zh/contributing/adding-resources/index.md new file mode 100644 index 00000000000..a21d7025e15 --- /dev/null +++ b/public/content/translations/zh/contributing/adding-resources/index.md @@ -0,0 +1,53 @@ +--- +title: "添加资源" +description: "我们添加资源到以太坊官网(ethereum.org)时所使用的政策" +lang: zh +--- + +# 添加资源{#adding-resources} + +我们想要确保我们上架的资源是最好的,能够让用户安全和放心。 + +任何人都可以自由地提议新的资源,以便将其添加到以太坊官网(ethereum.org)的资源板中,目前该页面位于[资源ethereum.org/资源](/resources/)。 + +尽管我们欢迎新资源的加入,但当前资源的选择是基于我们希望为用户创造的体验而决定的。 以下条件基于我们的一些设计原则: + +- ——激励性要求——:以太坊官网的任何内容都应向用户提供新价值。​ +- ——一个好的叙事——:列表中的内容应该提供一个“令人惊喜的”时刻 +- ——可信度——:所有项目必须确保合法合规,以最大限度降低用户风险。​​ + +总体而言,以太坊官网(ethereum.org )想要为新用户提供“无缝入门体验”。 由于这个原因,我们基于这些原则添加资源: + +- 易用性 +- 准确性 +- 维护 + +## 决策框架{#decision-framework} + +### 标准{#criteria} + +- **真实且准确的列表信息‌**——所有推荐的列表必须提供真实准确的信息。 提供了虚假信息的产品将会被下架。 +- **‌活跃的项目‌**——该资源应该由活跃团队维护,以确保质量和用户支持。 过时的资源将会被移除。 + +### 产品订购{#product-ordering} + +我们保留根据产品的影响力进行订购的权利。 新产品一般会被添加到列表底部,除非有其它说明。 + +## 持久性{#maintenance} + +随着以太坊生态系统的不断发展,我们将定期审核内容: + +- 以确保所有在列表中的资源仍然符合我们的标准 +- 验证建议的产品没有比当前上架的产品符合我们的更多标准 + +如果你想对此提供帮助,可以开展上述两项检查并让我们知道检查结果。 [创建一个问题](https://github.com/ethereum/ethereum-org-website/issues/new?template=bug_report.yaml)或发送邮件至 [website@ethereum.org](mailto:website@ethereum.org)。 + +--- + +## 添加你的资源{#add-your-resource} + +如果你想要在以太坊官网(ethereum.org)上添加你的资源且资源符合标准,可以在Github上创设一个开源项目。 + + +创设一个开源项目 + diff --git a/public/content/translations/zh/contributing/adding-staking-products/index.md b/public/content/translations/zh/contributing/adding-staking-products/index.md index 1dd261bdd62..d3ccb06ac27 100644 --- a/public/content/translations/zh/contributing/adding-staking-products/index.md +++ b/public/content/translations/zh/contributing/adding-staking-products/index.md @@ -1,6 +1,6 @@ --- -title: 添加质押产品或服务 -description: 将质押产品或服务添加到 ethereum.org 时适用的政策 +title: "添加质押产品或服务" +description: "将质押产品或服务添加到 ethereum.org 时适用的政策" lang: zh --- @@ -8,17 +8,17 @@ lang: zh 我们想要确保我们上架的资源是最好的,能够让用户安全和放心。 -任何人都可以提出向 ethereum.org 添加质押产品或服务的建议。 如果我们有遗漏,**[请提出建议](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A%2Ccontent+%3Afountain_pen%3A&template=suggest_staking_product.yaml)!** +任何人都可以提出向 ethereum.org 添加质押产品或服务的建议。 如果我们有遗漏,**[请建议](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A%2Ccontent+%3Afountain_pen%3A&template=suggest_staking_product.yaml)!** 我们目前在以下页面上架了质押产品和服务: -- [单独质押](/staking/solo/) +- [个人质押](/staking/solo/) - [质押即服务](/staking/saas/) - [质押池](/staking/pools/) 信标链上的权益证明自 2020 年 12 月 1 日起生效。 虽然质押仍相对较新,但我们已尝试在 ethereum.org 上创建一个公平透明的考量框架,但纳入标准会随时间推移而变化和发展,且最终由 ethereum.org 网站团队自行决定。 -## 决策框架 {#the-decision-framework} +## 决策框架{#the-decision-framework} 在 ethereum.org 上架产品不是由单个因素决定的。 在决定上架产品或服务时,会同时考虑多个标准。 满足以下标准越多,产品上架的可能性就越大。 @@ -57,7 +57,7 @@ lang: zh **支持哪些平台?** -- 例如 Linux、macOS、Windows、iOS、Android +- Linux、macOS、Windows、iOS、Android #### 软件和智能合约 {#software-and-smart-contracts} @@ -68,7 +68,7 @@ lang: zh - 开源项目应具有公开的源代码存储库 - 此项用于确定产品的“开源”评分。 -**产品是否已完成_测试版_开发?** +**产品是否已完成 _beta_ 开发?** - 产品处于开发周期的哪个阶段? - 不会考虑将测试阶段的产品纳入 ethereum.org @@ -87,14 +87,14 @@ lang: zh 对于与节点或客户端设置、管理或迁移相关的软件产品: -**支持哪些共识层客户端( Lighthouse、Teku、Nimbus、Prysm、Grandine)是否受支持?** +**支持哪些共识层客户端(即 Lighthouse、Teku、Nimbus、Prysm、Grandine)?** - 支持哪些客户端? 用户可以选择吗? - 这用于确定产品的“多客户端”评分。 #### 质押即服务 {#staking-as-a-service} -对于[质押即服务的上架](/staking/saas/)(即委托节点操作): +对于[质押即服务列表](/staking/saas/)(即委托节点操作): **使用该服务有哪些相关费用?** @@ -151,7 +151,7 @@ lang: zh **支持哪些用户界面?** -- 例如 浏览器应用程序、桌面应用程序、移动应用程序、命令行界面 +- 浏览器应用程序、桌面应用程序、移动应用程序、命令行界面 **对于节点工具,软件是否提供了在客户端之间轻松切换的方法?** @@ -165,12 +165,12 @@ lang: zh 上述[纳入标准](#criteria-for-inclusion)将用于计算每个产品或服务的累积评分。 这些分数会用来分类和展示满足某些客观标准的产品。 提供证据的标准越多,产品的排序就越高,并且在加载时会随机排列。 -这些标准的代码逻辑和权重当前包含在我们存储库的[这个 JavaScript 组件](https://github.com/ethereum/ethereum-org-website/blob/dev/src/components/Staking/StakingProductsCardGrid.js#L350)中。 +这些标准的逻辑代码和权重目前包含在我们代码库的[这个 JavaScript 组件](https://github.com/ethereum/ethereum-org-website/blob/dev/src/components/Staking/StakingProductsCardGrid.js#L350)中。 ## 添加你的产品或服务 {#add-product} 如果你想将质押产品或服务添加到 ethereum.org,请在 GitHub 上创建一个问题。 - 创建一个提议 +创设一个开源项目 diff --git a/public/content/translations/zh/contributing/adding-wallets/index.md b/public/content/translations/zh/contributing/adding-wallets/index.md index 680cf5bbf18..86a43d61ea1 100644 --- a/public/content/translations/zh/contributing/adding-wallets/index.md +++ b/public/content/translations/zh/contributing/adding-wallets/index.md @@ -1,6 +1,6 @@ --- -title: 添加钱包 -description: 向 ethereum.org 添加钱包时采用的政策 +title: "添加钱包" +description: "向 ethereum.org 添加钱包时采用的政策" lang: zh --- @@ -16,64 +16,64 @@ lang: zh 以太坊中的钱包日新月异。 我们已尝试在 ethereum.org 上创建一个公平的考量框架,但纳入标准会随时间推移而变化和发展。 -## 决策框架 {#the-decision-framework} +## 决策框架{#the-decision-framework} -### 纳入标准:必备条件 {#the-must-haves} +### 入选标准:必备条件 {#the-must-haves} -- **经过安全测试的产品** - 无论是通过审核、内部安全团队、开源编码还是其他方法,你的钱包的安全性都必须可靠。 这会降低我们用户的风险,并向我们表明你非常重视安全性。 +- **经过安全测试的产品** - 无论是通过审核、内部安全团队、开源编码还是其他方法,您的钱包的安全性都必须可靠。 这会降低我们用户的风险,并向我们表明你非常重视安全性。 - **“上线”超过六个月或由具有良好记录的团体发布的钱包** - 这是安全性的另一个衡量指标。 6 个月是发现严重缺陷和漏洞的最佳时间窗口。 我们要求 6 个月的时间,以便帮助筛选出那些作为项目很快就被放弃的分叉。 -- **由一个活跃的团队运作** - 这有助于确保质量,并确保用户的询问能够得到反馈。 -- **诚实准确的上架信息** - 任何所建议的来自项目的上架产品都应包含诚实准确的信息。 伪造上架信息的产品,例如声明你的产品是“开源”的但实际并非如此,产品将被移除。 +- **由一个活跃的团队运作** - 这有助于确保质量,并确保用户的问询能够得到支持。 +- **诚实准确的上架信息**——我们希望项目方提供的任何建议上架内容都包含诚实准确的信息。 伪造上架信息的产品,例如声明你的产品是“开源”的但实际并非如此,产品将被移除。 - **联系人** - 实施变更时,钱包的联系人将极大地帮助我们获取准确信息。 这样将在今后收集信息时确保 ethereum.org 的更新可管理。 -- **EIP-1559(类型 2)交易** - 你的钱包必须支持 EIP-1559(类型 2)交易才能在主网以太坊上进行交易。 -- **良好的用户体验** - 虽然用户体验是主观的,但如果多名核心团队成员测试产品后发现产品难以使用,我们保留拒绝钱包的权利,并将提供有用的改进建议。 这样做是为了保护我们主要由初学者组成的用户群。 +- **EIP-1559(类型 2)交易** - 您的钱包必须支持 EIP-1559(类型 2)交易,才能在以太坊主网上进行交易。 +- **良好的用户体验** - 虽然用户体验是主观的,但如果多名核心团队成员测试产品后发现产品难以使用,我们保留拒绝该钱包的权利,并将提供有用的改进建议。 这样做是为了保护我们主要由初学者组成的用户群。 +- **以以太坊为中心** - 钱包必须提供以以太坊为中心的主要体验。 这意味着以太坊(或任何二层网络)被设为默认网络,ERC 资产得到妥善支持,且各项功能与以太坊生态系统保持一致。 在用户界面中优先考虑其他一层网络的钱包将不会被收录。 ### 产品移除 {#product-removals} - **更新信息** - 钱包提供商有责任每 6 个月重新提交一次钱包信息,以确保所提供信息的有效性和相关性(即使其产品没有变化)。 如果产品团队未能这样做,ethereum.org 可能会从页面上移除该项目。 -### 其他标准:最好具备 {#the-nice-to-haves} +### 其他标准:加分项 {#the-nice-to-haves} -- **全球可访问** — 你的钱包没有地域限制或身份验证要求,因为这会让某些人无法使用你的服务。 -- **支持多种语言** - 你的钱包已经翻译成多种语言,全球用户都能够访问它。 -- **开源** - 你的整个项目的代码库(不只是模块)应该可以访问,并且你应该接受来自更广泛社区的拉取请求。 -- **非托管模式** - 用户可以控制自己的资金。 如果你的产品消失了,用户仍然可以获取和转移他们的资金。 +- **全球可访问** — 您的钱包没有地域限制或身份验证要求,因为这会让某些人无法使用您的服务。 +- **支持多种语言** - 您的钱包已翻译成多种语言,全球用户都能访问。 +- **开源** - 您整个项目的代码库(不只是模块)应该可以访问,并且您应该接受来自更广泛社区的拉取请求。 +- **非托管** - 用户可以控制自己的资金。 如果你的产品消失了,用户仍然可以获取和转移他们的资金。 - **支持硬件钱包** - 用户可以连接硬件钱包来签署交易。 - **WalletConnect** - 用户可以使用 WalletConnect 连接到去中心化应用程序。 -- **导入以太坊远程过程调用端点** - 用户可以导入节点的远程过程调用数据,这样他们可以连接到自己选择的节点或其他以太坊虚拟机兼容的网络。 -- **非同质化代币** - 用户能够查看钱包中的非同质化代币并与之互动。 +- **导入以太坊 RPC 端点** - 用户可以导入节点 RPC 数据,从而连接到自己选择的节点或其他与 EVM 兼容的网络。 +- **NFT** - 用户能够在钱包中查看自己的 NFT 并与之交互。 - **连接到以太坊应用程序** - 用户能够连接并使用以太坊应用程序。 -- **质押** - 用户可以直接通过钱包进行质押。 -- **兑换** - 用户可以通过钱包兑换代币。 -- **多链网络** - 你的钱包默认支持用户访问多个区块链网络。 -- **二层网络** - 你的钱包默认支持用户访问二层网络。 -- **自定义燃料费用** - 你的钱包允许用户自定义自己的交易燃料费用(基础费、优先费、最高费用)。 -- **支持以太坊域名服务** - 你的钱包允许用户向以太坊域名服务名称发送交易。 -- **支持 ERC-20** - 你的钱包允许用户导入 ERC-20 代币合约,或自动查询和显示 ERC-20 代币。 -- **购买加密货币** - 你的钱包支持用户直接购买和上手加密货币。 -- **出售法币** - 你的钱包支持用户将法币直接出售并提现到银行卡或银行帐户。 -- **多重签名** - 你的钱包支持通过多重签名来签署交易。 -- **社交恢复** - 你的钱包支持监护人,如果用户丢失了助记词,可以通过监护人来恢复他们的钱包。 -- **专职支持团队** - 你的钱包拥有一支专职支持团队,用户遇到问题时可以向该团队寻求帮助。 -- **教育资源/文档** - 你的产品应提供精心设计的入门培训体验,为用户提供帮助和培训。 或者有文章或视频之类的介绍操作方法的内容。 +- **质押** - 用户能够直接通过钱包进行质押。 +- **兑换** - 用户能够通过钱包兑换代币。 +- **多链网络** - 您的钱包默认支持用户访问多个区块链网络。 +- **二层网络** - 您的钱包默认支持用户访问二层网络。 +- **自定义燃料费** - 您的钱包允许用户自定义其交易燃料费(基本费用、优先费、最高费用)。 +- **支持 ENS** - 您的钱包允许用户向 ENS 名称发送交易。 +- **支持 ERC-20** - 您的钱包允许用户导入 ERC-20 代币合约,或自动查询和显示 ERC-20 代币。 +- **购买加密货币** - 您的钱包支持用户直接购买和上手加密货币。 +- **出售为法定货币** - 您的钱包支持用户出售加密货币并直接提现为法定货币至银行卡或银行账户。 +- **多重签名** - 您的钱包支持通过多重签名来签署交易。 +- **社交恢复** - 您的钱包支持监护人,如果用户丢失了助记词,可以使用这些监护人来恢复他们的钱包。 +- **专属支持团队** - 您的钱包拥有专属支持团队,用户遇到问题时可以向该团队寻求帮助。 +- **教育资源/文档** - 您的产品应提供精心设计的入门体验,为用户提供帮助和教学。 或者有文章或视频之类的介绍操作方法的内容。 ## 添加钱包 {#adding-a-wallet} 如果你想向 ethereum.org 添加钱包,请在 GitHub 上创建一个问题。 - 创建一个提议 +创设一个开源项目 -## 维护 {#maintenance} +## 持久性{#maintenance} 由于以太坊的流动性,团队和产品来来去去,创新每天都在发生,所以我们将对我们的内容进行例行检查,以便: - 确保所有钱包和上架的去中心化应用程序仍然符合我们的标准 -- 验证建议的产品没有比当前上架的产品符合我们的更多标准 - -ethereum.org 由开源社区维护,我们依靠社区来帮助持续更新它。 如果你发现有任何关于上架钱包的信息需要更新,请[创建一个问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=wallet+%3Apurse%3A&template=suggest_wallet.yaml)或[拉取请求](https://github.com/ethereum/ethereum-org-website/pulls)! +- 验证所建议的产品没有比当前上架的产品更符合我们的标准 +ethereum.org 由开源社区维护,我们依靠社区来帮助保持其内容的更新。 如果您发现任何关于已收录钱包的信息需要更新,请[创建问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=wallet+%3Apurse%3A&template=suggest_wallet.yaml)或[提交拉取请求](https://github.com/ethereum/ethereum-org-website/pulls)! ## 使用条款 {#terms-of-use} diff --git a/public/content/translations/zh/contributing/content-resources/index.md b/public/content/translations/zh/contributing/content-resources/index.md index 049361ca6ba..3c1322986dd 100644 --- a/public/content/translations/zh/contributing/content-resources/index.md +++ b/public/content/translations/zh/contributing/content-resources/index.md @@ -1,7 +1,7 @@ --- -title: 添加内容资源 +title: "添加内容资源" lang: zh -description: 在 ethereum.org 上上架内容资源的标准 +description: "在 ethereum.org 上上架内容资源的标准" --- # 添加内容资源 {#adding-content-resources} @@ -10,7 +10,7 @@ description: 在 ethereum.org 上上架内容资源的标准 如果你覺得某個頁麵中需要添加一個內容資源,請隨時在適當的地方提出建議。 -## 我们如何做出决定 {#how-we-decide} +## 我们如何决定 {#how-we-decide} 将按照以下标准评估学习资源: @@ -19,7 +19,7 @@ description: 在 ethereum.org 上上架内容资源的标准 - 信息准确吗? 它是基于事实还是基于观点? - 作者是否可信? 它们是否提及相关的来源? - 这些内容是否增加了现有资源或链接所不具有的独特价值? -- 这些内容是否服务于我们的其中一部分[用户](https://www.notion.so/efdn/Ethereum-org-User-Persona-Memo-b44dc1e89152457a87ba872b0dfa366c)? +- 此内容是否服务于我们的某个[用户画像](https://www.notion.so/efdn/Ethereum-org-User-Persona-Memo-b44dc1e89152457a87ba872b0dfa366c)? --- @@ -28,5 +28,5 @@ description: 在 ethereum.org 上上架内容资源的标准 如果你想要将内容资源添加到 ethereum.org,并且该内容资源符合标准,请在 GitHub 上创建一个提议。 - 创建一个提议 +创设一个开源项目 diff --git a/public/content/translations/zh/contributing/design-principles/index.md b/public/content/translations/zh/contributing/design-principles/index.md index 7ac7024018b..738d7e7d651 100644 --- a/public/content/translations/zh/contributing/design-principles/index.md +++ b/public/content/translations/zh/contributing/design-principles/index.md @@ -1,7 +1,7 @@ --- -title: 设计原则 +title: "设计原则" lang: zh -description: Ethereum.org 设计和内容决策背后的原则 +description: "Ethereum.org 设计和内容决策背后的原则" --- # 我们的设计原则 {#contributing-to-ethereumorg-} @@ -10,55 +10,55 @@ description: Ethereum.org 设计和内容决策背后的原则 我们的原则决定了网站的外观和感觉以及网站上的内容。 -你应该在为 [contribute to ethereum.org](/contributing/) 做贡献之前阅读这些原则。 +在[为 ethereum.org 做出贡献](/contributing/)前,您应阅读这些原则。 ## 什么是设计原则? {#ways-to-contribute} -别担心,它们非常简单。 **设计原则**是我们在设计(即创建、维护或更新)某物时参考的一套准则。 +别担心,它们非常简单。 **设计原则**是我们设计(即创建、维护或更新)事物时参考的一套准则。 -在 ethereum.org 的背景下,这些设计原则是我们希望网站向世界呈现和展示的内容的基础。 我们希望它们能表达我们的抱负,同时**也**要实现功能。 这不仅仅是网站的_外观_,还有它的_工作方式_,甚至是给人的_感觉。_从颜色到页面布局,再到我们在网站上讨论以太坊的方式,这一切都应该遵循这些原则。 +在 ethereum.org 的背景下,这些设计原则是我们希望网站向世界呈现和展示的内容的基础。 它们既有远大理想,**也**具备实用功能。 这不仅关乎网站的_外观_,也关乎其_运作方式_,甚至关乎它给人的_感觉_。从色彩、页面布局,到我们在网站上讨论以太坊的方式,一切都应遵循这些原则。 ## 实践中的原则 {#how-decisions-about-the-site-are-made} -让我们来看一个例子: 其中一项原则是“可信”,这意味着我们希望网站的访问者_感觉_并_知道_该网站是值得信赖的——就像更开放的以太坊生态系统一样。 在该原则下,我们有 3 个功能性“子原则”,我们认为这些是我们可以采取的可行步骤,以使网站具有可信度: +让我们来看一个例子: 原则之一是“可信”,这意味着我们希望网站的访问者能_感觉_到并_知道_该网站值得信赖——就像更广泛的以太坊生态系统一样。 在该原则下,我们有 3 个功能性“子原则”,我们认为这些是我们可以采取的可行步骤,以使网站具有可信度: - _“最新”_,即保持内容最新。 -- _“社会认同”_,即展示生态系统的规模、多样性和活跃度(你知道的:以太坊升级进度、去中心化金融、游戏、所有黑客马拉松等) -- _“一致”_,即网站设计以及写作的基调和准确性是一致的。 +- _“社会认同”_,即展示生态系统的规模、多样性和活跃度(例如:以太坊升级进度、DeFi、游戏、所有黑客马拉松等)。 +- _“一致”_,即网站设计以及文稿基调和准确性的一致。 因此,当我们做出设计或文案决策时,我们可以参考“可信”原则并自问: - _“网站是否反映了当前的信息?”_ -- _“我们如何以及在哪里展示生态系统的规模和活动?”_ -- _“我正在审核的由社区成员提出的新提议是否与网站上当前的设计和文风一致?”_ +- _“我们如何以及在何处展示生态系统的规模和活动?”_ +- _“我正在审核的社区成员的新贡献提案,是否与网站当前的设计和文风一致?”_ -## Ethereum.org 的设计原则 {#contributors} +## ethereum.org 设计原则 {#contributors} -### 1. 启发性 {#1-inspirational} +### 1. 鼓舞人心 {#1-inspirational} 网站应该能够激发用户,梦想以太坊能如何改变世界。 它应该激励人们去探索、体验和修复以太坊生态系统的工具和应用程序。 -- **斗志昂扬:**网站应该传达以太坊雄心勃勃的目标,即有意义地改变世界。 应该清楚的是,以太坊不仅仅是一些新技术的堆叠 - 它是一种变革性的技术。 -- **通过教育赋予权力**:网站应该对人们进行教导,以便他们了解以太坊的潜力,在生态系统中找到自己的位置,并感到有权参与其中。 +- \*\*激进:\*\*本站应传达以太坊旨在有意义地改变世界的宏伟目标。 应该清楚的是,以太坊不仅仅是一些新技术的堆叠 - 它是一种变革性的技术。 +- \*\*通过教育赋能:\*\*本站旨在教育大众,以便他们了解以太坊的潜力、在生态系统中找到自己的位置,并感觉自己有能力参与其中。 视觉导航 • 内容 -### 2. 通用性 {#2-universal} +### 2. 普适 {#2-universal} 以太坊是一个全球性的、去中心化的项目,我们的用户反映了这一点。 网站应致力于让每个人都能访问,并维护世界的多元文化。 -- **无障碍:**网站应遵循无障碍指南 - 包括允许低带宽连接的人访问。 -- **简单明了:**网站应该是简单而明确的。 文案不应使用可能被误解的用语或意思缺失的译文。 -- **以太坊是多面的:**以太坊是一个项目、一个代码库、一个社区和一个愿景。 以太坊出于不同的原因对不同的人都有价值,参与的方式也多种多样。 +- \*\*无障碍:\*\*网站应遵循无障碍指南——包括为低带宽连接的用户提供支持。 +- \*\*简明:\*\*网站应简单明了,无歧义。 文案不应使用可能被误解的用语或意思缺失的译文。 +- \*\*以太坊是多维度的:\*\*以太坊是一个项目、一个代码库、一个社区,也是一个愿景。 以太坊出于不同的原因对不同的人都有价值,参与的方式也多种多样。 -写作系统 • 色彩的使用 • 视觉导航 • 内容 +书写系统 • 色彩运用 • 视觉导向 • 内容 -### 3. 好故事 {#3-a-good-story} +### 3. 一个好故事 {#3-a-good-story} 网站应该像一个好故事一样运作。 访客就像在旅途中,而你所贡献的内容是旅途的一部分。 你的贡献应该运用清晰的叙述技巧:一个有开头(介绍/切入点)、中间(一些经验和见解)和结尾(指向相关资源或后续步骤的链接)。 -- **层次分明**:如果内容具有一个清晰的、有层次的信息架构,这将有助于 ethereum.org 的访问者在寻求达到他们的目的时“像读故事一样”浏览网站。 -- **踏脚石:**我们是来网站寻找答案的访问者的踏脚石。 我们不想取代许多现有资源或成为这些资源的替代品。 我们给出答案并提供可靠的后续步骤。 +- **层级分明**:清晰的层级化信息架构可帮助 ethereum.org 访问者在实现目标时“像读故事一样”浏览网站。 +- \*\*踏脚石:\*\*我们是所有寻求答案者的踏脚石。 我们不想取代许多现有资源或成为这些资源的替代品。 我们提供答案并给出可靠的后续步骤。 用户旅程 • 内容 @@ -66,9 +66,9 @@ description: Ethereum.org 设计和内容决策背后的原则 人们可能想要初步了解以太坊生态系统,或者对以太坊保持怀疑态度。 你的沟通方式将能发挥作用, 请确保他们在离开网站时对以太坊生态系统更加有信心。 -- **最新:**始终保持最新。 -- **社会认同:**展示生态系统的规模、多样性和活跃度。 -- **一致:**设计和内容的一致性传达了可信度。 +- \*\*最新:\*\*始终保持最新。 +- \*\*社会认同:\*\*展示生态系统的规模、多样性和活跃度。 +- \*\*一致:\*\*设计和内容的一致性传达了可信度。 视觉导航 • 内容 @@ -76,18 +76,18 @@ description: Ethereum.org 设计和内容决策背后的原则 该网站是许多贡献者的产物,就像整个生态系统一样。 -- **开放性:**为整个生态系统的源代码、流程和项目的透明度而欢呼吧。 -- **可扩展性:**模块化是我们一切努力背后的关键重点,所以贡献也应该是模块化的。 核心设计、组件代码和网站的实施应使其能够在未来轻松扩展。 -- **实验性:**我们正在不断地进行实验、测试和迭代。 -- **协作性:**这个项目将我们所有人聚集在一起。 -- **可持续性:**为社区长期维护而设置。 +- \*\*开放:\*\*颂扬整个生态系统中源代码、流程和项目的透明度。 +- \*\*可扩展:\*\*模块化是我们所有工作的核心焦点,因此贡献也应是模块化的。 网站的核心设计、组件代码和实现应使其在未来能被轻松扩展。 +- \*\*实验性:\*\*我们不断地实验、测试和迭代。 +- \*\*协作性:\*\*这个项目将我们所有人凝聚在一起。 +- \*\*可持续:\*\*为社区的长期维护做好准备 -你可以看到[我们的整个网站](/)充分体现了我们的设计原则。 +您可以在[我们整个网站](/)中看到我们设计原则的实际应用。 ## 提供反馈 {#give-feedback} -**分享你对本文档的反馈!**我们提出的原则之一是"**协作改进**",这意味着我们希望网站是众多贡献者的产物。 因此,本着这一原则,我们希望与以太坊社区分享这些设计原则。 +**请分享您对本文件的反馈!** 我们提出的原则之一是“**协作改进**”,这意味着我们希望网站是众多贡献者共同的产物。 因此,本着这一原则,我们希望与以太坊社区分享这些设计原则。 -虽然这些原则主要体现在 ethereum.org 网站上,但我们希望其中许多原则能够代表以太坊生态系统的整体价值。 也许你甚至想将其中一些原则运用到你自己的项目中! +虽然这些原则侧重于 ethereum.org 网站,但我们希望其中许多原则能代表整个以太坊生态系统的价值观。 也许你甚至想将其中一些原则运用到你自己的项目中! -你可以通过 [Discord 服务器](https://discord.gg/ethereum-org)或[创建一个问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=feature_request.yaml&title=)让我们知道你的想法。 +请在 [Discord 服务器](https://discord.gg/ethereum-org)上告诉我们您的想法,或者通过[创建问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=feature_request.yaml&title=)来告知我们。 diff --git a/public/content/translations/zh/contributing/design/adding-design-resources/index.md b/public/content/translations/zh/contributing/design/adding-design-resources/index.md index 37ec9520538..392c3aaa639 100644 --- a/public/content/translations/zh/contributing/design/adding-design-resources/index.md +++ b/public/content/translations/zh/contributing/design/adding-design-resources/index.md @@ -1,18 +1,18 @@ --- -title: 添加设计资源 -description: 确保 ethereum.org 上设计资料质量的准则和要求 +title: "添加设计资源" +description: "确保 ethereum.org 上设计资料质量的准则和要求" lang: zh --- # 添加设计资源 {#adding-design-resources} -任何人可以在 [web3 页面的设计和用户体验区域](/developers/docs/design-and-ux/)推荐新的设计资料。 +任何人都可以向 [web3 设计和用户体验页面](/developers/docs/design-and-ux/) 推荐新的设计资料。 请注意,本页面的重点是为有抱负的 web3 设计师提供用户价值。 该设计区域不是为了宣传你的服务、产品或平台。 为确保我们维护高标准的资料并推广有价值的见解,我们制定了一项上架政策: -## 研究和仪表板 {#Research-studies} +## 研究报告和仪表板 {#Research-studies} 1. 健全的方法 @@ -48,7 +48,7 @@ c. 文章应简明扼要并切中要害。 a. 文章的主要目的应是分享见解,而不是宣传某个具体项目或公司。 -## 社区/去中心化自治组织 {#Communities-and-DAOs} +## 社区 / DAO {#Communities-and-DAOs} 1. 网站必须明确说明如何加入去中心化自治组织/社区 @@ -56,7 +56,7 @@ a. 文章的主要目的应是分享见解,而不是宣传某个具体项目 a. 应将成为会员的好处放在显著位置。 -**示例**:收到关于工作的反馈、获得工作机会或奖励、分享设计和研究见解。 +**示例**:收到关于工作的反馈、获得工作机会或赏金、分享设计和研究见解。 3. 在 Discord 上支持积极活跃地交流 diff --git a/public/content/translations/zh/contributing/design/index.md b/public/content/translations/zh/contributing/design/index.md index bbffffca9f7..e051cd2fff5 100644 --- a/public/content/translations/zh/contributing/design/index.md +++ b/public/content/translations/zh/contributing/design/index.md @@ -1,10 +1,10 @@ --- -title: 设计贡献 -description: 为 ethereum.org 做出设计贡献 +title: "设计贡献" +description: "为 ethereum.org 做出设计贡献" lang: zh --- -# 为 ethereum.org 做出设计贡献 {#design-contributions} +# 为 ethereum.org 贡献设计 {#design-contributions} 设计是任何项目的关键组成部分,通过将你的时间和设计技能奋献给 ethereum.org,可以帮助改善访问者的用户体验。 为开源项目做贡献为你提供了在协作环境中获得相关经验和发展技能的机会。 你将有机会和其他有独特观点及见解的设计师、开发者和社区成员合作。 @@ -12,7 +12,7 @@ lang: zh ## 如何做出贡献? -###  对早期设计原型提供反馈 {#design-critique} +###  针对早期设计原型提供反馈 {#design-critique} 有时我们需要一些帮助来检验我们的最初构想。 这是在没有任何技术知识的情况下做出贡献的好方法。 @@ -28,28 +28,28 @@ lang: zh 2. 点击右下角的反馈小组件,并回答与设计和内容相关的问题。 3. 重点关注开放式问题。 -###  发现网站上与设计相关的问题并进行报告 {#report-design-issues} +###  在网站上发现与设计相关的问题并进行报告 {#report-design-issues} ethereum.org 是一个快速发展的网站,拥有许多功能和内容。 一些用户界面很容易过时或需要改进。 如果你遇到任何此类情况,请向我们报告,以便引起我们的注意。 1. 浏览网站并关注网站的设计。 2. 如果发现任何视觉或用户体验方面的问题,请截图并记录下来。 -3. 使用[漏洞报告](https://github.com/ethereum/ethereum-org-website/issues/new/choose)来报告发现的问题。 +3. 使用 [bug 报告](https://github.com/ethereum/ethereum-org-website/issues/new/choose)报告发现的问题。 -###  提出设计变更 {#propose-design-changes} +###  提出设计更改 {#propose-design-changes} -如果你愿意接受设计挑战,可以访问我们的 GitHub 问题看板,并筛选出 [与设计相关的问题](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8)。 +如果你愿意接受设计挑战,可以访问我们的 GitHub 问题看板并筛选[与设计相关的问题](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8)。 -1. 请浏览我们的网站并关注其设计,或访问我们的 GitHub 存储库并查看标记有[“Design required”(需要设计参与)”标签](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8)的问题。 +1. 浏览我们的网站并注意其设计,或者转到我们的 GitHub 代码库,审查标记有 [“需要设计”标签](https://github.com/ethereum/ethereum-org-website/labels/design%20required%20%F0%9F%8E%A8) 的问题。 2. 构思解决方案并进行设计。 (最好使用我们的[设计系统](https://www.figma.com/community/file/1134414495420383395))。 -3. 在相应的 GitHub 问题中提出解决方案,或者[创建一个新的问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A&template=feature_request.yaml&title=Feature+request)来提出建议。 +3. 在相应的 GitHub 问题中提出解决方案,或[创建一个新问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=feature+%3Asparkles%3A&template=feature_request.yaml&title=Feature+request)。 4. 等待设计团队审核。 -###  一起构建设计系统 {#Contribute-to-design-system} +###  共同构建设计系统 {#Contribute-to-design-system} 使用我们的设计系统,设计 ethereum.org 将变得轻松有趣。 如果你是一位经验丰富的设计师,就可以帮助我们为网站准备许多组件。 -1. 从 GitHub 上的[设计系统看板](https://github.com/ethereum/ethereum-org-website/labels/design%20system)中选择一个要处理的问题,或者创建一个新问题。 +1. 从 GitHub 上的[设计系统看板](https://github.com/ethereum/ethereum-org-website/labels/design%20system)中选择一个要处理的问题,或创建一个新问题。 2. 请求将所选问题分配给自己。 3. 开始在 Figma 中设计要求的组件。 4. 一旦需要审查或指导,请在 GitHub 上将组件分享给设计团队。 @@ -58,10 +58,10 @@ ethereum.org 是一个快速发展的网站,拥有许多功能和内容。 一 ###  在网站上撰写与设计相关的内容 {#write-design-articles} -以太坊开发者社区很强大,但设计社区稍显落后。 如果你是一位拥有 Web3 知识的设计师,请考虑与大社区分享你的知识,以便我们大家能够共同成长和进步;我们有[一个关于为以太坊设计的页面](/developers/docs/design-and-ux/),你可以为其做出贡献。 你还可以查看我们的[上架政策](/contributing/design/adding-design-resources)。 +以太坊开发者社区很强大,但设计社区稍显落后。 如果你是具备 Web3 知识的设计师,请考虑与广大社区分享你的学习心得,以便我们共同成长和进步;我们有一个[关于为以太坊设计的页面](/developers/docs/design-and-ux/),欢迎你为此页面贡献内容。 你也可以查看我们的[收录政策](/contributing/design/adding-design-resources)。 1. 构思 ethereum.org 上应涵盖的设计主题,这些主题应对该领域的设计师有所裨益。 -2. 访问我们的 GitHub 存储库,[创建一个问题](https://github.com/ethereum/ethereum-org-website/issues/new)并提出一个主题(先不要写内容)。 +2. 前往我们的 GitHub 代码库,[提出一个问题](https://github.com/ethereum/ethereum-org-website/issues/new),建议一个主题(先不要写内容)。 3. 等待设计团队批准。 4. 获得批准后,开始撰写内容。 5. 在相应的 GitHub 问题中提交。 @@ -71,7 +71,7 @@ ethereum.org 是一个快速发展的网站,拥有许多功能和内容。 一 可视化是用来解释抽象主题最有力的工具之一。 通过添加图表和信息图表,可视化可以挖掘出巨大的潜力。 毕竟,一张图片胜过千言万语。 1. 访问我们的网站,查看可以添加新信息图表的页面。 -2. 确保插图风格与我们的[网站](/assets/)相符。 -3. 访问我们的 GitHub 存储库,[创建一个问题](https://github.com/ethereum/ethereum-org-website/issues/new)并提交插图。 +2. 确保插图风格与我们的[素材](/assets/)一致。 +3. 前往我们的 GitHub 代码库,[提出一个问题](https://github.com/ethereum/ethereum-org-website/issues/new)来建议该插图。 4. 设计团队将进行审查。 5. 我们创建一个新问题,邀请开发者来实现新图像。 diff --git a/public/content/translations/zh/contributing/index.md b/public/content/translations/zh/contributing/index.md index a6f0e32ac62..a2bf2df1fb5 100644 --- a/public/content/translations/zh/contributing/index.md +++ b/public/content/translations/zh/contributing/index.md @@ -1,43 +1,49 @@ --- -title: 贡献力量 -description: 了解你可以为 ethereum.org 做出贡献的几种方式 +title: "贡献力量" +description: "了解你可以为 ethereum.org 做出贡献的几种方式" lang: zh --- -# 为 ethereum.org 贡献力量 🦄 {#contributing-to-ethereumorg} +# 为 ethereum.org 做贡献 🦄 {#contributing-to-ethereumorg} -Ethereum.org 是一个开源项目,有超过 **12,000** 名贡献者帮助翻译、编写、设计和维护网站。 +Ethereum.org 是一个开源项目,有 **12,000** 多名贡献者帮助翻译、编写、设计和维护网站。 我们是一个热情的社区,将帮助你在以太坊生态系统中学习和成长,同时也做出有意义的贡献并获得相关的实践经验! -## 如何做出贡献 {#ways-to-contribute} +## 贡献方式 {#ways-to-contribute} **翻译** -- [加入翻译计划](/contributing/translation-program/) – 帮助我们为 ethereum.org 增加新语言支持 + +- [加入翻译计划](/contributing/translation-program/) – 帮助我们将 ethereum.org 带给新的语言 **开发** -- [处理有待解决的问题](https://github.com/ethereum/ethereum-org-website/issues) - 我们确定需要开展的工作 + +- [处理待解决的问题](https://github.com/ethereum/ethereum-org-website/issues) – 我们已确定需要完成的工作 **设计** -- [帮助设计网站](/contributing/design/) — 任何水平的设计者都可以做出贡献来改进网站。 + +- [帮助设计网站](/contributing/design/) – 任何水平的设计师都可以为改进网站做出贡献 **内容** + - [创建/编辑内容](/contributing/#how-to-update-content) – 建议新页面或对现有内容进行调整 - [添加社区资源](/contributing/content-resources/) – 将有用的文章或资源添加到相关页面 -- [对设计资源提出建议](/contributing/design/adding-design-resources/) - 添加、更新和删除有用的设计资源 +- [建议设计资源](/contributing/design/adding-design-resources/) – 添加、更新和删除有用的设计资源 - [测验](/contributing/quizzes/) – 为相关页面添加、更新和删除测试题库 **功能创意** -- [申请功能](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=feature_request.yaml&title=) – 让我们了解你在新功能或设计方面的任何想法 + +- [请求新功能](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=feature_request.yaml&title=) – 让我们了解你对新功能或新设计的任何想法 **产品列表** + - [添加交易所](/contributing/adding-exchanges/) – 将交易所添加到我们的[交易所查找器](/get-eth/#country-picker) - [添加产品](/contributing/adding-products/) – 将去中心化应用程序或钱包添加到相关页面 - [添加开发者工具](/contributing/adding-developer-tools/) – 将开发者工具添加到相关页面 - [添加二层网络](/contributing/adding-layer-2s/) – 将二层网络添加到相关页面 -- [添加质押产品或服务](/contributing/adding-staking-products/) – 添加有助于促进单独质押、联合质押或质押即服务的项目 -- [添加钱包](/contributing/adding-wallets/) – 为[查找钱包页面](/wallets/find-wallet/)添加钱包 -- [为我们的去中心化科学页面建议项目](/contributing/adding-desci-projects/) – 添加基于以太坊构建的项目,为去中心化科学做贡献 +- [添加质押产品或服务](/contributing/adding-staking-products/) – 添加有助于促进个人质押、联合质押或质押即服务的项目 +- [添加钱包](/contributing/adding-wallets/) – 为[钱包查找页面](/wallets/find-wallet/)添加钱包 +- [为我们的 DeSci 页面建议项目](/contributing/adding-desci-projects/) – 添加基于以太坊构建、为去中心化科学做贡献的项目 有疑问吗? 🤔 加入我们的 [Discord 服务器](https://discord.gg/ethereum-org) @@ -49,27 +55,27 @@ Ethereum.org 是一个开源项目,有超过 **12,000** 名贡献者帮助翻 查看所有任务 -## 如何在 ethereum.org 上工作 {#how-to-update-content} +## 如何参与 ethereum.org 的工作 {#how-to-update-content} -如果你希望为[翻译计划](/contributing/translation-program/)做贡献,那么你需要在 [Crowdin](https://crowdin.com/project/ethereum-org) 上创建一个帐户。 对于其他所有任务,例如在网站上添加或编辑内容或视觉效果、修复错误、处理开放任务,你都需要一个 [GitHub](https://github.com/) 帐户。 +如果你希望参与[翻译计划](/contributing/translation-program/),你需要在 [Crowdin](https://crowdin.com/project/ethereum-org) 上创建一个帐户。 对于其他所有事项 – 在网站上添加或编辑内容或视觉效果、修复漏洞、处理开放任务 – 你都需要一个 [GitHub](https://github.com/) 帐户。 所有更新都是通过 GitHub 拉取请求流程进行的。 这意味着你要在网站上创建本地副本,做出你的更改,以及请求合并你的更改。 如果你以前从未这样做过,请按照我们 [GitHub 存储库](https://github.com/ethereum/ethereum-org-website)底部的说明进行操作。 你不需要权限来处理任何事情,但是最好让我们知道你打算做什么。 你可以这样做: -- 评论 [GitHub](https://github.com/ethereum/ethereum-org-website) 中的一个问题或拉取请求 +- 在 [GitHub](https://github.com/ethereum/ethereum-org-website) 上对议题或拉取请求 (PR) 发表评论 - 在我们的 [Discord 服务器](https://discord.gg/ethereum-org)上发消息 在做出贡献之前,请你了解以下内容: -- 不断发展的 [ethereum.org 愿景](/about/) +- ethereum.org 不断演进的[愿景](/about/) - 我们的[设计原则](/contributing/design-principles/) - 我们的[风格指南](/contributing/style-guide/) - 我们的[行为准则](/community/code-of-conduct) -## 如何做出有关网站的决定 {#how-decisions-about-the-site-are-made} +## 关于网站的决策是如何制定的 {#how-decisions-about-the-site-are-made} 关于个人拉取请求、设计演变和重大升级的决策,由来自整个以太坊生态系统的团队做出。 该团队包括项目管理人员、开发者、设计师、营销和通信人员以及主题专家。 社区的参与将为每项决策提供信息:因此请提出问题、提交拉取请求或联系该团队: @@ -81,29 +87,29 @@ Ethereum.org 是一个开源项目,有超过 **12,000** 名贡献者帮助翻 在向 ethereum.org 贡献任何内容或创意时,请仅使用你有权使用的原创作品或内容。 以太坊生态系统内的许多项目都使用开源许可,以便于自由分享信息。 但是,如果你找不到相关信息,请不要尝试将其添加到 ethereum.org。 被视为抄袭的拉取请求都将被拒绝。 -## 新接触开源项目? {#new-to-open-source} +## 新接触开源项目? 开源新手?{#new-to-open-source} -我们的 GitHub 存储库中有一些准入门槛较低的问题,专为刚接触开源设计的开发者设计,我们将这类问题标记为[入门优选问题](https://github.com/ethereum/ethereum-org-website/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)。 +我们的 GitHub 代码库中有一些低门槛的问题,专门为刚接触开源的开发者设计,并被标记为 [good first issue](https://github.com/ethereum/ethereum-org-website/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)。 -## 领取链上成就代币 (OAT) {#oat} +## 领取你的链上成就代币 (OAT) {#oat} -如果你的贡献被合并到 ethereum.org 中,你将有机会在 [Galxe](https://app.galxe.com/quest/ethereumorg) 上领取特殊徽章。 链上成就代币 (OAT) 是你助力改善生态系统的证明。 +如果你的贡献被合并到 ethereum.org,你将有机会在 [Galxe](https://app.galxe.com/quest/ethereumorg) 上领取一个特殊徽章。 链上成就代币 (OAT) 是你助力改善生态系统的证明。 -[关于链上成就代币的更多信息](https://help.galxe.com/en/articles/9645630-create-quest-rewards#h_1c5d63ba03) +[关于 OAT 的更多信息](https://help.galxe.com/en/articles/9645630-create-quest-rewards#h_1c5d63ba03) ### 如何领取 + 1. 加入我们的 [Discord 服务器](https://discord.gg/ethereum-org)。 -2. 在 `#🥇 | proof-of-contribution` 频道中粘贴指向你贡献的链接。 +2. 在 `#🥇 | proof-of-contribution` 频道中粘贴你的贡献链接。 3. 等待我们团队的成员向你发送链上成就代币链接。 4. 领取你的链上成就代币! 你只能使用自已保管的钱包来领取链上成就代币。 请勿使用交易所帐户或你未持有私人密钥的其他帐户,因为这些帐户不允许你访问和管理你的链上成就代币。 -## 领取你的 GitPOAP 徽章 {#claim-gitpoap} +## 领取你的 GitPOAP {#claim-gitpoap} GitPOAP 还将自动表彰你做出的合并贡献,并让你在其平台上单独铸造一枚特别贡献者 POAP 徽章! - ### 如何领取 {#how-to-claim} 1. 访问 [GitPOAP](https://www.gitpoap.io)。 diff --git a/public/content/translations/zh/contributing/quizzes/index.md b/public/content/translations/zh/contributing/quizzes/index.md index ea2d9d895ab..214dbec6842 100644 --- a/public/content/translations/zh/contributing/quizzes/index.md +++ b/public/content/translations/zh/contributing/quizzes/index.md @@ -1,10 +1,10 @@ --- -title: 添加测验 -description: 向 ethereum.org 添加测验时采用的政策 +title: "添加测验" +description: "向 ethereum.org 添加测验时采用的政策" lang: zh --- -# 测试 {#quizzes} +# 测验 {#quizzes} 测验让用户有机会自我检测,看看自己是否理解刚刚读过的页面内容。 问题应仅基于页面上提供的内容并且不应询问页面上未提及的信息。 @@ -13,13 +13,13 @@ lang: zh 一些现有测验的示例可以在下面找到: - [二层网络](/layer-2) -- [非同质化代币](/nft/) +- [NFT](/nft/) - [什么是以太坊?](/what-is-ethereum/) -- [以太币是什么?](/what-is-ether/) +- [什么是 ETH?](/what-is-ether/) ## 添加学习测验 -如果一个页面尚未创建学习测验,请为其[创建问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)。 +如果某个页面还没有为其创建学习测验,请为此 [创建议题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)。 请提供以下信息: @@ -32,7 +32,7 @@ lang: zh ## 添加测验问题 -如果你想将一个问题添加到测验的问题库中,请[创建问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)并提供以下信息: +如果您想向测验题库中添加问题,请 [创建议题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml) 并提供以下信息: - 你想要添加测验问题的页面 - 对于每个问题,提供以下信息: @@ -43,7 +43,7 @@ lang: zh ## 更新测验问题 -如果你想在测验的问题库中更新一个问题,请[创建问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)并提供以下信息: +如果您想更新测验题库中的问题,请 [创建议题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml) 并提供以下信息: - 你想要更新测验问题的页面 - 对于每个被更新的问题,提供以下信息: @@ -55,7 +55,7 @@ lang: zh ## 删除测验问题 -如果页面上和问题相关的内容不再存在并且需要删除问题,请[创建问题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml)以删除测验问题并提供以下信息: +如果页面上已不存在某个问题的内容,且该问题需要被删除,请 [创建议题](https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=&template=suggest_quiz.yaml) 以删除该问题,并提供以下信息: - 你想要删除测验问题的页面 - 你想要删除的问题 diff --git a/public/content/translations/zh/contributing/translation-program/faq/index.md b/public/content/translations/zh/contributing/translation-program/faq/index.md index 650379aa0b2..e8a747ff4e5 100644 --- a/public/content/translations/zh/contributing/translation-program/faq/index.md +++ b/public/content/translations/zh/contributing/translation-program/faq/index.md @@ -1,10 +1,10 @@ --- -title: 翻译计划常见问题 (FAQ) +title: "翻译计划常见问题 (FAQ)" lang: zh -description: 关于 ethereum.org 翻译计划的常见问题 +description: "关于 ethereum.org 翻译计划的常见问题" --- -# ethereum.org 翻译指南 {#translating-ethereum-guide} +# 翻译 ethereum.org 指南 {#translating-ethereum-guide} 如果你是翻译计划的新手,而且不知道从何下手,这里的一些常见问题会有所帮助。 使用本指南来寻找常见问题的答案。 @@ -18,31 +18,31 @@ ethereum.org 翻译计划是这种做法的延伸,其组织方式考虑到了 因此,这个翻译计划是开放和自愿的,参与不会得到补偿。 如果我们要按照翻译字数对翻译人员提供补偿,我们只会邀请那些有足够翻译经验的人(专业翻译人员)加入这个翻译计划。 这将导致翻译计划具有排他性,并阻止了我们实现所概述的目标。这个目标具体而言就是:允许所有人参加和参与到生态系统中。 -我们尽一切努力使我们的贡献者能够在以太坊生态系统中取得成功;许多非货币性的激励措施已经到位,如:[提供 POAP 徽章](/contributing/translation-program/acknowledgements/#poap)和[翻译人员证书](/contributing/translation-program/acknowledgements/#certificate),整理[翻译排行榜](/contributing/translation-program/acknowledgements/)和[列出我们网站上的所有翻译人员](/contributing/translation-program/contributors/)。 +我们尽一切努力帮助我们的贡献者在以太坊生态系统中取得成功;我们制定了许多非金钱激励措施,例如:[提供 POAP](/contributing/translation-program/acknowledgements/#poap) 和[翻译证书](/contributing/translation-program/acknowledgements/#certificate),以及组织[翻译排行榜](/contributing/translation-program/acknowledgements/)和[在网站上列出我们所有的翻译人员](/contributing/translation-program/contributors/)。 -## 如何翻译带有 `` 的语句? {#tags} +## 如何翻译带有 `` 的字符串? {#tags} -并非每个语句都以纯文本形式书写。 部分语句包含 HTML 标签 (`<0>` ``) 等混合脚本。通常是句子中的超链接或不同格式。 +并非每个语句都以纯文本形式书写。 有些字符串包含混合脚本,例如 HTML 标签(`<0>`、``)。这通常用于句子中间的超链接或替代样式。 -- 翻译标签内的文本,但不翻译标签本身。 不能翻译或删除 `<` 和 `>` 中的任何内容。 +- 翻译标签内的文本,但不翻译标签本身。 `<` 和 `>` 中的任何内容都不得翻译或删除。 - 为了保持语句完整,建议你点击左下方的"Copy Source"按钮。 这将复制原文语句并粘贴到文本框内。 这让你明确标签的位置,有助于避免错误。 -![高亮显示“复制原文”按钮的 Crowdin 界面](./html-tag-strings.png) +![Crowdin 界面,其中“复制原文”按钮高亮显示](./html-tag-strings.png) 你可以在语句中移动标签的位置,使其在句子中更加自然 – 但请确保移动整个标签。 -更多关于处理标签和代码片段的详细信息,请参阅 [《ethereum.org 翻译风格指南》](/contributing/translation-program/translators-guide/#dealing-with-tags)。 +有关处理标签和代码片段的更多深入信息,请参阅 [ethereum.org 翻译风格指南](/contributing/translation-program/translators-guide/#dealing-with-tags)。 ## 上下文在哪里? {#strings} 通常情况下,仅靠原文语句可能不足以让你提供准确翻译。 - 查看“屏幕截图”和“上下文”以获取更多信息。 在原文语句部分,你将看到附加的屏幕截图,从而了解使用该语句的上下文。 -- 如果仍然不确定,请在“COMMENTS”部分中添加标记。 [不知道如何评论?](#comment) +- 如果仍然不确定,请在“COMMENTS”部分中添加标记。 [不确定如何发表评论?](#comment) -![如何通过屏幕截图为语句提供上下文信息](./source-string.png) +![显示如何通过屏幕截图为字符串提供上下文](./source-string.png) -![为上下文添加一个示例屏幕截图](./source-string-2.png) +![为提供上下文而添加的示例屏幕截图](./source-string-2.png) ## 如何留下评论或问题? 我想标记一个问题或错别字... {#comment} @@ -52,16 +52,16 @@ ethereum.org 翻译计划是这种做法的延伸,其组织方式考虑到了 - 问题一旦提交,就将报告给我们的团队。 我们将解决这个问题,并通过回复评论和关闭问题来让你知道。 - 如果你提供不正确的翻译,那么在下次审核期间,母语人士将审核该翻译和你建议的替代方案。 -![如何发表评论和提出问题](./comment-issue.png) +![显示如何发表评论和提出问题](./comment-issue.png) ## 什么是翻译记忆库 (TM)? {#translation-memory} -翻译记忆库 (TM) 是一项 Crowdin 功能,可存储所有先前已翻译的 [ethereum.org](https://ethereum.org/) 中的语句。 翻译过的语句会自动保存到 TM 中。 这款实用工具可以帮助你节省时间! +翻译记忆库 (TM) 是一项 Crowdin 功能,可存储所有先前已翻译的 ethereum.org 中的语句。 翻译过的语句会自动保存到 TM 中。 这款实用工具可以帮助你节省时间! - 请看“TM and MT Suggestions”部分,你会看到其他翻译人员如何翻译相同或类似语句。 如果发现匹配率很高的建议,可以点击以引用该翻译内容。 - 如果列表中没有任何内容,你可以搜索 TM 中以前做过的翻译并重新使用以保持一致性。 -![翻译记忆库屏幕截图](./translation-memory.png) +![翻译记忆库的屏幕截图](./translation-memory.png) ## 如何使用 Crowdin 词汇表? {#glossary} @@ -71,19 +71,19 @@ Crowdin 词汇表是阐明术语和定义的最佳位置。 有两种方法来 - 首先,当你在原文语句上发现带下划线的术语时,将鼠标移到上面,即可看到简要定义。 -![词汇表定义示例](./glossary-definition.png) +![词汇表示例定义](./glossary-definition.png) - 第二,如果看到一个不熟悉但没有下划线的术语,你可以在词汇表选项卡(右侧列第三个按钮)中搜索。 你会找到特定术语和项目中常用术语的解释。 -![Crowdin 中“词汇表”选项卡位置的屏幕截图](./glossary-tab.png) +![显示 Crowdin 中“词汇表”选项卡位置的屏幕截图](./glossary-tab.png) - 如果仍然找不到,即可借此机会添加新术语! 我们建议你在搜索引擎上进行查找,并将描述添加到词汇表中。 这将非常有助于其他翻译人员更好地理解该术语。 -![如何向 Crowdin 添加词汇表术语的屏幕截图](./add-glossary-term.png) +![显示如何向 Crowdin 添加词汇表术语的屏幕截图](./add-glossary-term.png) ### 术语翻译政策 {#terminology} -_适用于名称(商标、公司、人员)和新技术术语(信标链、分片链等)_ +_适用于名称(品牌、公司、人员)和新技术术语(信标链、分片链等)_ 以太坊提出了很多最近出现的新术语。 由于没有各自语言的官方译本,因此翻译人员对有些术语的翻译不同。 这种不一致会造成误解,降低可读性。 @@ -93,7 +93,7 @@ _适用于名称(商标、公司、人员)和新技术术语(信标链、 如果发现你不熟悉的术语,我们建议你: -- 参考[词汇表](#glossary),你可能会发现其他翻译人员以前的译法。 如果你认为之前翻译的术语不恰当,请随时通过向 Crowdin 词汇表添加新术语来恢复你的译文。 +- 参考[术语表](#glossary),你可能会发现其他翻译人员以前的译法。 如果你认为之前翻译的术语不恰当,请随时通过向 Crowdin 词汇表添加新术语来恢复你的译文。 - 如果词汇表中之前没有翻译,我们建议你在搜索引擎或媒体文章中查找,显示该术语在社区中的实际使用情况。 - 如果根本找不到任何参考资料,请按你的直觉和理解翻译成自己的语言! - 如果不太确定,可以不翻译这一术语。 有时,英语术语足以提供准确定义。 @@ -102,18 +102,18 @@ _适用于名称(商标、公司、人员)和新技术术语(信标链、 ## 审核流程如何运作? {#review-process} -为确保我们翻译的质量和一致性达到一定的水平,我们与 [Acolad](https://www.acolad.com/)合作,它是全球最大的语言服务提供者之一。 Acolad 拥有 20,000 名专业语言学家,这意味着他们可以针对我们所需的每种语言和内容类型提供专业的审稿人。 +为确保我们翻译的质量和一致性达到一定水平,我们与 [Acolad](https://www.acolad.com/) 合作,它是全球最大的语言服务提供商之一。 Acolad 拥有 20,000 名专业语言学家,这意味着他们可以针对我们所需的每种语言和内容类型提供专业的审稿人。 -审核过程是简单明确的;在一个[内容存储桶](/contributing/translation-program/content-buckets)被全部翻译后,我们便会安排对该内容库进行审核。 审核过程直接在 Crowdin 进行。 当审核完成后,我们将用翻译内容更新网站。 +审核过程非常简单;一旦一组内容被 100% 翻译,我们就会为该内容集安排审核。 审核过程直接在 Crowdin 进行。 当审核完成后,我们将用翻译内容更新网站。 ## 如何以我的语言添加内容? {#adding-foreign-language-content} 目前,所有非英文内容都是直接从英文源内容翻译而来,任何不是以英文形式存在的内容都不能添加到其他语言中。 -要为 ethereum.org 推荐新内容,你可以在 GitHub 上[创建一个提议](https://github.com/ethereum/ethereum-org-website/issues)。 如果要添加的话,内容将用英语编写并使用 Crowdin 翻译成其他语言。 +要为 ethereum.org 推荐新内容,你可以在 GitHub 上[创建一个问题](https://github.com/ethereum/ethereum-org-website/issues)。 如果要添加的话,内容将用英语编写并使用 Crowdin 翻译成其他语言。 我们计划在不久的将来支持对于非英文内容的添加。 ## 联系我们 {#contact} -感谢阅读所有内容。 我们希望这对你加入我们的计划有所帮助。 欢迎加入我们的 [Discord 翻译频道](https://discord.gg/ethereum-org),提出问题并与其他翻译人员合作,或者通过 translations@ethereum.org 联系我们! +感谢阅读所有内容。 我们希望这对你加入我们的计划有所帮助。 欢迎随时加入我们的 [Discord 翻译频道](https://discord.gg/ethereum-org),提出问题并与其他翻译人员合作,或通过 translations@ethereum.org 联系我们! diff --git a/public/content/translations/zh/contributing/translation-program/how-to-translate/index.md b/public/content/translations/zh/contributing/translation-program/how-to-translate/index.md index 5d9f0995087..5580b450a79 100644 --- a/public/content/translations/zh/contributing/translation-program/how-to-translate/index.md +++ b/public/content/translations/zh/contributing/translation-program/how-to-translate/index.md @@ -1,18 +1,18 @@ --- -title: 如何翻译 +title: "如何翻译" lang: zh -description: 使用 Crowdin 翻译 ethereum.org 的操作指南 +description: "使用 Crowdin 翻译 ethereum.org 的操作指南" --- # 如何翻译 {#how-to-translate} -## 视频指南 {#visual-guide} +## 可视化指南 {#visual-guide} 更喜欢视频学习的人员请观看 Luka 演示如何设置 Crowdin。 或者,你可以在下一节找到书面形式的相同步骤。 -## 书面指南 {#written-guide} +## 文字指南 {#written-guide} ### 在 Crowdin 中参与我们的项目 {#join-project} @@ -22,9 +22,10 @@ description: 使用 Crowdin 翻译 ethereum.org 的操作指南 参与项目 -### 选择语言 {#open-language} +### 打开你的语言 {#open-language} -登录 Crowdin 后,你会看见项目描述和所有可用语言的列表。 每种语言还包含关于可翻译总字数的信息,并提供了特定语言中有多少内容已经翻译并获得批准的概况。 +登录 Crowdin 后,你会看见项目描述和所有可用语言的列表。 +每种语言还包含关于可翻译总字数的信息,并提供了特定语言中有多少内容已经翻译并获得批准的概况。 打开你想要翻译的目标语言,查看可翻译的文件列表。 @@ -34,23 +35,21 @@ description: 使用 Crowdin 翻译 ethereum.org 的操作指南 网站内容分为多个文档和内容存储桶。 可以在右边查看每个文档的进度 - 如果翻译进度低于 100%,请贡献你的力量! -找不到你的语言? [创建一个问题](https://github.com/ethereum/ethereum-org-website/issues/new/choose)或者在 [Discord](https://discord.gg/ethereum-org) 中联系我们。 +找不到你的语言? [创建问题](https://github.com/ethereum/ethereum-org-website/issues/new/choose)或在我们的 [Discord](https://discord.gg/ethereum-org) 中提问 ![Crowdin 中已翻译和未翻译的文件](./crowdin-files.png) -关于内容存储桶的说明:我们使用 Crowdin 中的“内容存储桶”功能最先发布最高优先级内容。 当你查看一种语言时(例如[菲律宾语](https://crowdin.com/project/ethereum-org/fil#)),会看到内容存储桶对应的文件夹,例如(“1. 首页”、“2. 基础知识”、“3. 探究”等)。 +关于内容存储桶的说明:我们使用 Crowdin 中的“内容存储桶”功能最先发布最高优先级内容。 当你查看一种语言时,例如 [菲律宾语](https://crowdin.com/project/ethereum-org/fil#) ,你会看到内容存储桶对应的文件夹(“1.”) 首页”、“2. 基础知识”、“3. 探究”等)。 我们建议按照数字顺序进行翻译 (1 → 2 → 3 → ⋯),以保证影响最大的页面最先得到翻译。 -[了解关于 ethereum.org 内容存储桶的更多信息](/contributing/translation-program/content-buckets/) - ### 翻译 {#translate} 当你选择想翻译的文件后,文件将在在线编辑器内打开。 如果你从未使用过 Crowdin,你可以通过这个快速指南来了解基础知识。 ![Crowdin 在线编辑器](./online-editor.png) -**_1 - 左侧边栏_** +**_1 – 左侧边栏_** - 未翻译(红色)– 尚未翻译的文本。 这些是你应该翻译的文本。 - 已翻译(绿色)– 已翻译但尚未审核的文本。 欢迎你提出其他翻译建议,或使用编辑器中的“+”和“-”按钮对现有翻译投票。 @@ -60,7 +59,8 @@ description: 使用 Crowdin 翻译 ethereum.org 的操作指南 **_2 – 编辑区域_** -主要翻译区域 – 源文本显示在顶部,还有更多上下文和屏幕截图(如果有)。 要添加新翻译,请在“Enter translation here”字段中输入你的翻译,然后点击“Save”。 +主要翻译区域 – 源文本显示在顶部,还有更多上下文和屏幕截图(如果有)。 +要添加新翻译,请在“Enter translation here”字段中输入你的翻译,然后点击“Save”。 还可以在此区域找到现有文本翻译和其他语言的翻译,以及翻译记忆库的匹配项和机器翻译建议。 @@ -70,9 +70,9 @@ description: 使用 Crowdin 翻译 ethereum.org 的操作指南 通过使用上面的按钮,你还可以切换到翻译记忆库,在其中搜索现有翻译,或者切换到词汇表,其中包含关键术语的描述和标准翻译。 -想了解更多信息? 可随时查看[关于使用 Crowdin 在线编辑器的文档](https://support.crowdin.com/online-editor/) +想了解更多信息? 欢迎随时查看[关于使用 Crowdin 在线编辑器的文档](https://support.crowdin.com/online-editor/) -### 审核过程 {#review-process} +### 审核流程 {#review-process} 一旦你完成翻译(即内容存储桶的所有文件均显示 100%),我们的专业翻译服务机构将审核(并可能编辑)你完成的内容。 一旦审核完成(即审核进度为 100%),我们会将内容添加到网站上。 @@ -85,7 +85,7 @@ description: 使用 Crowdin 翻译 ethereum.org 的操作指南 ### 联系我们 {#get-in-touch} -还有其他问题? 或者想与我们的团队和其他翻译人员合作? 请在我们的 [ethereum.org Discord 服务器](https://discord.gg/ethereum-org)的 #translations 频道中发帖 +还有其他问题吗? 或者想与我们的团队和其他翻译人员合作? 请在我们的 [ethereum.org Discord 服务器](https://discord.gg/ethereum-org) 的 #translations 频道中发帖 也可以通过向 translations@ethereum.org 发送邮件联系我们 diff --git a/public/content/translations/zh/contributing/translation-program/index.md b/public/content/translations/zh/contributing/translation-program/index.md index ace8481c5fa..ef42874b9b5 100644 --- a/public/content/translations/zh/contributing/translation-program/index.md +++ b/public/content/translations/zh/contributing/translation-program/index.md @@ -1,7 +1,7 @@ --- -title: 翻译计划 +title: "翻译计划" lang: zh -description: 关于 ethereum.org 翻译计划的信息 +description: "关于 ethereum.org 翻译计划的信息" --- # 翻译计划 {#translation-program} @@ -16,11 +16,11 @@ Ethereum.org 翻译计划是开放的,所有人都可以参与! 1. 你需要登录或注册 Crowdin 帐户。 2. 选择你想贡献翻译的语言。 -3. 在开始之前,请查看[如何翻译](/contributing/translation-program/how-to-translate/)指南,学习如何使用 Crowdin 和 [翻译风格指南](/contributing/translation-program/translators-guide/),了解相关提示和最佳做法。 +3. 在开始之前,请先阅读[如何翻译](/contributing/translation-program/how-to-translate/)指南,了解如何使用 Crowdin,并查看[翻译风格指南](/contributing/translation-program/translators-guide/),获取提示和最佳实践。 4. 机器翻译将不会被批准。 5. 所有翻译在添加到网站之前都会经过审核,因此你的翻译在上线之前会有一个短暂的延迟。 -_加入 [ethereum.org Discord](https://discord.gg/ethereum-org) 合作翻译、提问、分享反馈和想法,或加入翻译组。_ +_加入 [ethereum.org Discord](https://discord.gg/ethereum-org) 协作翻译、提问、分享反馈和想法,或加入一个翻译组。_ 开始翻译 @@ -32,35 +32,36 @@ _加入 [ethereum.org Discord](https://discord.gg/ethereum-org) 合作翻译、 Ethereum.org 翻译计划旨在通过将 Ethereum.org 和其他以太坊内容翻译成尽可能多的语言,让所有人都能参与以太坊。 -阅读更多关于 Ethereum.org 翻译计划[任务和愿景](/contributing/translation-program/mission-and-vision)的信息。 +阅读更多关于 ethereum.org 翻译计划的[使命和愿景](/contributing/translation-program/mission-and-vision)。 -### 我们迄今取得的进展 {#our-progress} +### 我们目前的进展 {#our-progress} -- [**超过 6,900 **位翻译人员](/contributing/translation-program/contributors/) -- 网站支持 **68** 种语言 -- [2024 年翻译了** 289 万**字](/contributing/translation-program/acknowledgements/) +- [**6,900 多名**翻译者](/contributing/translation-program/contributors/) +- **68** 种语言已在网站上线 +- [2024 年已翻译 **289 万**字](/contributing/translation-program/acknowledgements/) ### 致谢 {#acknowledgements} -成千上万社区成员参与 Ethereum.org 的翻译,他们是翻译计划的关键组成部分。 我们要感谢我们的翻译人员,并在他们的职业生涯中给予支持。 以下是我们对翻译人员的一些致谢方式: +成千上万社区成员参与 Ethereum.org 的翻译,他们是翻译计划的关键组成部分。 +我们要感谢我们的翻译人员,并在他们的职业生涯中给予支持。 以下是我们对翻译人员的一些致谢方式: #### 证书 {#certificate} -如果你参与了翻译计划,并且至少有 5000 个翻译的字词获得批准,就有资格获得 Ethereum.org 翻译人员证书。 [更多关于证书的信息](/contributing/translation-program/acknowledgements/#certificate) +如果你参与了翻译计划,并且至少有 5000 个翻译的字词获得批准,就有资格获得 Ethereum.org 翻译人员证书。 [关于证书的更多信息](/contributing/translation-program/acknowledgements/#certificate) #### OAT {#oats} -翻译计划的贡献者有资格根据 2024 年翻译的字数获得不同的 OAT(链上成就代币)。 链上成就代币是非同质化代币,可证明你对 ethereum.org 翻译计划的贡献。 [有关链上成就代币的更多信息](/contributing/translation-program/acknowledgements/#oats) +翻译计划的贡献者有资格根据 2024 年翻译的字数获得不同的 OAT(链上成就代币)。 链上成就代币是非同质化代币,可证明你对 ethereum.org 翻译计划的贡献。 [关于 OAT 的更多信息](/contributing/translation-program/acknowledgements/#oats) -#### 致谢翻译人员 {#translator-acknowledgements} +#### 译者致谢 {#translator-acknowledgements} -通过发布[排行榜](/contributing/translation-program/acknowledgements/)和[翻译计划全体贡献者名单](/contributing/translation-program/contributors/),对我们的优秀翻译人员致以公开感谢。 +通过[排行榜](/contributing/translation-program/acknowledgements/)和[翻译计划所有贡献者列表](/contributing/translation-program/contributors/)公开致谢我们的顶级译者。 #### 奖励 {#rewards} -过去,我们追加奖励了最活跃的贡献者,为其提供了 [Devcon](https://devcon.org/en/) 和 [Devconnect](https://devconnect.org/) 等以太坊会议的票证以及 Ethereum.org 专属商品。 +过去,我们曾向最活跃的贡献者追溯发放奖励,包括 [Devcon](https://devcon.org/en/) 和 [Devconnect](https://devconnect.org/) 等以太坊会议的门票以及 ethereum.org 独家周边商品。 我们一直在考虑一些创新方式来奖励我们的贡献者,敬请关注! @@ -68,23 +69,23 @@ Ethereum.org 翻译计划旨在通过将 Ethereum.org 和其他以太坊内容 如果你正在为翻译计划做贡献或考虑参与其中,应该查看以下翻译指南: -- [翻译风格指南](/contributing/translation-program/translators-guide/) _– 面向 ethereum.org 翻译人员的说明和技巧_ -- [翻译常见问题](/contributing/translation-program/faq/) _– 有关 ethereum.org 翻译计划的一些常见问题与解答_ -- [Crowdin 在线编辑器指南](https://support.crowdin.com/online-editor/) _- 使用 Crowdin 在线编辑器和 Crowdin 一些高级功能的深度指南_ -- [内容存储桶](/contributing/translation-program/content-buckets/) _– ethereum.org 的每个内容存储桶中包含哪些页面_ +- [翻译风格指南](/contributing/translation-program/translators-guide/) _– 面向 ethereum.org 译者的说明和提示_ +- [翻译常见问题解答](/contributing/translation-program/faq/) _– 关于 ethereum.org 翻译计划的常见问题与解答_ +- [Crowdin 在线编辑器指南](https://support.crowdin.com/online-editor/) _– 关于如何使用 Crowdin 在线编辑器和 Crowdin 部分高级功能的深度指南_ -有关其他有用的翻译工具、翻译人员社区和翻译计划博客文章,请访问[资源页面](/contributing/translation-program/resources/)。 +有关其他有用的翻译工具、译者社区和翻译计划博客文章,请访问[资源页面](/contributing/translation-program/resources/)。 ## 联系我们 {#get-in-touch} -还有其他问题吗? 或者想与我们的团队和其他翻译人员合作? 请在我们 [ethereum.org Discord 服务器](https://discord.gg/ethereum-org)的 #translations 频道中发帖 +还有其他问题吗? 或者想与我们的团队和其他翻译人员合作? 请在我们的 [ethereum.org Discord 服务器](https://discord.gg/ethereum-org) 的 #translations 频道中发帖 也可以通过向 translations@ethereum.org 发送邮件联系我们 -## 开始你自己的翻译计划 {#starting-a-translation-program} +## 启动你自己的翻译计划 {#starting-a-translation-program} -我们致力于将以太坊内容翻译成尽可能多的语言,并向所有人提供教育内容。 我们对翻译很重视,希望帮助其他以太坊项目组织、管理和改进他们的翻译工作。 +我们致力于将以太坊内容翻译成尽可能多的语言,并向所有人提供教育内容。 +我们对翻译很重视,希望帮助其他以太坊项目组织、管理和改进他们的翻译工作。 -出于这个原因,我们制作了一本[翻译计划手册](/contributing/translation-program/playbook/),其中包含我们在翻译 ethereum.org 的过程中获得的一些技巧和最佳做法。 +为此,我们创建了[翻译计划手册](/contributing/translation-program/playbook/),其中包含我们在翻译 ethereum.org 过程中总结的一些技巧和最佳实践。 想要进一步合作或使用我们的一些翻译资源? 对手册有任何反馈意见? 我们很乐意通过 translations@ethereum.org 听到你们的声音。 diff --git a/public/content/translations/zh/contributing/translation-program/mission-and-vision/index.md b/public/content/translations/zh/contributing/translation-program/mission-and-vision/index.md index 774035687ea..3ad538a762f 100644 --- a/public/content/translations/zh/contributing/translation-program/mission-and-vision/index.md +++ b/public/content/translations/zh/contributing/translation-program/mission-and-vision/index.md @@ -1,10 +1,10 @@ --- -title: 使命和愿景 +title: "使命和愿景" lang: zh -description: Ethereum.org 翻译计划的使命和愿景 +description: "Ethereum.org 翻译计划的使命和愿景" --- -# 使命和愿景 {#mission-and-vision} +# 使命与愿景 {#mission-and-vision} 以太坊社区旨在成为全球化和包容性的社区,但其大部分内容仅面向英语使用者,而忽略了全球 60 亿非英语使用者。 为了使 ethereum.org 成为全球社区进入以太坊的门户,我们认为很有必要为非英语国家人士按母语提供以太坊内容。 diff --git a/public/content/translations/zh/contributing/translation-program/playbook/index.md b/public/content/translations/zh/contributing/translation-program/playbook/index.md new file mode 100644 index 00000000000..8dfcf4512ab --- /dev/null +++ b/public/content/translations/zh/contributing/translation-program/playbook/index.md @@ -0,0 +1,317 @@ +--- +title: "翻译程序操作手册" +lang: zh +description: "建立翻译项目的实用技巧与重要注意事项合集" +--- + +# 翻译程序操作手册{#translation-program-playbook} + +英语是世界上使用最广泛的语言之一,也是迄今为止全球学习人数最多的语言。 由于英语是互联网上最常用的语言——尤其在社交媒体领域——且多语言编程语言较为稀缺,区块链领域的大部分内容都以英语为母语编写。 + +然而,全球超过60亿人(占总人口的75%以上)完全不会说英语,这为绝大多数人接触以太坊设置了巨大的门槛。 + +正因如此,该领域越来越多的项目正寻求将内容翻译成不同语言并进行本地化,以面向全球市场。 + +提供多语言内容是拓展全球社区、为非英语使用者提供教育、确保内容与信息触达更广泛受众、并吸引更多人加入该领域的简单而有效的方式。 + +本指南旨在解决内容本地化过程中常见的挑战与误解。 它提供了一个分步指南,涵盖内容管理、翻译与审校流程、质量保证、译员招募以及本地化流程中的其他关键环节。 + +## 内容管理 {#content-management} + +翻譯內容管理是指通過自動化翻譯工作流程,消除重複性手動操作,提升效率與質量,實現更佳管控,並促進協作的過程。 + +在本地化过程中,内容管理存在多种不同的方法,具体取决于内容类型和您的需求。 + +管理内容的基本方法是创建双语文件,其中包含源文本和目标文本。 这种译法很少被采用,因为除了简洁之外,它并无显著优势。 + +翻译机构通常通过使用翻译管理软件或本地化工具来管理翻译项目,这些工具不仅具备项目管理功能,还能对文件、内容及译员实现更全面的管控。 + +阅读更多关于内容管理的信息: + +[Trados 谈何为翻译管理](https://www.trados.com/solutions/translation-management/) + +[关于多语言内容管理的用语](https://phrase.com/blog/posts/multilingual-content-management/) + +### 翻译管理软件{#translation-management-software} + +市面上有许多翻译管理系统和本地化工具,软件的选择主要取决于您的具体需求。 + +尽管某些项目选择不使用翻译管理系统,而倾向于手动翻译——无论是直接在双语文件中操作,还是借助GitHub等托管服务——这种做法都会显著降低项目控制力、生产效率、翻译质量、可扩展性及协作能力。 这种方法可能最适合小型或一次性翻译项目。 + +快速了解一些功能强大且广泛使用的翻译管理工具: + +**最适合众包和协作** + +[Crowdin](https://crowdin.com/) + +- 对开源项目免费 (不限字数和项目) +- 所有计划均提供 TM 和词汇表 +- 支持超过 60 种文件类型,超过 70 种 API 集成 + +[Lokalise](https://lokalise.com/) + +- 2 名团队成员可免费使用,更多成员需选用付费方案(大多数方案对字符串数量有限制) +- 一些付费计划均提供 TM 和词汇表 +- 支持超过 30 种文件类型,超过 40 种 API 集成 + +[Transifex](https://www.transifex.com/) + +- 只有付费方案(大多数方案对字符串数量有限制) +- 所有付费计划均提供 TM 和词汇表 +- 支持超过 30 种文件类型,超过 20 种 API 集成 + +[Phrase](https://phrase.com/) + +- 只有付费方案(所有方案都有无限制的字符串数量,项目团队成员数量则有限制) +- 一些付费计划均提供 TM 和词汇表 +- 支持超过 40 种文件类型,超过 20 种 API 集成 + +[Smartcat](https://www.smartcat.com/) + +- 有基础的免费方案和付费的高级功能(所有方案都有无限制的字符串和项目数量) +- 所有计划均提供 TM 和词汇表 +- 支持超过 60 种文件类型,超过 20 种 API 集成 + +[POEditor](https://poeditor.com/) + +- 对开源项目免费(所有项目有字符串数量限制,开源项目无限制) +- 付费计划提供 TM 和词汇表 +- 支持超过 20 种文件类型,超过 10 种 API 集成 + +以及很多其他选择…… + +**专业翻译工具** + +[SDL Trados Studio](https://www.trados.com/products/trados-studio/) + +- 为自由译者和团队提供的付费计划 +- 功能强大的计算机辅助翻译 (CAT) 工具与翻译人员效率提升软件 + +[MemoQ](https://www.memoq.com/) + +- 提供有限免费版本,同时设有多个付费方案以解锁高级功能。 +- 面向企业、语言服务提供商及翻译人员的翻译管理软件 + +[Memsource](https://www.memsource.com/) + +- 个人翻译者免费使用,团队用户则提供多种付费方案。 +- 云端计算机辅助翻译与翻译管理系统 + +以及很多其他选择…… + +阅读更多关于翻译管理软件的信息: + +[维基百科对翻译管理系统的定义](https://en.wikipedia.org/wiki/Translation_management_system) + +[Phrase:每个翻译管理软件都应具备的 7 个要素](https://phrase.com/blog/posts/7-things-every-translation-management-software-should-have/) + +[MemoQ 解读:何为翻译管理系统](https://www.memoq.com/tools/what-is-a-translation-management-system) + +[Gengo 推荐的 16 款最佳翻译管理系统](https://gengo.com/translator-product-updates/16-best-translation-management-systems/) + +## 工作流程 {#workflow} + +在翻译领域,翻译工作流程可以指代几种不同的含义,这些含义既相互关联,又是项目中需要重点考虑的因素。 + +我们将在下文探讨这两种情况。 + +**含义 1** + +这可能是人们理解翻译工作流程最常见的方式,也是听到“工作流程”这个词时通常会想到的内容。 + +本质上,这是从开始考虑翻译到在产品中使用翻译内容的整个工作流程。 + +在此情况下,一个示例工作流如下: + +1. **翻译文件的准备工作**——听起来很简单,但你需要考虑几个重要事项。 在此步骤中,您应该对整个流程的运作方式有清晰的规划。 + +- _你将使用哪些文件类型? 您希望以何种格式接收翻译后的文件?_ + - 若您的内容以DOCX或MD格式提供,翻译过程将比处理PDF版本的白皮书或其他文档简单得多。 +- _哪些本地化工具支持这种文件类型? 能否在翻译该文件时保留原始格式?_ + - 并非所有文件类型都支持直接本地化(例如PDF文件、图像文件),也并非所有本地化工具都支持所有文件类型。 +- _谁将翻译内容? 您将选择专业翻译服务还是依靠志愿者?_ + - 这会影响到你需要做出的其他若干决定。 例如,专业翻译人员比志愿者更擅长使用高级本地化工具。 +- _你对语言学家有什么期望? 如果您正在使用语言服务供应商,他们对您有什么期望?_ + - 这是确保您的目标、期望和时间表保持一致的关键步骤。 +- 所有待译内容的重要性是否相同? 应该优先翻译哪些内容吗?_ + - 存在若干方法可用于确定特定内容的优先级,这些内容应优先进行翻译与实施。 例如,如果你有大量内容需要翻译,可以使用版本控制来确保译者清楚哪些内容需要优先处理。 + +2. **共享待译文件**——这一步骤同样需要长远考量,并非像将源文件发送给语言服务供应商那样简单直接。 + +- _谁将翻译内容? 多少人会参与到该流程中?_ + - 若计划使用本地化工具,此步骤将得到简化,因为您可以直接将源文件上传至该工具。 即使翻译过程在托管服务上进行,情况也是如此,因为源文件无需导出到任何地方。 +- _源文件将进行人工处理,还是可以实现自动化处理?_ + - 大多数本地化工具都支持某种形式的文件管理流程集成或自动化。 另一方面,若您采用的是独立译员协作模式而非本地化工具,手动向数百甚至数千名译员发送源文件的做法显然难以实现规模化运作。 +- _将使用哪些工具进行本地化?_ + - 这个问题的答案将决定你处理其他所有事情的方式。 选择合适的工具可助您实现内容管理自动化,包括管理翻译记忆库和术语库、管理译员、追踪翻译/审校进度等,因此请花些时间研究您想要使用的工具。 若您不打算使用本地化工具,则上述所有操作均需手动完成。 +- _翻译流程需要多长时间? 要花多少钱?_ + - 此时,您应该准备好将源文件分享给语言服务提供商或翻译团队。 语言服务供应商可协助您分析字数统计并提供报价,其中包含翻译流程的费率及时间安排。 +- _您是否计划在此过程中对源内容进行修改/更新?_ + - 如果您的内容具有动态性且频繁变更,任何修改或更新都可能打乱翻译进度。 使用翻译记忆库可显著缓解此问题,但仍需仔细规划工作流程,避免阻碍译者的翻译进度。 + +3. **管理翻译流程**——源内容移交给语言服务供应商或译员后,您的工作并未结束。 为确保翻译质量达到最佳水平,内容创作者应尽可能深度参与翻译流程。 + +- _您计划如何与译员进行沟通?_ + - 若您计划使用本地化工具,沟通可直接在工具内进行。 建议与译员建立备用沟通渠道,因为他们可能更愿意主动联系,而即时通讯工具能实现更自由的交流。 +- _如何处理翻译者的问题? 谁应该回答这些问题?_ + - 翻译者(专业与非专业人士) 经常会带着疑问,想弄清问题的请求,或者其它的补充内容,反馈与改进建议来主动联系我们。 回应像这类的询问有助于提高与翻译者的互动率和译文的质量。 给他们提供尽可能多的资源同样很有意义(如指南,提示,专业术语指南,常见答疑等)。 +- _审核流程如何进行? 想要外包这个项目,或者您有能力在内部审核? + - 虽然审核不总是硬性要求,但审核是一个合格翻译流程的重要部分。 通常来说,让专业译者外包审核流程是最简单的。 但是,如果您拥有一个强大的国际团队,审核或答疑也可以在内部进行。 + +4. 发布译文 — 翻译流程的最后一部分,不过提前规划它依旧很重要。 + +- 所有的译文都会在同一时间完成吗? + - 如果答案是否定的,那么您应该考虑哪些译文应当被优先发布,如何实时追踪正在进行的翻译流程,翻译完成时应怎样发布。 +- _翻译内容将如何交付给你? 它将以什么格式呈现?_ + - 无论采用哪种方法,这都是一个重要的考量因素。 本地化工具能让您保持对目标文件格式和导出过程的控制,并且通常支持自动化,例如通过与托管服务的集成来实现。 +- _您将如何在项目中实施翻译?_ + - 在某些情况下,这可能简单到只需上传翻译文件或将其添加到文档中。 然而,对于更复杂的项目,如网站或应用程序的翻译,您应确保代码支持国际化,并提前规划好实施流程。 +- _如果格式与源文件不同会怎样?_ + - 与上述情况类似,如果您翻译的是简单的文本文件,格式可能并不至关重要。 然而,对于更复杂的文件,如网站或应用程序的内容,格式和代码必须与源文件完全一致,以便在您的项目中实施。 否则,目标文件将需要由翻译人员或您的开发者进行编辑。 + +**含义 2** + +另一种翻译工作流程,它不考虑内部决策和方法。 这里主要关注的是内容本身的流动。 + +在此情况下,一个示例工作流如下: + +1. _翻译 → 实现_ + +- 最简单的工作流程,由于在实施前没有审查或质量保证流程来评估和编辑翻译,因此翻译很可能由人工完成。 +- 采用此工作流程时,确保译员能够维持一定的翻译质量至关重要,这需要项目经理与译员之间具备充分的资源支持和有效沟通。 + +2. _翻译 → 审核 → 实现_ + +- 一个更高级的工作流程,包含审阅和编辑环节,以确保翻译质量达到可接受且一致的标准。 +- 针对这一工作流程,存在多种实施方案:翻译环节可由专业译员或志愿者完成,而审校工作则通常由熟悉目标语言语法与正字法规范的专业审校人员负责。 + +3. _翻译 → 审核 → QA → 实现_ + +- 确保最高质量水平的最佳工作流程。 虽然质量检查并非总是必需,但在翻译和审校后,它能帮助您更好地了解译文的质量。 +- 通过这一流程,翻译工作可以完全由志愿者甚至机器翻译来完成。 审校环节则应由专业译员负责,而质量保证 (QA) 可由语言服务提供商承担,如果公司内部有目标语言的母语员工,也可自行完成。 + +阅读更多关于翻译工作流程的信息: + +[Content Rules 谈翻译工作流程的五个阶段](https://contentrules.com/creating-translation-workflow/) + +[Smartling 关于翻译工作流管理的解读](https://www.smartling.com/resources/101/what-is-translation-workflow-management/) + +[RixTrans 翻译流程详解](https://www.rixtrans.com/translation-workflow) + +## 术语管理 {#terminology-management} + +制定明确的术语处理方案,是确保翻译质量与一致性、节省译员时间的关键步骤之一。 + +在翻译领域,这被称为术语管理,是语言服务提供商除提供语言专家资源库和内容管理外,为客户提供的核心服务之一。 + +术语管理是指识别、收集和管理对项目至关重要且必须始终确保准确、一致翻译的术语的过程。 + +开始思考术语管理时,有几个步骤需要遵循: + +- 确定应纳入术语库的关键术语。 +- 创建术语及其定义的词汇表。 +- 翻译术语并将它们添加到词汇表。 +- 检查并批准翻译。 +- 维护术语表,并在新术语变得重要时及时更新。 + +阅读更多关于术语管理的信息: + +[Trados 谈术语管理](https://www.trados.com/solutions/terminology-management/translation-101-what-is-terminology-management.html) + +[Language Scientific 谈术语管理的重要性](https://www.languagescientific.com/terminology-management-why-it-matters/#:~:text=Terminology%20management%20is%20the%20process,are%20related%20to%20each%20other.) + +[Clear Words Translation 谈术语管理是什么及其重要性](http://clearwordstranslations.com/language/en/what-is-terminology-management/) + +### 翻译记忆和词汇表 {#tm-and-glossary} + +翻译记忆库与术语表是翻译行业中的重要工具,也是大多数语言服务提供商所依赖的核心资源。 + +让我们来看看这些术语的含义以及它们之间的区别: + +**翻译记忆库 (TM)** – 一种自动存储文本片段或字符串的数据库,涵盖较长的文本块、完整句子、段落及独立术语,同时记录其在各语言中的当前及历史翻译版本。 + +大多数本地化工具、翻译管理系统以及计算机辅助翻译工具都内置了翻译记忆库,这些记忆库通常也可以导出,并在其他同类工具中使用。 + +使用翻译记忆库的好处包括:加快翻译速度、提升翻译质量、在更新或更改源内容时保留特定翻译,以及对重复内容降低翻译成本。 + +翻译记忆库的工作原理基于不同文本片段之间的匹配百分比,通常在两个片段包含超过 50% 相同内容时最为有效。 它们还被用于自动翻译重复的句段,这些句段是 100% 匹配的,从而无需对重复内容进行多次翻译。 + +阅读更多关于翻译记忆的信息: + +[Memsource 谈翻译记忆库](https://www.memsource.com/translation-memory/) + +[Smartling 谈什么是翻译记忆库](https://www.smartling.com/resources/101/what-is-translation-memory/) + +**术语表 –** 一份包含重要或敏感术语、其定义、功能及既定翻译的清单。 术语表与翻译记忆库的主要区别在于,术语表并非自动生成,且不包含完整句子的翻译。 + +大多数本地化工具、翻译管理系统以及计算机辅助翻译工具都内置了术语表,您可以对其进行维护,以确保其中包含对项目至关重要的术语。 与翻译记忆库类似,术语表通常也可以导出,并在其他本地化工具中使用。 + +在启动翻译项目之前,强烈建议您花些时间,为译员和审校人员创建一份术语表。 使用术语表能确保重要术语的准确翻译,为译者提供必要的上下文,并保证翻译的一致性。 + +尽管术语表通常包含目标语言的既定翻译,但即便没有这些翻译,它们同样具有实用价值。 即使没有既定的翻译,术语表也可以包含技术术语的定义,突出不应翻译的术语,并告知译者某个特定术语是作为名词、动词、专有名词还是其他词性使用。 + +阅读更多关于术语表的信息: + +[Lionbridge 谈什么是翻译术语表](http://info.lionbridge.com/rs/lionbridge/images/Lionbridge%20FAQ_Glossary_2013.pdf) + +[Transifex 谈术语表](https://docs.transifex.com/glossary/glossary) + +如果您不打算在项目中使用本地化工具,则可能无法使用翻译记忆库和术语表(您可以在 Excel 文件中创建术语表或术语库,但自动化的术语表能免除翻译人员手动查找术语及其定义的需要)。 + +这意味着所有重复和相似的内容每次都需要人工翻译。 此外,翻译人员还需要就某些术语是否需要翻译、在文本中如何使用以及是否已有既定译法等问题进行咨询。 + +_您希望在项目中使用 ethereum.org 的翻译记忆库和术语表吗? 通过向 translations@ethereum.org._ 发送邮件联系我们 + +## 翻译者宣传 {#translator-outreach} + +**与语言服务供应商合作** + +如果您正在与语言服务提供商及其专业译员合作,那么这部分内容对您可能不太适用。 + +在这种情况下,选择一家能够以多种语言提供您所需全部服务(如翻译、审校、质量保证)的语言服务提供商至关重要。 + +虽然仅凭报价选择语言服务提供商可能颇具诱惑,但值得注意的是,大型语言服务提供商收费较高自有其道理。 + +- 他们的数据库中拥有数以万计的语言专家,这意味着他们能够为您的项目指派具备足够经验和特定领域知识的翻译人员(例如技术翻译专家)。 +- 他们在处理各类项目及满足客户多样化需求方面拥有丰富经验。 这意味着他们更能适应您独特的工作流程,为您的翻译过程提供宝贵建议和潜在改进方案,并确保满足您的需求、要求及交付期限。 +- 大多数大型语言服务提供商都拥有自己的本地化工具、翻译记忆库和术语表供您使用。 即便没有,他们也至少储备了足够多的语言专家,以确保其译员能够熟悉并熟练操作您希望使用的任何本地化工具。 + +您可以在[2021 年 Nimdzi 100 报告](https://www.nimdzi.com/nimdzi-100-top-lsp/)中找到全球最大语言服务提供商的深度对比分析,包括各公司的详细信息、按服务类型划分的细分数据、地理分布情况等内容。 + +**与非专业译者合作** + +您可能正在与非专业译员合作,并寻找志愿者协助翻译工作。 + +接触并邀请他人加入您的项目有多种途径。 这主要取决于您的产品特性以及您现有社区的规模。 + +以下是招募志愿者的一些方式概述: + +**外联 –** 尽管以下各点已有所涉及,但主动接触潜在志愿者并确保他们了解您的翻译项目,这本身就是一种有效的方式。 + +许多人渴望参与并为他们喜爱的项目贡献力量,但常常苦于非开发者或缺乏专业技术,找不到明确的参与途径。 若能提升项目的知名度,许多双语人士很可能对此表现出浓厚兴趣。 + +**深入社区内部探索 –** 该领域的大多数项目已拥有庞大且活跃的社区基础。 许多社区成员或许会乐于以简单的方式为项目贡献力量。 + +尽管参与开源项目通常源于内在动力,但它同时也是一次绝佳的学习机会。 任何对您的项目感兴趣的人,很可能都乐意以志愿者身份加入翻译计划,因为这不仅能让他们为自己关心的事业贡献力量,还能在实践过程中获得深入的学习体验。 + +**在产品中提及计划 –** 如果您的产品广受欢迎且用户众多,在使用过程中突出展示您的翻译计划并号召用户参与,效果会非常显著。 + +这可以简单到在您的应用或网站上为产品添加一个带有行动号召的横幅或弹窗。 这种方法之所以有效,是因为您的目标受众正是您的社区成员——他们是最有可能首先参与进来的人群。 + +**社交媒体 –** 社交媒体是宣传您的翻译项目、联系您的社区成员以及吸引尚未成为社区成员的其他人的有效途径。 + +若您拥有 Discord 服务器或 Telegram 频道,可便捷地将其用于项目推广、与译者沟通及致谢贡献者。 + +像 X(前身为 Twitter)这样的平台同样有助于吸纳新社区成员,并公开表彰您的贡献者。 + +Linux 基金会发布了一份内容详尽的[《2020 FOSS 贡献者调查报告》](https://www.linuxfoundation.org/wp-content/uploads/2020FOSSContributorSurveyReport_121020.pdf),分析了开源贡献者及其动机。 + +## 结论 {#conclusion} + +本文档包含每个翻译项目都应了解的一些关键考量因素。 这绝不是一份详尽的指南,但可以帮助任何没有翻译行业经验的人为他们的项目组织翻译计划。 + +若您希望获得关于翻译项目管理中不同工具、流程及关键环节的更详尽指导与解析,一些大型语言服务提供商设有博客专栏,定期发布本地化流程各维度的专业文章。 如果您想深入研究以上任何主题并专业地了解本地化流程的运作方式,这些都是最好的资源。 + +每节末尾附有相关链接;但是,您可以在线找到许多其他资源。 + +若要获取合作提案,或想了解更多关于维护 ethereum.org 翻译项目过程中我们积累的信息、经验教训和最佳实践,欢迎随时通过 translations@ethereum.org 与我们联系。 diff --git a/public/content/translations/zh/contributing/translation-program/resources/index.md b/public/content/translations/zh/contributing/translation-program/resources/index.md index 275df67c777..3df82cab7e6 100644 --- a/public/content/translations/zh/contributing/translation-program/resources/index.md +++ b/public/content/translations/zh/contributing/translation-program/resources/index.md @@ -1,34 +1,38 @@ --- -title: 翻译人员的资源 +title: "翻译人员的资源" lang: zh -description: 对 ethereum.org 翻译人员有用的资源 +description: "对 ethereum.org 翻译人员有用的资源" --- -# 资源 {#resources} +# 资源{#resources} 你可以在下面找到一些对 ethereum.org 翻译人员有用的指南和工具,还可以找到翻译社区和最新进展。 ## 指南 {#guides} -- [翻译风格指南](/contributing/translation-program/translators-guide/) _– 面向 ethereum.org 翻译人员的说明和技巧_ -- [翻译常见问题](/contributing/translation-program/faq/) _– 有关 ethereum.org 翻译计划的一些常见问题与解答_ -- [Crowdin 在线编辑器指南](https://support.crowdin.com/online-editor/) _- 使用 Crowdin 在线编辑器和 Crowdin 一些高级功能的深度指南_ -- [内容存储桶](/contributing/translation-program/content-buckets/) _– ethereum.org 的每个内容存储桶中包含哪些页面_ +- [翻译风格指南](/contributing/translation-program/translators-guide/) _– ethereum.org 翻译人员指南和技巧_ +- [翻译常见问题解答](/contributing/translation-program/faq/) _– 关于 ethereum.org 翻译计划的常见问题与解答_ +- [Crowdin 在线编辑器指南](https://support.crowdin.com/online-editor/) _– 关于如何使用 Crowdin 在线编辑器和 Crowdin 部分高级功能的深度指南_ ## 工具 {#tools} -- [Linguee](https://www.linguee.com/) _– 翻译和字典搜索引擎,可按词或短语搜索_ -- [Proz 术语搜索](https://www.proz.com/search/) _– 专业术语的翻译字典和词汇表数据库_ -- [Eurotermbank](https://www.eurotermbank.com/) _ – 42 种语言的欧洲术语集_ +- [Linguee](https://www.linguee.com/) + _– 翻译和字典搜索引擎,可按词或短语搜索_ +- [Proz 术语搜索](https://www.proz.com/search/) + _– 专业术语的翻译字典和词汇表数据库_ +- [Eurotermbank](https://www.eurotermbank.com/) + _– 42 种语言的欧洲术语集_ ## 社区 {#communities} -- [特定语种的 Discord 翻译团体](https://discord.gg/ethereum-org) _ – 在 ethereum.org 翻译人员与翻译团体之间建立联系的倡议举措_ -- [中文翻译人员团体](https://www.notion.so/Ethereum-org-05375fe0a94c4214acaf90f42ba40171) _– 方便中文翻译人员之间协作的 Notion 页面_ +- [特定语种的 Discord 翻译团体](https://discord.gg/ethereum-org) + _– 在 ethereum.org 翻译人员与翻译团体之间建立联系的倡议举措_ +- [中文翻译小组](https://www.notion.so/Ethereum-org-05375fe0a94c4214acaf90f42ba40171) + _– 方便中文翻译人员协调工作的 Notion 页面_ -## 最近更新 {#latest-updates} +## 最新更新 {#latest-updates} -要及时了解翻译计划的最新进展,可以关注[以太坊基金会博客](https://blog.ethereum.org/): +要及时了解翻译计划的最新进展,可以关注 [以太坊基金会博客](https://blog.ethereum.org/): - [2021 年 10 月里程碑更新](https://blog.ethereum.org/2021/10/04/translation-program-update/) - [2020 年 12 月里程碑更新](https://blog.ethereum.org/2020/12/21/translation-program-milestones-updates-20/) @@ -37,8 +41,9 @@ description: 对 ethereum.org 翻译人员有用的资源 ## 翻译人员官方互动时间 {#office-hours} -每个月的第二个星期三是翻译人员的官方互动时间。 互动会在 [ethereum.org 的 Discord](https://discord.gg/ethereum-org) #官方互动时间频道举办,你也可以在那里查看确切的举行时间和其他详细信息。 +每个月的第二个星期三是翻译人员的官方互动时间。 官方互动时间将在 [ethereum.org Discord](https://discord.gg/ethereum-org) 的 #office-hours 语音频道进行,你也可以在那里找到确切的时间和其他详细信息。 -在官方互动时间,我们的翻译人员可以询问有关翻译流程的问题,提出有关翻译计划的反馈,分享交流他们的想法,或者单纯与 ethereum.org 的核心团队聊天。 最后,我们希望通过这些电话会议传达翻译计划取得的最新进展,并与我们的贡献者分享重要的技巧和说明。 +在官方互动时间,我们的翻译人员可以询问有关翻译流程的问题,提出有关翻译计划的反馈,分享交流他们的想法,或者单纯与 ethereum.org 的核心团队聊天。 +最后,我们希望通过这些电话会议传达翻译计划取得的最新进展,并与我们的贡献者分享重要的技巧和说明。 如果你是 ethereum.org 翻译人员或想要成为翻译人员,欢迎加入任何一场我们的官方互动时间。 diff --git a/public/content/translations/zh/contributing/translation-program/translatathon/details/index.md b/public/content/translations/zh/contributing/translation-program/translatathon/details/index.md new file mode 100644 index 00000000000..1d59190e5af --- /dev/null +++ b/public/content/translations/zh/contributing/translation-program/translatathon/details/index.md @@ -0,0 +1,90 @@ +--- +title: "详细信息和规则" +lang: zh +template: translatathon +--- + +![](./participate.png) + +Translatathon 面向所有人开放,任何人都可以通过填写申请表和加入 Crowdin 中的项目来参与。 + +在翻译期间,译员可以通过在 Crowdin 编辑器中为自己所用语言的未翻译字符串提供翻译来收集积分。 + +每位参与者的最终得分由其在翻译期间所翻译的字数,以及其收集到的任何潜在奖励积分决定的,并以此为根据在排行榜上进行排名。 + +## 入门 {#getting-started} + +翻译过程在 Crowdin 上的 ethereum.org 项目中进行,译员为未翻译的字符串建议翻译,这些字符串几乎涵盖了 ethereum.org 网站的所有内容。 + +翻译是直接在在线编辑器中建议的,因此无需下载或上传任何文件或交付成果。 每个翻译的单词都会被跟踪和计数。 + +**1) 加入项目** + +- 要开始贡献,请加入 [Crowdin 上的 ethereum.org 项目](https://crowdin.com/project/ethereum-org) +- 您将需要登录或创建一个帐户 - 只需一个电子邮件地址和密码即可。 + +**2) 选择您的语言** + +- 在目标语言列表中找到您的语言,然后点击其名称或旗帜以将其打开。 +- 如果您想翻译成一种不可用的语言,请在 Crowdin 上联系 [Ethereum.org 团队](https://crowdin.com/profile/ethdotorg) 或发送电子邮件至 translations@ethereum.org,我们将根据请求添加其他目标语言。 + +**3) 打开一个未翻译的文件** + +- 找到第一个未翻译的文件以开始翻译。 包含源文件的文件夹是基于优先级的,因此您应从包含未翻译文件的第一个文件夹开始翻译。 +- 每个文件都有一个进度指示器,显示文件中有多少可翻译内容已被翻译和批准... 如果任何文件的翻译进度低于 100%,请翻译它。 + +**4) 翻译未翻译的字符串** + +- 当您打开文件进行翻译时,请确保您只翻译未翻译的字符串! +- 每个字符串都有一个状态指示器,显示它是_已翻译_、_未翻译_还是_已批准_。 如果源字符串在您的语言中已经有建议的翻译,则无需翻译它。 +- 您还可以在编辑器中筛选字符串以显示_未翻译的优先_或_仅未翻译的_。 + +有关浏览和使用 Crowdin 编辑器的详细指南,我们建议所有 Translatathon 参与者阅读我们的[如何翻译](/contributing/translation-program/how-to-translate/)指南。 + +您还可以通过查看我们的[翻译风格指南](/contributing/translation-program/translators-guide/)来找到一些提示和最佳实践。 + +**积分如何运作** + +每位 Translatathon 参与者将通过翻译 ethereum.org Crowdin 项目和其他符合条件的项目(下面提供了符合条件项目的完整列表)中的内容来获得积分,计入其最终得分。 + +计分方式很简单:**1 个翻译单词 = 1 积分** + +为了获得最终的积分分配,您建议的翻译需要通过评估过程,专业审校员将检查每位参与者的翻译,以确保它们符合最低质量门槛,并且在此过程中没有使用机器或人工智能翻译。 + +## 生态系统内容 {#ecosystem-content} + +由于 ethereum.org 翻译计划一直在进行,网站上某些目标语言的翻译进度明显高于其他语言。 + +为确保所有 Translatathon 参与者都有平等的机会尽可能多地翻译内容并竞争最高奖项,作为 Translatathon 一部分的源内容不仅限于 ethereum.org 网站内容。 + +翻译任何符合条件项目的参与者将获得同等数量的积分,任何项目中 1 个翻译单词 = 1 积分。 + +以下是 2025 Translatathon 的所有符合条件的项目列表: + +- [Ethereum.org](https://crowdin.com/project/ethereum-org) + +- [Ethereum.org 开发者教程](https://crowdin.com/project/33388446abbe9d7aa21e42e49bba7f97) + +- [EthStaker 存款 CLI](https://crowdin.com/project/ethstaker-deposit-cli) + +- [Eth Docker 文档](https://crowdin.com/project/eth-docker-docs) + +- [Remix IDE 相关文档](https://crowdin.com/project/remix-translation) + +- [Remix LearnEth](https://crowdin.com/project/remix-learneth) + +- [web3.py](https://crowdin.com/project/web3py) + +## 评估过程 {#evaluation-process} + +所有翻译都将经过质量保证和反馈,专业语言学家将根据质量和准确性评估提交的内容。 + +我们还将运行**反机器翻译措施**,使用一些工具自动检测机器或人工智能翻译。 + +虽然翻译质量在计分中不起关键作用,但任何**被发现使用机器或人工智能翻译**或建议低质量和不准确翻译的参与者都将没有资格获得奖品! + +评估期将在整个九月进行,结果将在 9 月 25 日的 ethereum.org 社区电话会议上公布。 + +所有翻译在添加到网站之前也会进行全面审核。 + + diff --git a/public/content/translations/zh/contributing/translation-program/translatathon/index.md b/public/content/translations/zh/contributing/translation-program/translatathon/index.md new file mode 100644 index 00000000000..adc2b00bae6 --- /dev/null +++ b/public/content/translations/zh/contributing/translation-program/translatathon/index.md @@ -0,0 +1,100 @@ +--- +title: "2025 ethereum.org 翻译马拉松" +lang: zh +template: translatathon +--- + + + + + + + +## 简介 {#introduction} + +我们相信,无论人们使用何种语言,都应可以访问以太坊内容和入门资源。 +为实现这一目标,ethereum.org 翻译计划旨在将网站翻译成尽可能多的语言。 + +作为翻译计划的一部分,我们正在组织第三届翻译马拉松 (Translatathon),这是一场翻译竞赛,旨在激励大家为欠活跃的语言贡献翻译,增加网站上的可用语言和内容数量,引入新贡献者并奖励现有贡献者。 + +如果你以英语以外的语言为母语,并希望在赢取奖品的同时,帮助普及以太坊内容,请继续阅读以了解更多信息! + +[了解更多关于 ethereum.org 翻译计划的信息](/contributing/translation-program/) + +## 时间线 {#timeline} + +以下是 2025 年翻译马拉松的重要日期: + + + + + +## 参与 {#participate} + +![社区和地球的图像](./participate.png) + + + +

谁可以参加?

+ 年满 18 岁、以至少一种非英语语言为母语且精通英语的任何人。 +
+ +

我需要是译员吗?

+ 否。 你只需会双语并提供人工翻译(禁止使用机器翻译!) 尽你所能,无需专业经验。 +
+
+ + + +

我需要投入多少时间?

+ 随你意愿。 有资格获奖的最低门槛是翻译 1,000 个单词,大约需要 2 小时才能完成,而争夺最高奖项则需要投入更多的时间。 +
+ +

我需要熟悉以太坊吗?

+ 否。 虽然熟悉以太坊有助于提高你的工作效率和质量,但翻译马拉松也是一种学习体验,欢迎大家在参与的同时加入并了解更多关于以太坊的信息。 +
+
+ +有关更多详细信息,[请参阅完整的条款和条件](/contributing/translation-program/translatathon/terms-and-conditions) + +### 分步说明 {#step-by-step-instructions} + + + +## 奖品 {#prizes} + +| 名次 | 奖金金额 | +| ------------- | ----- | +| 第 1 名 | $4000 | +| 第 2 名 | $2500 | +| 第 3 名 | $1500 | +| 第 4 名 | $1100 | +| 第 5 名 | $1000 | +| 第 6 名 | $600 | +| 第 7 名 | $550 | +| 第 8 名 | $500 | +| 第 9 名 | $450 | +| 第 10 名 | $400 | +| 第 11 - 20 名 | $240 | +| 第 21 - 50 名 | $120 | +| 第 51 - 100 名 | $60 | +| 第 101 - 150 名 | $40 | +| 其余 | $20 | + +所有奖品都将以 ETH 支付。 + + + + diff --git a/public/content/translations/zh/contributing/translation-program/translators-guide/index.md b/public/content/translations/zh/contributing/translation-program/translators-guide/index.md index a5a9ceaec32..ebe1f037b2d 100644 --- a/public/content/translations/zh/contributing/translation-program/translators-guide/index.md +++ b/public/content/translations/zh/contributing/translation-program/translators-guide/index.md @@ -1,7 +1,7 @@ --- -title: 翻译人员指南 +title: "翻译人员指南" lang: zh -description: 适用于 Ethereum.org 翻译人员的说明和技巧 +description: "适用于 Ethereum.org 翻译人员的说明和技巧" --- # Ethereum.org 翻译风格指南 {#style-guide} @@ -10,15 +10,15 @@ Ehereum.org 翻译风格指南包含一些最重要的指南、说明和翻译 本文档是一份一般性指南,并不特定于任何一种语言。 -如果有任何问题、建议或反馈,请随时通过 translations@ethereum.org 与我们联系,在 Crowdin 上向 @ethdotorg 发送消息,或[加入我们的 Discord](https://discord.gg/ethereum-org),你可以通过#translations 频道向我们发送消息或联系任何团队成员。 +如有任何问题、建议或反馈,请随时通过 translations@ethereum.org 联系我们、在 Crowdin 上向 @ethdotorg 发送消息,或[加入我们的 Discord](https://discord.gg/ethereum-org),您可以在 #translations 频道中向我们发送消息或联系任何团队成员。 ## 使用 Crowdin {#using-crowdin} -你可以在[翻译计划页面](/contributing/translation-program/#how-to-translate)上找到有关如何在 Crowdin 中加入项目以及如何使用 Crowdin 在线编辑器的基本说明。 +您可以在[翻译计划页面](/contributing/translation-program/#how-to-translate)上找到有关如何在 Crowdin 中加入项目以及如何使用 Crowdin 在线编辑器的基本说明。 -如果你想了解更多关于 Crowdin 并使用它的一些高级功能,[Crowdin 知识库](https://support.crowdin.com/online-editor/)包含很多所有 Crowdin 功能的深入指南和概述。 +如果您想详细了解 Crowdin 及其高级功能,[Crowdin 知识库](https://support.crowdin.com/online-editor/)中包含了有关其所有功能的大量深度指南和概述。 -## 理解信息的精髓 {#capturing-the-essence} +## 抓住信息的精髓 {#capturing-the-essence} 当翻译 ethereum.org 内容时,避免直译。 @@ -50,7 +50,7 @@ Ethereum.org 提供多种语言版本,使用替代拉丁文的书写系统( 翻译内容时,应确保翻译内容一致且不包含任何拉丁字符。 -一个常见的误解是,Ethereum一直是用拉丁文书写。 这大部分是不正确的,请使用你的母语拼写 Ethereum(例如:中文的以太坊,阿拉伯语的 إيثيريوم 等)。 +一个常见的误解是,Ethereum一直是用拉丁文书写。 这在大多数情况下是错误的,请使用您母语中 Ethereum 的拼写(例如:中文为“以太坊”,阿拉伯语为“إيثيريوم”等)。 **以上规则不适用于通常不应翻译专有名词的语言。** @@ -60,7 +60,7 @@ Ethereum.org 提供多种语言版本,使用替代拉丁文的书写系统( 在将新页面上传到 Crowdin 时,我们隐藏了翻译人员不应翻译的内容,这意味着 Crowdin 中翻译人员可见的所有元数据都应该被翻译。 -翻译源文本为“en”的任何字符串时,请特别注意。 这表示页面可用的语言,应翻译为[你的语言的 ISO 语言代码](https://www.andiamo.co.uk/resources/iso-language-codes/)。 这些字符串应始终使用拉丁字符而不是目标语言原生的书写脚本进行翻译。 +翻译源文本为“en”的任何字符串时,请特别注意。 这代表页面可用的语言,应翻译为[您所用语言的 ISO 语言代码](https://www.andiamo.co.uk/resources/iso-language-codes/)。 这些字符串应始终使用拉丁字符而不是目标语言原生的书写脚本进行翻译。 如果你不确定要使用哪种语言代码,你可以查看 Crowdin 中的翻译记忆库,或在 Crowdin 在线编辑器的页面 URL 中找到你的语言的语言代码。 @@ -78,15 +78,18 @@ Ethereum.org 提供多种语言版本,使用替代拉丁文的书写系统( 你可以在下面找到一些示例,说明这些字符串对于翻译人员的外观以及如何识别它们(文章链接主要位于这些页面的底部,位于“进一步阅读”部分): -![Sidebar.png 中的文章标题](./article-titles-in-sidebar.png) ![Editor.png 中的文章标题](./article-titles-in-editor.png) +![侧边栏中的文章标题.png](./article-titles-in-sidebar.png) +![编辑器中的文章标题.png](./article-titles-in-editor.png) ## Crowdin 警告 {#crowdin-warnings} -Crowdin 有一个内置功能,可以在翻译人员即将出错时发出警告。 在保存翻译之前,如果你忘记在译文中加上原文中的标签、翻译了不应翻译的元素、添加了多个连续的空格、忘记结尾标点等,Crowdin 会自动提醒你。 如果你看到这样的警告,请返回并仔细检查建议的翻译。 +Crowdin 有一个内置功能,可以在翻译人员即将出错时发出警告。 在保存翻译之前,如果你忘记在译文中加上原文中的标签、翻译了不应翻译的元素、添加了多个连续的空格、忘记结尾标点等,Crowdin 会自动提醒你。 +如果你看到这样的警告,请返回并仔细检查建议的翻译。 **永远不要忽略这些警告,因为它们通常意味着有问题,或者翻译缺少源文本的关键部分。** -当你忘记在翻译中添加标签时出现 Crowdin 警告的示例: ![Crowdin 警告示例](./crowdin-warning-example.png) +当您忘记向译文添加标签时出现的 Crowdin 警告示例: +![Crowdin 警告示例](./crowdin-warning-example.png) ## 处理标签和代码片段 {#dealing-with-tags} @@ -96,15 +99,18 @@ Crowdin 有一个内置功能,可以在翻译人员即将出错时发出警告 为了更轻松地管理标签并直接从源中复制它们,我们建议你在 Crowdin 编辑器中更改你的设置。 -1. 打开“设置” ![如何打开编辑器中的设置](./editor-settings.png) +1. 打开设置 + ![如何在编辑器中打开设置](./editor-settings.png) 2. 向下滚动到“HTML 标签显示”部分 -3. 选择“隐藏” ![请选择“隐藏”](./hide-tags.png) +3. 选择“隐藏” + ![请选择“隐藏”](./hide-tags.png) 4. 点击“保存” -通过选择此选项,完整的标签文本将不再显示,而是由一个数字代替。 翻译时,点击此标签会自动将确切的标签复制到翻译字段。 +通过选择此选项,完整的标签文本将不再显示,而是由一个数字代替。 +翻译时,点击此标签会自动将确切的标签复制到翻译字段。 **链接** @@ -114,15 +120,15 @@ Crowdin 有一个内置功能,可以在翻译人员即将出错时发出警告 处理链接的最佳方法是直接从源中复制它们,方法是点击它们或使用“复制源”按钮 (Alt+C)。 -![link.png 示例](./example-of-link.png) +![link.png](./example-of-link.png 示例) -链接同样以标签的形式出现在源文本中(即 \<0> \). 如果你将鼠标悬停在标签上,编辑器将显示其全部内容 - 有时这些标签将代表链接。 +链接也以标签的形式出现在源文本中(即 `<0>` ``)。 如果你将鼠标悬停在标签上,编辑器将显示其全部内容 - 有时这些标签将代表链接。 从源复制链接而不要更改其顺序,这一点非常重要。 如果标签的顺序发生变化,它们所代表的链接将被破坏。 -![tags.png 中的链接示例](./example-of-links-inside-tags.png) +![tags.png](./example-of-links-inside-tags.png 中的链接示例) **标签和变量** @@ -132,35 +138,35 @@ Crowdin 有一个内置功能,可以在翻译人员即将出错时发出警告 示例:``Decentralized`` -`` - _使文本变粗的开始标签_ +`` - _使文本变为粗体的开始标签_ Decentralized - _可翻译文本_ `` - _结束标签_ -!['strong' tags.png 的示例](./example-of-strong-tags.png) +![“strong”标签示例.png](./example-of-strong-tags.png) 代码片段的处理方式与其他标签略有不同,因为它们包含不应翻译的代码。 示例:``nonce`` -`` - _开始标签,其中包含一段代码_ +`` - _开始标签,包含代码片段_ -nonce - _不可翻译的文本_ +nonce - _不可翻译文本_ `` - _结束标签_ -![代码片段 .png 的示例](./example-of-code-snippets.png) +![代码片段示例.png](./example-of-code-snippets.png) 源文本还包含缩短的标签,这些标签只包含数字,这意味着它们的功能不是很明显。 你可以将鼠标悬停在这些标签上,以准确查看它们提供的功能。 -在下面的示例中,你可以看到,将鼠标悬停在 \<0> 标签显示,它代表 `` 并包含代码片段,因此不应翻译这些标签内的内容。 +在下例中,当您将鼠标悬停在 `<0>` 标签上时,可以看到它代表 `` 且包含一个代码片段,因此不应翻译这些标签内的内容。 -![模棱两可的 tags.png 的示例](./example-of-ambiguous-tags.png) +![模棱两可的 tags.png](./example-of-ambiguous-tags.png 的示例) -## 简短与完整形式/缩写 {#short-vs-full-forms} +## 缩写与完整形式 {#short-vs-full-forms} -网站上使用了很多缩写,例如 dApp、NFT、DAO、DeFi 等。 这些缩写通常用于英语,并且大多数网站访问者都熟悉它们。 +网站上使用了很多缩写,例如 dapps、NFT、DAO、DeFi 等。 这些缩写通常用于英语,并且大多数网站访问者都熟悉它们。 由于它们通常没有其他语言的既定翻译,处理这些和类似术语的最佳方法是提供完整形式的描述性翻译,并在括号中添加英文缩写。 @@ -168,9 +174,9 @@ nonce - _不可翻译的文本_ 如何翻译 dApp 的示例: -- Decentralized applications (dapps) → _完整的翻译形式 (括号中为英文缩写)_ +- Decentralized applications (dapps) → _翻译后的完整形式(括号中为英文缩写)_ -## 没有既定翻译的术语 {#terms-without-established-translations} +## 尚无既定译法的术语 {#terms-without-established-translations} 某些术语在其他语言中可能没有既定翻译,并且以原始英语术语而广为人知。 这些术语主要包括较新的概念,如工作量证明、权益证明、信标链、质押等。 @@ -178,19 +184,19 @@ nonce - _不可翻译的文本_ 翻译它们时,请随意发挥创意,使用描述性翻译,或直接按字面翻译。 -**大多数术语应该翻译而不是将其中一些保留英文的原因是,随着越来越多的人开始使用以太坊和相关技术,这种新术语将在未来变得更加普遍。 如果我们想让来自世界各地的更多人加入这个领域,我们需要以尽可能多的语言提供易于理解的术语,即使我们需要自行创建它。** +**大多数术语应该翻译而不是将其中一些保留为英文,其原因是,随着越来越多的人开始使用以太坊和相关技术,这些新术语将在未来变得更加普遍。** 如果我们想让来自世界各地的更多人加入这个领域,我们需要以尽可能多的语言提供易于理解的术语,即使我们需要自行创建。\*\* -## 按钮与行动号召 {#buttons-and-ctas} +## 按钮和号召性用语 {#buttons-and-ctas} 网站包含许多按钮,其翻译方式应与其他内容不同。 可以通过查看上下文屏幕截图、与大多数字符串连接或通过检查编辑器中的上下文(包括短语“button”)来识别按钮文本。 -按钮的翻译应尽可能简短,以防止格式不匹配。 此外,按钮翻译应该是必要的,即呈现命令或请求。 +按钮的翻译应尽可能简短,以防止格式不匹配。 此外,按钮的译文应使用祈使语气,即表达命令或请求。 -![如何查找按钮 .png](./how-to-find-a-button.png) +![如何查找按钮.png](./how-to-find-a-button.png) -## 翻译包容性 {#translating-for-inclusivity} +## 包容性翻译 {#translating-for-inclusivity} Ethereum.org 的访问者来自世界各地和不同的背景。 因此,网站上的语言应该是中立的,欢迎所有人而不是排他性的。 @@ -200,7 +206,7 @@ Ethereum.org 的访问者来自世界各地和不同的背景。 因此,网站 最后,语言应该适合所有大众和年龄段的读者。 -## 特定语言的翻译 {#language-specific-translations} +## 特定于语言的翻译 {#language-specific-translations} 翻译时,重要的是要遵循你的语言中使用的语法规则、约定和格式,而不是从源复制。 源文本遵循英语语法规则和约定,而这不适用于许多其他语言。 @@ -208,7 +214,7 @@ Ethereum.org 的访问者来自世界各地和不同的背景。 因此,网站 一些需要特别注意的例子: -### 标点、格式 {#punctuation-and-formatting} +### 标点和格式 {#punctuation-and-formatting} **大写** @@ -220,8 +226,8 @@ Ethereum.org 的访问者来自世界各地和不同的背景。 因此,网站 - 正字法规则定义了每种语言的空格使用。 因为到处都使用空格,所以这些规则是最独特的,而空格是最容易误译的元素。 - 英语和其他语言之间的一些常见间距差异: - - 计量单位和货币前的空格(例如 USD、EUR、kB、MB) - - 度数符号前的空格(例如°C、℉) + - 计量单位和货币符号前的空格(例如:USD、EUR、kB、MB) + - 度数符号前的空格(例如:°C、℉) - 一些标点符号前的空格,尤其是省略号 (...) - 斜杠前后的空格 (/) @@ -229,7 +235,7 @@ Ethereum.org 的访问者来自世界各地和不同的背景。 因此,网站 - 每种语言都有一套多样化和复杂的规则来编写列表。 这些可能与英语有很大不同。 - 在某些语言中,每个新行的第一个单词需要大写,而在其他语言中,新行应该以小写字母开头。 许多语言对列表中的大小写也有不同的规则,具体取决于每行的长度。 -- 这同样适用于行项目的标点符号。 列表中的结束标点可以是句点 (**.**)、逗号 (**,**) 或分号 (**;**)具体取决于语言 +- 这同样适用于行项目的标点符号。 列表中的结束标点可以是句点 (.)、逗号 (,) 或分号 (;),具体取决于语言。 **引号** @@ -240,7 +246,7 @@ Ethereum.org 的访问者来自世界各地和不同的背景。 因此,网站 - »示例文本« - “示例文本” - ‘示例文本’ - - «示例文本» + - «示例 文本» **连字符和破折号** @@ -253,10 +259,10 @@ Ethereum.org 的访问者来自世界各地和不同的背景。 因此,网站 - 用不同语言书写数字的主要区别在于用于小数和千位的分隔符。 对于千数来说,这可以是句号、逗号或空格。 同样,一些语言使用小数点,而另一些语言使用小数点逗号。 - 一些大数的例子: - - 英语 - **1,000.50** - - 西班牙语 - **1.000,50** - - 法语 - **1 000,50** -- 翻译数字时的另一个重要考虑因素是百分号。 它可以用不同的方式编写:**100%**、**100 %** 或 **%100**。 + - 英语 – **1,000.50** + - 西班牙语 – **1.000,50** + - 法语 – **1 000,50** +- 翻译数字时的另一个重要考虑因素是百分号。 可以写成不同形式:**100%**、**100 %** 或 **%100**。 - 最后,负数可以不同地显示,具体取决于语言:-100、100-、(100) 或 [100]。 **日期** diff --git a/public/content/translations/zh/dao/index.md b/public/content/translations/zh/dao/index.md index 83a24731f20..503e26bf2a7 100644 --- a/public/content/translations/zh/dao/index.md +++ b/public/content/translations/zh/dao/index.md @@ -1,16 +1,16 @@ --- -title: 什么是去中心化自治组织 (DAO)? -metaTitle: 什么是去中心化自治组织 (DAO)? | 去中心化自治组织 -description: 以太坊上的去中心化自治组织简介 +title: "什么是去中心化自治组织 (DAO)?" +metaTitle: "什么是去中心化自治组织 (DAO)? | 去中心化自治组织" +description: "以太坊上的去中心化自治组织简介" lang: zh template: use-cases emoji: ":handshake:" sidebarDepth: 2 image: /images/use-cases/dao-2.png -alt: 表示去中心化自治组织在对提案投票。 -summaryPoint1: 没有集中领导的、成员共同拥有的社区。 -summaryPoint2: 一种与互联网上的陌生人合作的安全方式。 -summaryPoint3: 一个为特定事业投入资金的安全场所。 +alt: "表示去中心化自治组织在对提案投票。" +summaryPoint1: "没有集中领导的、成员共同拥有的社区。" +summaryPoint2: "一种与互联网上的陌生人合作的安全方式。" +summaryPoint3: "一个为特定事业投入资金的安全场所。" --- ## 什么是去中心化自治组织? {#what-are-daos} @@ -19,15 +19,15 @@ summaryPoint3: 一个为特定事业投入资金的安全场所。 去中心化自治组织让全世界志同道合之士开展合作,而无需信赖一位宅心仁厚的领导来管理资金和运营。 没有可以随意花钱的首席执行官,也没有能够做假账的首席财务官。 取而代之的是,融入代码的基于区块链的规则规定组织如何运作以及资金如何使用。 -去中心化自治组织拥有内部资产,未经该组织批准,任何人都无权动用。 决策通过提案和投票监管,确保组织中的每位成员都有发言权,并且一切都发生在[链上](/glossary/#on-chain),公开透明。 +去中心化自治组织拥有内部资产,未经该组织批准,任何人都无权动用。 决策通过提案和投票进行治理,以确保组织中的每个人都有发言权,并且一切都透明地[在链上](/glossary/#onchain)进行。 ## 我们为什么需要去中心化自治组织? {#why-dao} -与他人创办涉及资金和金钱的组织,需要对与合作对象高度信任。 不过,显然很难相信互联网上素不相识的人。 通过去中心化自治组织,你不需要相信组织中的其他人,只需要相信去中心化自治组织的代码就够了,它是 100% 公开透明的,任何人都可以验证。 +与他人创办涉及资金和金钱的组织,需要对合作对象高度信任。 不过,显然很难相信互联网上素不相识的人。 通过去中心化自治组织,你不需要相信组织中的其他人,只需要相信去中心化自治组织的代码就够了,它是 100% 公开透明的,任何人都可以验证。 这为全球合作和协调提供了许多新机会。 -### 对比 {#dao-comparison} +### 比较 {#dao-comparison} | 去中心化自治组织 | 传统组织 | | ------------------------- | ------------------------------ | @@ -37,23 +37,23 @@ summaryPoint3: 一个为特定事业投入资金的安全场所。 | 以去中心化方式自动提供服务(例如慈善基金的分配)。 | 需要人工处理或自动集中控制,易受操纵。 | | 所有活动公开透明。 | 活动通常是私密进行,不向公众开放。 | -### 去中心化自治组织示例 {#dao-examples} +### DAO 示例 {#dao-examples} 为了帮助你更好地理解,这里有一些去中心化自治组织的应用示例: -- **慈善机构** – 可以接受全世界任何人的捐赠,并投票决定要资助的项目。 -- **集体所有权** – 可以购买实体或数字资产,组织成员可以投票决定如何使用它们。 -- **风险投资和赠款** – 可以成立一个风险基金,汇集投资资本并投票进行商业投资。 后续收益可以分配给相应 DAO 成员。 +- **慈善机构** – 您可以接受来自世界各地任何人的捐赠,并投票决定要资助哪些事业。 +- **集体所有权** – 您可以购买实体或数字资产,成员可以投票决定如何使用它们。 +- **风险投资和拨款** – 您可以创建一个风险基金,汇集投资资本并对要支持的风险项目进行投票。 后续收益可以分配给相应 DAO 成员。 ## 去中心化自治组织如何运作? {#how-daos-work} -去中心化自治组织的核心是[智能合约](/glossary/#smart-contract),它定义了组织的规则并持有组织的资产。 合约在以太坊上生效后,除非表决通过,否则任何人都不能修改规则。 任何人都无法超越合约定义的规则和逻辑行事。 由于资产也由智能合约定义,这也意味着未经组织批准任何人都不能使用资金。 所以去中心化组织也不需要中央权威。 相反,组织集体作出决定,而付款会在表决通过后自动获批。 +DAO 的支柱是其[智能合约](/glossary/#smart-contract),它定义了组织的规则并掌管着该团体的资金库。 合约在以太坊上生效后,除非表决通过,否则任何人都不能修改规则。 任何人都无法超越合约定义的规则和逻辑行事。 由于资产也由智能合约定义,这也意味着未经组织批准任何人都不能使用资金。 所以去中心化组织也不需要中央权威。 相反,组织集体作出决定,而付款会在表决通过后自动获批。 之所以能够做到这一点,是因为智能合约在以太坊上生效后,就无法被篡改。 一切都是公开的,你不可能在其他人一无所知的情况下修改代码(去中心化组织定义的规则)。 -## 以太坊与去中心化自治组织 {#ethereum-and-daos} +## 以太坊和 DAO {#ethereum-and-daos} 以太坊为去中心化自治组织提供了坚实基础,原因如下: @@ -62,7 +62,7 @@ summaryPoint3: 一个为特定事业投入资金的安全场所。 - 智能合约可以发送/接收资金。 没有这点,你就需要可信的中间人来管理组织资金。 - 比起竞争,以太坊社区更趋向于合作,这使得各类应用程序和服务系统蓬勃发展。 -## 去中心化自治组织的治理 {#dao-governance} +## DAO 治理 {#dao-governance} 治理去中心化自治组织时要考虑很多因素,比如投票和提案如何运作。 @@ -70,97 +70,99 @@ summaryPoint3: 一个为特定事业投入资金的安全场所。 委托就像是去中心化自治组织的代议制民主。 代币持有者将投票委托给那些自提名并承诺管理协议和随时了解动态的用户。 -#### 知名案例 {#governance-example} +#### 一个著名的例子 {#governance-example} -[以太坊域名服务](https://claim.ens.domains/delegate-ranking) - 以太坊域名服务持有者可以将他们的选票委托给参与的社区成员来代表他们。 +[ENS](https://claim.ens.domains/delegate-ranking) – ENS 持有者可以将其投票委托给活跃的社区成员来代表他们。 ### 自动交易治理 {#governance-example} 在很多去中心化自治组织中,如果达到法定人数的成员投票赞成,交易将自动执行。 -#### 知名案例 {#governance-example} +#### 一个著名的例子 {#governance-example} -[Nouns](https://nouns.wtf) — 在去中心化自治组织 Nouns 中,只要创始人不否决,如果投票达到法定票数并且多数票赞成,那么交易将自动执行。 +[Nouns](https://nouns.wtf) – 在 Nouns DAO 中,只要未被创始人否决,如果达到法定票数且多数票赞成,交易就会自动执行。 -### 多重签名治理 {#governance-example} +### 多签治理 {#governance-example} -虽然去中心化自治组织可能有数千名有投票权的成员,但资金一般会放在一个由 5 到 20 名活跃社区成员共同管理的[钱包](/glossary/#wallet)中,这些成员受组织信任并接受监督(社区知道他们的公开身份)。 投票后,[多重签名](/glossary/#multisig)的签名者执行社区的意愿。 +虽然 DAO 可能有数千名投票成员,但资金可以存放在一个由 5-20 名受信任且通常已公开身份(社区知道其公开身份)的活跃社区成员共享的[钱包](/glossary/#wallet)中。 投票后,[多签](/glossary/#multisig)签名者将执行社区的意愿。 -## 去中心化自治组织相关法律 {#dao-laws} +## DAO 法律 {#dao-laws} 1977 年,怀俄明州发明了有限责任公司制度,保护企业家并对他们的责任范围做出限制。 最近,他们率先制定了《去中心化自治组织法》,确立了去中心化自治组织的法律地位。 目前,怀俄明州、佛蒙特州和维尔京群岛都制定了各自的去中心化自治组织法律。 -### 知名案例 {#law-example} +### 一个著名的例子 {#law-example} -[CityDAO](https://citizen.citydao.io/) — 依照怀俄明州的去中心化自治组织相关法律,CityDAO 购买了黄石国家公园附近的 40 英亩土地。 +[CityDAO](https://citizen.citydao.io/) – CityDAO 利用怀俄明州的 DAO 法律购买了黄石国家公园附近 40 英亩的土地。 -## 去中心化自治组织的成员资格 {#dao-membership} +## DAO 成员资格 {#dao-membership} 去中心化自治组织成员资格分为多种模式。 成员资格可以决定投票方式和去中心化自治组织的其他关键事项。 ### 基于代币的成员资格 {#token-based-membership} -通常完全[无需许可](/glossary/#permissionless),具体取决于使用的代币。 这些治理代币大多可以在[去中心化交易所](/glossary/#dex)进行交易,无需许可。 其余代币要通过提供流动性或其他“工作量证明”才能赚取。 无论何种方式,只要持有代币就可以参与投票。 +通常完全[无需许可](/glossary/#permissionless),具体取决于所使用的代币。 这些治理代币大多可以在[去中心化交易所](/glossary/#dex)上无需许可地交易。 其余代币要通过提供流动性或其他“工作量证明”才能赚取。 无论何种方式,只要持有代币就可以参与投票。 -_通常用来管理各种去中心化协议和/或代币本身。_ +_通常用于治理广泛的去中心化协议和/或代币本身。_ -#### 知名案例 {#token-example} +#### 一个著名的例子 {#token-example} -[MakerDAO](https://makerdao.com) — 去中心化交易所普遍提供 MakerDAO 的代币 MKR,任何人都可以买入,从而获得对 Maker 协议未来的投票权。 +[MakerDAO](https://makerdao.com) – MakerDAO 的代币 MKR 在去中心化交易所广泛可用,任何人都可以购买以获得对 Maker 协议未来的投票权。 ### 基于份额的成员资格 {#share-based-membership} 基于份额的去中心化自治组织在更大程度上需要许可,但仍然相当公开透明。 任何潜在成员都可以提交加入去中心化自治组织的提案,并且通常以代币或工作的形式提供有价值的贡献。 份额代表直接投票权和所有权。 成员可以随时退出组织并带走属于他们的资金份额。 -_通常用于联系更紧密、以人为中心的组织,例如慈善机构、工人团体和投资俱乐部等。 也可以管理协议和代币。_ +_通常用于关系更紧密、以人为本的组织,如慈善机构、工人合作社和投资俱乐部。_ 也可以治理协议和代币。_ -#### 知名案例 {#share-example} +#### 一个著名的例子 {#share-example} -[MolochDAO](http://molochdao.com/) – MolochDAO 致力于为以太坊项目募集资金。 他们需要成员资格提案,以便组织可以评估你是否具有必要的专业知识和资本来对潜在受资助者做出明智判断。 你无法通过在公开市场上购买代币来加入这类去中心化自治组织。 +[MolochDAO](http://molochdao.com/) – MolochDAO 专注于为以太坊项目提供资金。 他们需要成员资格提案,以便组织可以评估你是否具有必要的专业知识和资本来对潜在受资助者做出明智判断。 你无法通过在公开市场上购买代币来加入这类去中心化自治组织。 ### 基于信誉的成员资格 {#reputation-based-membership} -信誉代表参加投票的证明,并授予去中心化自治组织中的投票权。 不同于基于代币或份额的成员资格,基于信誉的去中心化自治组织不会将所有权转让给贡献者。 信誉不能够购买、转让或委托;去中心化自治组织成员必须通过参与获得信誉。 链上投票无需许可,潜在成员可以自由提交加入去中心化自治组织的提案,并要求获得信誉和代币,作为他们所做贡献的奖励。 +信誉代表参加投票的证明,并授予去中心化自治组织中的投票权。 不同于基于代币或份额的成员资格,基于信誉的去中心化自治组织不会将所有权转让给贡献者。 信誉不能够购买、转让或委托;去中心化自治组织成员必须通过参与获得信誉。 链上投票无需许可,因此潜在人员可以自由提交加入去中心化自治组织的提案,并要求获得信誉和代币作为他们所做贡献的奖励。 -_通常用于协议和[去中心化应用程序](/glossary/#dapp)的去中心化开发和管理,但同时非常适合各类组织,例如慈善机构、工人团体、投资俱乐部等。_ +_通常用于协议和[去中心化应用程序](/glossary/#dapp)的去中心化开发和治理,但也同样适用于各种组织,例如慈善机构、工人合作社和投资俱乐部等。_ -#### 知名案例 {#reputation-example} +#### 一个著名的例子 {#reputation-example} -[DXdao](https://DXdao.eth.limo) -- DXdao 是一个全球性的主权团体,自 2019 年以来一直致力于构建和管理去中心化协议和应用程序。 它利用基于信誉的治理和[全息共识](/glossary/#holographic-consensus)来协调和管理资金,这意味着没有人能够影响其未来或治理。 +[DXdao](https://DXdao.eth.limo) – DXdao 是一个全球主权集体,自 2019 年以来一直致力于构建和治理去中心化协议和应用程序。 它利用基于信誉的治理和[全息共识](/glossary/#holographic-consensus)来协调和管理资金,这意味着没有人可以通过购买来影响其未来或治理。 -## 加入/创立去中心化自治组织 {#join-start-a-dao} +## 加入/启动一个 DAO {#join-start-a-dao} -### 加入去中心化自治组织 {#join-a-dao} +### 加入 DAO {#join-a-dao} -- [以太坊社区中的去中心化自治组织](/community/get-involved/#decentralized-autonomous-organizations-daos) -- [DAOHaus 的去中心化自治组织列表](https://app.daohaus.club/explore) -- [Tally.xyz 的去中心化自治组织列表](https://www.tally.xyz) +- [以太坊社区 DAO](/community/get-involved/#decentralized-autonomous-organizations-daos) +- [DAOHaus 的 DAO 列表](https://app.daohaus.club/explore) +- [Tally.xyz 的 DAO 列表](https://www.tally.xyz/explore) +- [DeGov.AI 的 DAO 列表](https://apps.degov.ai/) -### 创立去中心化自治组织 {#start-a-dao} +### 启动 DAO {#start-a-dao} -- [使用 DAOHaus 创立去中心化自治组织](https://app.daohaus.club/summon) -- [从 Tally 开创治理去中心化自治组织](https://www.tally.xyz/add-a-dao) -- [创立由 Aragon 支持的去中心化自治组织](https://aragon.org/product) -- [创立 colony](https://colony.io/) -- [使用 DAOstack 的全息共识机制创建去中心化自治组织](https://alchemy.daostack.io/daos/create) +- [通过 DAOHaus 召唤一个 DAO](https://app.daohaus.club/summon) +- [通过 Tally 启动一个 Governor DAO](https://www.tally.xyz/get-started) +- [创建一个由 Aragon 支持的 DAO](https://aragon.org/product) +- [启动一个 Colony](https://colony.io/) +- [使用 DAOstack 的全息共识创建一个 DAO](https://alchemy.daostack.io/daos/create) +- [使用 DeGov 启动器启动一个 DAO](https://docs.degov.ai/integration/deploy) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -### 去中心化自治组织相关文章 {#dao-articles} +### DAO 文章 {#dao-articles} -- [什么是去中心化自治组织?](https://aragon.org/dao)– [Aragon](https://aragon.org/) -- [去中心化自治组织之家](https://wiki.metagame.wtf/docs/great-houses/house-of-daos) – [Metagame](https://wiki.metagame.wtf/) -- [什么是去中心化自治组织,其宗旨是什么?](https://daohaus.substack.com/p/-what-is-a-dao-and-what-is-it-for) – [DAOhaus](https://daohaus.club/) -- [如何创立由去中心化自治组织提供支持的数字社区](https://daohaus.substack.com/p/four-and-a-half-steps-to-start-a) – [DAOhaus](https://daohaus.club/) -- [什么是去中心化自治组织?](https://coinmarketcap.com/alexandria/article/what-is-a-dao) – [Coinmarketcap](https://coinmarketcap.com) +- [什么是 DAO?](https://aragon.org/dao) – [Aragon](https://aragon.org/) +- [DAO 之家](https://wiki.metagame.wtf/docs/great-houses/house-of-daos) – [Metagame](https://wiki.metagame.wtf/) +- [什么是 DAO,它有什么用?](https://daohaus.substack.com/p/-what-is-a-dao-and-what-is-it-for) – [DAOhaus](https://daohaus.club/) +- [如何启动一个由 DAO 支持的数字社区](https://daohaus.substack.com/p/four-and-a-half-steps-to-start-a) – [DAOhaus](https://daohaus.club/) +- [什么是 DAO?](https://coinmarketcap.com/alexandria/article/what-is-a-dao) – [Coinmarketcap](https://coinmarketcap.com) - [什么是全息共识?](https://medium.com/daostack/holographic-consensus-part-1-116a73ba1e1c) - [DAOstack](https://daostack.io/) -- [《去中心化自治组织不是公司:去中心化在自治组织中很重要》,作者 Vitalik](https://vitalik.eth.limo/general/2022/09/20/daos.html) -- [去中心化自治组织、数据可用性委员会、数据可用性等等:不完整术语指南](https://blog.ethereum.org/2014/05/06/daos-dacs-das-and-more-an-incomplete-terminology-guide) - [以太坊博客](https://blog.ethereum.org) +- [《DAO 不是公司:去中心化在自治组织中的重要性》,作者:Vitalik](https://vitalik.eth.limo/general/2022/09/20/daos.html) +- [DAO、DAC、DA 等:不完全术语指南](https://blog.ethereum.org/2014/05/06/daos-dacs-das-and-more-an-incomplete-terminology-guide) - [以太坊博客](https://blog.ethereum.org) ### 视频 {#videos} -- [什么是加密货币中的去中心化自治组织?](https://youtu.be/KHm0uUPqmVE) -- [去中心化自治组织能构建一座城市吗?](https://www.ted.com/talks/scott_fitsimones_could_a_dao_build_the_next_great_city) – [TED](https://www.ted.com/) +- [加密世界中的 DAO 是什么?](https://youtu.be/KHm0uUPqmVE) +- [DAO 能建一座城吗?](https://www.ted.com/talks/scott_fitsimones_could_a_dao_build_the_next_great_city) – [TED](https://www.ted.com/) diff --git a/public/content/translations/zh/decentralized-identity/index.md b/public/content/translations/zh/decentralized-identity/index.md index 2a2cf200b11..15c088ab883 100644 --- a/public/content/translations/zh/decentralized-identity/index.md +++ b/public/content/translations/zh/decentralized-identity/index.md @@ -1,25 +1,25 @@ --- -title: 去中心化身份 -description: 什么是去中心化身份,它为什么很重要? +title: "去中心化身份" +description: "什么是去中心化身份,它为什么很重要?" lang: zh template: use-cases emoji: ":id:" sidebarDepth: 2 image: /images/eth-gif-cat.png -summaryPoint1: 传统身份系统有权对你的身份标识进行发布、维护和控制。 -summaryPoint2: 去中心化身份消除了对中心化第三方的依赖。 -summaryPoint3: 多亏了加密技术,用户现在拥有了再次发布、持有和控制其自身身份标识和身份证明的工具。 +summaryPoint1: "传统身份系统有权对你的身份标识进行发布、维护和控制。" +summaryPoint2: "去中心化身份消除了对中心化第三方的依赖。" +summaryPoint3: "多亏了加密技术,用户现在拥有了再次发布、持有和控制其自身身份标识和身份证明的工具。" --- 现如今,身份几乎支撑着你生活的方方面面。 使用线上服务、银行开户、选举投票、购买房产、找工作——所有这些都需要证明你的身份。 -然而,传统身份管理系统长期以来一直依赖于中心化中间机构,这种机构发布、持有和控制你的身份标识和[身份证明](/glossary/#attestation)。 这意味着你无法掌控你的身份相关信息,也无法决定谁能够访问你的可识别个人信息 (PII),以及这些人有多大的访问权限。 +然而,传统的身份管理系统长期以来一直依赖于中心化中介机构,由这些机构发行、持有和控制您的标识符和[身份证明](/glossary/#attestation)。 这意味着你无法掌控你的身份相关信息,也无法决定谁能够访问你的可识别个人信息 (PII),以及这些人有多大的访问权限。 -为了解决这些问题,我们在以太坊等公链上构建了去中心化身份系统。 去中心化身份允许每个人管理他们的身份相关信息。 借助去中心化身份解决方案,_你_可以创建身份标识,以及声明和持有身份证明,无需依赖于中心化机构,如服务提供方或政府。 +为了解决这些问题,我们在以太坊等公链上构建了去中心化身份系统。 去中心化身份允许每个人管理他们的身份相关信息。 借助去中心化身份解决方案,_您_可以创建标识符,声明和持有您的身份证明,而无需依赖服务提供商或政府等中心化机构。 ## 什么是身份? {#what-is-identity} -身份是指由一些独特特征定义的一个人的自我意识。 身份表示一个_个体_,即一个独立的人类实体。 身份也可以指其他非人实体,比如组织或行政机构。 +身份是指由一些独特特征定义的一个人的自我意识。 身份是指作为_个体_,即一个独特的人类实体。 身份也可以指其他非人实体,比如组织或行政机构。 @@ -27,7 +27,7 @@ summaryPoint3: 多亏了加密技术,用户现在拥有了再次发布、持 身份标识是一条信息,用来指向一个特定身份或多个身份。 常见的身份标识包括: -- 姓名 +- 名称 - 社会保障号/税号 - 手机号码 - 出生日期和出生地点 @@ -39,15 +39,15 @@ summaryPoint3: 多亏了加密技术,用户现在拥有了再次发布、持 1. 去中心化身份增加了个人对识别信息的控制度。 可以在不依赖中心化机构和第三方服务的情况下验证去中心化身份标识和身份证明。 -2. 去中心化身份解决方案为验证和管理用户身份提供一种可保护隐私的去信任无缝方法。 +2. 去中心化身份解决方案为验证和管理用户身份提供了一种免信任、无缝且保护隐私的方法。 3. 去中心化身份利用区块链技术,在不同方之间建立信任,并提供加密保证来证实身份证明的有效性。 -4. 去中心化身份使身份数据可移植。 用户将身份证明和身份标识存储在移动钱包中,并可以与他们选择的任何一方共享。 去中心化身份标识和身份证明不会被锁在签发组织的数据库中。 +4. 去中心化身份使身份数据可移植。 用户将身份证明和标识符存储在移动钱包中,并可以与他们选择的任何一方共享。 去中心化身份标识和身份证明不会被锁在签发组织的数据库中。 -5. 去中心化身份应与新兴的[零知识](/glossary/#zk-proof)技术充分配合,这将使个人在无需透露具体细节的情况下,能够证明他们拥有过某物或做过某事。 这可以成为一种将信任和隐私结合在一起的强有力方式,适用于投票等应用。 +5. 去中心化身份应与新兴的[零知识](/glossary/#zk-proof)技术很好地配合,这将使个人能够证明他们拥有某物或做过某事,但无需透露具体是什么。 这可以成为一种将信任和隐私结合在一起的强有力方式,适用于投票等应用。 -6. 去中心化身份使[防女巫](/glossary/#anti-sybil)机制能够识别一人假扮多人操控某个系统或发起垃圾邮件攻击的情况。 +6. 去中心化身份能使[反女巫](/glossary/#anti-sybil)机制能够识别一个个体假装成多个个体以利用或滥刷某个系统的情况。 ## 去中心化身份用例 {#decentralized-identity-use-cases} @@ -55,47 +55,73 @@ summaryPoint3: 多亏了加密技术,用户现在拥有了再次发布、持 ### 1. 通用登录 {#universal-dapp-logins} -去中心化身份有助于实现去中心化身份验证替代密码登录。 服务提供商可以向用户发布认证,这些认证可以存储在以太坊钱包中。 身份证明的一个示例是[非同质化代币](/glossary/#nft),可授予持有者访问在线社区的权限。 +去中心化身份有助于实现去中心化身份验证替代密码登录。 服务提供商可以向用户发布认证,这些认证可以存储在以太坊钱包中。 身份证明的一个示例是非同质化代币 ([NFT](/glossary/#nft)),可授予持有者访问在线社区的权限。 -然后,[使用以太坊登录](https://siwe.xyz/)功能将使服务器能够确认用户的以太坊帐户,并从他们的帐户地址获取所需的身份证明。 这意味着用户无需记住冗长的密码即可访问平台和网站,从而改善用户的线上体验。 +然后,[使用以太坊登录](https://siwe.xyz/)功能将使服务器能够确认用户的以太坊帐户,并从其帐户地址获取所需的身份证明。 这意味着用户无需记住冗长的密码即可访问平台和网站,从而改善用户的线上体验。 -### 2. “了解你的客户”身份验证 {#kyc-authentication} +### 2. KYC 身份验证 {#kyc-authentication} 许多在线服务的使用需要个人提供身份证明和凭证,例如驾驶执照或国家护照。 但这种方法是有问题的,因为私人用户信息可能会被泄露,并且服务提供商无法验证身份证明的真实性。 -去中心化身份使公司能够跳过传统的[了解你的客户 (KYC)](https://en.wikipedia.org/wiki/Know_your_customer) 流程,通过可验证凭据验证用户身份。 这降低了身份管理的成本,并防止使用伪造证件。 +去中心化身份使公司能够跳过传统的[“了解你的客户”(KYC)](https://en.wikipedia.org/wiki/Know_your_customer) 流程,通过可验证凭证来验证用户身份。 这降低了身份管理的成本,并防止使用伪造证件。 ### 3. 投票和在线社区 {#voting-and-online-communities} -在线投票和社交媒体是去中心化身份的两个新应用。 在线投票方案容易受到操控,尤其当恶意行为者创建虚假身份进行投票时。 要求个人提供链上身份证明可以提高在线投票流程的公平性。 +在线投票和社交媒体是去中心化身份的两个新应用。 在线投票方案容易受到操控,尤其当恶意行为者创建虚假身份进行投票时。 要求个人提供链上身份认证可以提高在线投票流程的公平性。 去中心化身份可以帮助创建没有虚假帐户的在线社区。 例如,每位用户可能必须使用链上身份系统(如以太坊域名服务)来验证他们的身份,从而减少是机器人的可能性。 -### 4. 防女巫保护 {#sybil-protection} +### 4. 反女巫保护 {#sybil-protection} -使用[二次方投票](/glossary/#quadratic-voting)的资助应用程序容易受到[女巫攻击](/glossary/#sybil-attack),因为当有更多人参与投票时,资助的价值就会增加,这会促使用户将他们的捐赠分散到多个身份。 通过增加每位参与者证明他们是真人的负担,去中心化身份有助于防止这种情况发生,尽管通常不必透露具体的私人信息。 +使用[二次方投票](/glossary/#quadratic-voting)的资助应用程序容易受到[女巫攻击](/glossary/#sybil-attack)的影响,因为当更多人投票时,资助的价值就会增加,这会激励用户将捐款分散到多个身份中。 通过增加每位参与者证明他们是真人的负担,去中心化身份有助于防止这种情况发生,尽管通常不必透露具体的私人信息。 + +### 5. 国家和政府 ID {#national-and-government-id} + +政府可以利用去中心化身份的原则,在以太坊上将国家 ID、护照或驾照等基础身份证件作为可验证凭证发行,从而提供强大的加密真实性保证,以减少在线身份验证中的欺诈和伪造行为。 公民可以将这些身份证明存储在他们的个人[钱包](/wallets/)中,并用它们来证明自己的身份、年龄或投票权。 + +该模型允许选择性披露,特别是在与[零知识证明 (ZKP)](/zero-knowledge-proofs/) 隐私技术结合使用时。 例如,公民可以通过加密方式证明自己年满 18 岁以访问有年龄限制的服务,而无需透露其确切出生日期,从而提供比传统 ID 更高的隐私性。 + +#### 💡案例研究:以太坊上的不丹国家数字身份 (NDI) {#case-study-bhutan-ndi} + +- 为不丹近 80 万公民提供可验证的身份凭证 +- 于 2025 年 10 月从 Polygon 网络[迁移到以太坊主网](https://www.bhutanndi.com/article/bhutan-adopts-ethereum-for-national-identity-a-new-chapter-in-digital-sovereignty_2d0c7ec2-5605-4c42-b258-bd9361ae8878) +- 截至 2025 年 3 月,已发行超过 [234,000 个数字 ID](https://www.blockchain-council.org/blockchain/bhutan-uses-blockchain-in-digital-id-project/) + +不丹王国于 2025 年 10 月[将其国家数字身份 (NDI) 系统迁移到](https://www.bhutanndi.com/article/bhutan-adopts-ethereum-for-national-identity-a-new-chapter-in-digital-sovereignty_2d0c7ec2-5605-4c42-b258-bd9361ae8878)以太坊。 不丹的 NDI 系统建立在去中心化身份和自托管身份的原则之上,使用去中心化标识符和可验证凭证,将数字签名的凭证直接颁发到公民的个人钱包中。 通过将这些凭证的加密证明锚定在以太坊上,该系统确保了它们的真实性、防篡改性,并且任何一方都可以在不查询中央机构的情况下进行验证。 + +该系统的架构通过使用[零知识证明 (ZKP)](/zero-knowledge-proofs/) 技术来强调隐私。 这种“选择性披露”的实现方式允许公民在访问服务时证明特定事实(例如“我已年满 18 岁”或“我是公民”),而无需透露其完整的身份证号码或确切的出生日期等基础个人数据。 这展示了以太坊在构建安全、以用户为中心且保护隐私的国家 ID 系统方面的强大实际应用。 + +#### 💡案例研究:以太坊[二层网络](/layer-2/) ZKSync Era 上的布宜诺斯艾利斯市 QuarkID {#case-study-buenos-aires-quarkid} + +- 在发布时向超过 [360 万用户](https://buenosaires.gob.ar/innovacionytransformaciondigital/miba-con-tecnologia-quarkid-la-ciudad-de-buenos-aires-incorporo)颁发了去中心化身份凭证 +- QuarkID 是一种开源协议,被联合国可持续发展目标认定为[数字公共产品](https://www.digitalpublicgoods.net/r/quarkid) +- 强调“[政府即用户](https://buenosaires.gob.ar/innovacionytransformaciondigital/miba-con-tecnologia-quarkid-la-ciudad-de-buenos-aires-incorporo)”模型,即市政府不拥有该协议,从而赋予公民完全的数据所有权和隐私权 + +2024 年,布宜诺斯艾利斯市政府 (GCBA) 将 QuarkID 集成到 miBA 中。QuarkID 是由 GCBA 创新和数字化转型秘书处构建的开源“数字信任框架”,miBA 则是该市居民用于访问政府服务和官方文件的官方应用程序。 发布时,miBA 的所有 360 多万用户都获得了去中心化的数字身份,允许他们管理和分享链上可验证的数字文件和证书,包括公民身份凭证、出生、结婚和死亡证明、税务记录、疫苗接种记录等。 + +QuarkID 系统建立在以太坊[二层网络](/layer-2/) ZKSync Era 之上,使用 ZKP 技术,允许公民通过移动设备点对点地验证个人凭证,而无需暴露不必要的个人数据。 该计划强调了一个“政府即用户”的模型,其中 GCBA 作为开源、可互操作的 QuarkID 协议的一个用户,而不是一个中心化的所有者。 这种支持 ZKP 的架构提供了一个关键的隐私功能:任何第三方,甚至包括 GCBA,都无法追踪公民如何、何时或为何使用他们的凭证。 这个成功的项目为公民提供了完全的自托管身份和对其敏感数据的控制权,所有这些都由以太坊的全球分布式网络保障安全。 ## 什么是身份证明? {#what-are-attestations} 身份证明是一个实体对另一个实体提出的所有权声明。 如果你在美国生活,你的驾驶执照会由美国车辆管理局(一个实体)颁发,它证明你(另一个实体)依法可驾驶汽车。 -身份证明与身份标识不同。 身份证明_包含_用于指向特定身份的身份标识,并声明与此身份相关的属性。 因此,你的驾驶执照具有身份标识(姓名、出生日期、地址),但也是你具有合法驾驶权利的证明。 +身份证明与身份标识不同。 身份证明_包含_用于引用特定身份的标识符,并对与此身份相关的属性进行声明。 因此,你的驾驶执照具有身份标识(姓名、出生日期、地址),但也是你具有合法驾驶权利的证明。 ### 什么是去中心化身份标识? {#what-are-decentralized-identifiers} 诸如你的法定姓名或电子邮件地址等传统身份标识依赖于第三方——政府和电子邮件提供商。 去中心化身份标识 (DID) 则不同——它们不由任何中心实体发布、管理或控制。 -去中心化身份标识由个人发行、持有和控制。 [以太坊帐户](/glossary/#account)是去中心化身份标识的一个示例。 你可以根据需要创建任意数量的帐户,无需任何人的许可,也无需将它们存储在一个中心注册系统中。 +去中心化身份标识由个人发行、持有和控制。 [以太坊帐户](/glossary/#account)是去中心化标识符的一个示例。 你可以根据需要创建任意数量的帐户,无需任何人的许可,也无需将它们存储在一个中心注册系统中。 -去中心化身份标识存储在分布式账本([区块链](/glossary/#blockchain))或[对等网络](/glossary/#peer-to-peer-network)上。 这使得去中心化身份标识 (DID) 具有[全局唯一性、可解析性、高可用性,并可加密验证](https://w3c-ccg.github.io/did-primer/)。 去中心化身份标识可与不同的实体相关联,包括个人、组织或政府机构。 +去中心化标识符存储在分布式账本([区块链](/glossary/#blockchain))或[点对点网络](/glossary/#peer-to-peer-network)上。 这使得去中心化标识符 (DID) [具有全局唯一性、高可用性、可解析性,并可加密验证](https://w3c-ccg.github.io/did-primer/)。 去中心化身份标识可与不同的实体相关联,包括个人、组织或政府机构。 -## 是什么让去中心化身份标识成为可能? {#what-makes-decentralized-identifiers-possible} +## 是什么让去中心化身份标识成为可能? 是什么让去中心化标识符成为可能?{#what-makes-decentralized-identifiers-possible} -### 1. 公钥加密 {#public-key-cryptography} +### 1. 公钥密码学 {#public-key-cryptography} -公钥加密是一种为实体生成[公钥](/glossary/#public-key)和[私钥](/glossary/#private-key)的信息安全措施。 公钥[加密](/glossary/#cryptography)在区块链网络中用于验证用户身份和证明数字资产的所有权。 +公钥密码学是一种信息安全措施,为实体生成一个[公钥](/glossary/#public-key)和一个[私钥](/glossary/#private-key)。 公钥[密码学](/glossary/#cryptography)在区块链网络中用于验证用户身份和证明数字资产的所有权。 -一些去中心化身份标识,如以太坊帐户,都有公钥和私钥。 公钥用于识别帐户的操控者,而私钥可以签名和解密此帐户的消息。 公钥加密提供验证实体身份、防止冒充身份和使用假身份所需的证明,它使用[加密签名](https://andersbrownworth.com/blockchain/public-private-keys/)来验证所有声明。 +一些去中心化身份标识,如以太坊帐户,都有公钥和私钥。 公钥用于识别帐户的操控者,而私钥可以签名和解密此帐户的消息。 公钥密码学提供验证实体身份、防止冒充和使用虚假身份所需的证明,它使用[加密签名](https://andersbrownworth.com/blockchain/public-private-keys/)来验证所有声明。 ### 2. 去中心化数据存储 {#decentralized-datastores} @@ -103,11 +129,11 @@ summaryPoint3: 多亏了加密技术,用户现在拥有了再次发布、持 如有任何人需要确认去中心化身份标识的有效性,他们可以在区块链上查找相关公钥。 这与需要第三方进行身份认证的传统身份标识不同。 -## 去中心化身份标识和身份证明如何实现去中心化身份? {#how-decentralized-identifiers-and-attestations-enable-decentralized-identity} +## 去中心化身份标识和身份证明如何实现去中心化身份? 去中心化标识符和身份证明如何实现去中心化身份?{#how-decentralized-identifiers-and-attestations-enable-decentralized-identity} 去中心化身份的概念是,与身份有关的信息应由自己控制,且应该是私密和可移植的,而其主要构成要素是去中心化身份标识和身份证明。 -在去中心化身份的背景下,身份证明(又称[可验证凭证](https://www.w3.org/TR/vc-data-model/))是由签发者发布、可加密验证的防篡改声明。 实体(如,组织)发出的每个身份证明或可验证凭证都与他们的去中心化身份标识有关。 +在去中心化身份的背景下,身份证明(也称为[可验证凭证](https://www.w3.org/TR/vc-data-model/))是由签发者发布的、防篡改、可加密验证的声明。 实体(如,组织)发出的每个身份证明或可验证凭证都与他们的去中心化身份标识有关。 由于去中心化身份标识存储在区块链上,任何人都可以多方查证以太坊上签发者的去中心化身份标识,以验证身份证明的有效性。 实际上,以太坊区块链就像是一个共用目录,能够验证与某些实体相关的去中心化身份标识。 @@ -115,77 +141,78 @@ summaryPoint3: 多亏了加密技术,用户现在拥有了再次发布、持 去中心化身份标识对于通过去中心化身份保护个人隐私信息不受侵犯也至关重要。 例如,如果某人提交一份身份证明的证据(驾驶执照),则验证者不需要检查证据中信息的有效性。 只需要获得身份证明真实性的加密保证,以及颁发组织身份的加密保证,验证者就可以确定证据是否有效。 -## 去中心化身份中身份证明的类型 {#types-of-attestations-in-decentralized-identity} +## 去中心化身份中的身份证明类型 {#types-of-attestations-in-decentralized-identity} 在基于太坊的身份生态系统中,如何存储和检索身份证明信息与传统身份管理系统不同。 下文概括了一些在去中心化身份系统中签发、存储和验证身份证明的方法。 -### 链下身份证明 {#off-chain-attestations} +### 链下身份证明 {#offchain-attestations} -将身份证明存储在链上的一个问题是,其中可能包含个人想要保密的信息。 以太坊区块链具有开放性,因此不适合用于存储此类身份证明。 +将身份认证存储在链上的一个问题是,其中可能包含个人想要保密的信息。 以太坊区块链具有开放性,因此不适合用于存储此类身份证明。 -解决方法是签发身份证明至用户的数字钱包,由用户链下持有,但使用签发者链上存储的去中心化身份标识进行签名。 这些身份证明被编码为 [JSON Web 令牌](https://en.wikipedia.org/wiki/JSON_Web_Token),其中包含签发者的数字签名,从而可以轻松验证链下声明。 +解决方法是签发身份认证至用户的数字钱包,由用户链下持有,但使用签发者链上存储的去中心化身份标识进行签名。 这些身份证明被编码为 [JSON Web 令牌](https://en.wikipedia.org/wiki/JSON_Web_Token),其中包含签发者的数字签名——可以轻松验证链下声明。 -以下是用于解释链下身份证明的假设场景: +以下是用于解释链下身份认证的假设场景: 1. 大学(签发者)生成身份证明(数字学术证书),用其密钥签名,然后将其颁发给 Bob(身份所有者)。 2. Bob 申请了一份工作并想向雇主证明他的学历,因此他分享了移动钱包中的身份证明。 然后,公司(验证者)可以通过检查签发者的去中心化身份(即其在以太坊上的公钥)来确认身份证明的有效性。 -### 可以随时访问的链下身份证明 {#offchain-attestations-with-persistent-access} +### 具有持久访问权限的链下身份证明 {#offchain-attestations-with-persistent-access} -在这种协议下,身份证明将被转变为 JSON 文件并存储在链下(理想情况下存储在[去中心化云存储](/developers/docs/storage/)平台上,例如 IPFS 或 Swarm)。 但是,JSON 文件的[哈希值](/glossary/#hash)存储在链上,并通过链上注册系统链接至去中心化身份。 所关联的去中心化身份可以是身份证明的签发者或接收者。 +在这种协议下,身份证明被转换为 JSON 文件并存储在链下(理想情况下存储在 IPFS 或 Swarm 等[去中心化云存储](/developers/docs/storage/)平台上)。 但是,JSON 文件的[哈希](/glossary/#hash)值存储在链上,并通过链上注册表链接至去中心化标识符 (DID)。 所关联的去中心化身份可以是身份证明的签发者或接收者。 这种方法使身份证明能够基于区块链长期存在,同时使声明信息保持加密并维持其可验证性。 它还允许选择性披露,因为私钥的持有者可以解密信息。 ### 链上身份证明 {#onchain-attestations} -链上身份证明保存在以太坊区块链上的[智能合约](/glossary/#smart-contract)中。 智能合约(充当注册系统)将身份证明映射到相应的链上去中心化身份标识(公钥)。 +链上身份证明保存在以太坊区块链上的[智能合约](/glossary/#smart-contract)中。 智能合约(充当注册系统)将身份认证映射到相应的链上去中心化身份标识(公钥)。 -以下示例展示了链上身份证明在实践中的使用方式: +以下示例展示了链上身份认证在实践中的使用方式: 1. 一家公司(XYZ 公司)计划使用智能合约出售所有权份额,但只想卖给那些已完成背景调查的买家。 -2. XYZ 公司可以让执行背景调查的公司在以太坊上发布链上身份证明。 此身份证明可以证实某人已通过背景调查,但不会暴露任何个人信息。 +2. XYZ 公司可以让执行背景调查的公司在以太坊上发布链上身份认证。 此身份证明可以证实某人已通过背景调查,但不会暴露任何个人信息。 3. 出售股份的智能合约可以核查注册合约中筛选出的买家的身份,从而使智能合约确定哪些人可以购买股份。 ### 灵魂绑定代币和身份 {#soulbound} -[灵魂绑定代币](https://vitalik.eth.limo/general/2022/01/26/soulbound.html)([不可转让的非同质化代币](/glossary/#nft))可用于收集特定钱包的独有信息。 这有效地创建了一个绑定至特定以太坊地址的唯一链上身份,其中可能包括代表成就(例如完成某些特定在线课程或在游戏中超过特定分数)或社区参与度的代币。 +[灵魂绑定代币](https://vitalik.eth.limo/general/2022/01/26/soulbound.html)([不可转让的 NFT](/glossary/#nft))可用于收集特定钱包的独有信息。 这有效地创建了一个绑定至特定以太坊地址的唯一链上身份,其中可能包括代表成就(例如完成某些特定在线课程或在游戏中达到阈值分数)或社区参与度的代币。 ## 使用去中心化身份 {#use-decentralized-identity} 有许多雄心勃勃的项目使用以太坊作为去中心化身份解决方案的基础: -- **[以太坊域名服务 (ENS)](https://ens.domains/)** - _用于链上机器可读标识(例如以太坊钱包地址、内容哈希和元数据)的去中心化命名系统。_ -- **[SpruceID](https://www.spruceid.com/)** - _去中心化身份项目允许用户使用以太坊帐户和以太坊域名服务配置文件来控制数字身份,而不是依赖第三方服务。_ -- **[以太坊认证服务 (EAS)](https://attest.sh/)** - _一个去中心化的账本/协议,用于进行各类链上或链下认证。_ -- **[非机器人证明](https://www.proofofhumanity.id)** - _非机器人证明 (PoH) 是在以太坊上建立的社会身份验证系统。_ -- **[BrightID](https://www.brightid.org/)** - _一个去中心化的开源社交身份网络,旨在通过创建和分析社交图谱来改进身份验证。_ -- **[walt.id](https://walt.id)** — _开源去中心化身份和钱包基础架构,使开发人员和组织能够利用自主主权身份和非同质化代币/灵魂绑定代币。_ -- **[Veramo](https://veramo.io/)** - _一个 JavaScript 框架,使任何人都能轻松地在其应用程序中使用可用加密方法验证的数据。_ +- **[以太坊域名服务 (ENS)](https://ens.domains/)** - _一种去中心化的命名系统,用于机器可读的链上标识符,如以太坊钱包地址、内容哈希和元数据。_ +- **[使用以太坊登录 (SIWE)](https://siwe.xyz/)** - _使用以太坊帐户进行身份验证的开放标准。_ +- **[SpruceID](https://www.spruceid.com/)** - _一个去中心化身份项目,允许用户使用以太坊帐户和 ENS 个人资料来控制数字身份,而无需依赖第三方服务。_ +- **[以太坊身份证明服务 (EAS)](https://attest.org/)** - _一个去中心化的账本/协议,用于对任何事物进行链上或链下身份证明。_ +- **[Proof of Humanity](https://www.proofofhumanity.id)** - _Proof of Humanity (或 PoH) 是一个建立在以太坊上的社会身份验证系统。_ +- **[BrightID](https://www.brightid.org/)** - _一个去中心化的开源社交身份网络,旨在通过创建和分析社交图谱来改革身份验证。_ +- **[walt.id](https://walt.id)** — _开源的去中心化身份和钱包基础设施,使开发人员和组织能够利用自托管身份和 NFT/SBT。_ +- **[Veramo](https://veramo.io/)** - _一个 JavaScript 框架,让任何人都可以轻松地在他们的应用程序中使用可加密验证的数据。_ -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} ### 文章 {#articles} -- [区块链用例:数字身份中的区块链](https://consensys.net/blockchain-use-cases/digital-identity/) — _共识系统_ -- [什么是以太坊 ERC725? 区块链上的自主身份管理](https://cryptoslate.com/what-is-erc725-self-sovereign-identity-management-on-the-blockchain/) — _Sam Town_ +- [区块链用例:数字身份中的区块链](https://consensys.net/blockchain-use-cases/digital-identity/) — _ConsenSys_ +- [什么是以太坊 ERC725? 区块链上的自托管身份管理](https://cryptoslate.com/what-is-erc725-self-sovereign-identity-management-on-the-blockchain/) — _Sam Town_ - [区块链如何解决数字身份问题](https://time.com/6142810/proof-of-humanity/) — _Andrew R. Chow_ -- [什么是去中心化身份以及你为什么要关心?](https://web3.hashnode.com/what-is-decentralized-identity) — _Emmanuel Awosika_ +- [什么是去中心化身份,为何要关注它?](https://web3.hashnode.com/what-is-decentralized-identity) — _Emmanuel Awosika_ - [去中心化身份简介](https://walt.id/white-paper/digital-identity) — _Dominik Beron_ ### 视频 {#videos} -- [去中心化身份(奖励直播环节)](https://www.youtube.com/watch?v=ySHNB1za_SE&t=539s) — _一个很好的去中心化身份解说视频,来自 Andreas Antonopolous_ -- [使用以太坊和 Ceramic、IDX、React 以及 3ID Connect 的去中心化身份登录](https://www.youtube.com/watch?v=t9gWZYJxk7c) - _来自 Nader Dabit 的一个 YouTube 教程,介绍如何使用用户的以太坊钱包构建身份管理系统以创建、读取和更新他们的个人资料_ -- [BrightID - 以太坊上的去中心化身份](https://www.youtube.com/watch?v=D3DbMFYGRoM) — _Bankless 播客节目讨论 BrightID(以太坊的去中心化身份解决方案)_ -- [链下互联网:去中心化身份和可验证凭证](https://www.youtube.com/watch?v=EZ_Bb6j87mg) — Evin McMullen 的 EthDenver 2022 演讲 -- [可验证凭据释义](https://www.youtube.com/watch?v=ce1IdSr-Kig) - Tamino Baumann 的 YouTube 讲解视频和演示 +- [去中心化身份(直播附赠环节)](https://www.youtube.com/watch?v=ySHNB1za_SE&t=539s) — _Andreas Antonopolous 制作的关于去中心化身份的精彩解说视频_ +- [使用以太坊和 Ceramic、IDX、React 以及 3ID Connect 登录和实现去中心化身份](https://www.youtube.com/watch?v=t9gWZYJxk7c) — _Nader Dabit 制作的 YouTube 教程,介绍如何使用用户的以太坊钱包构建身份管理系统以创建、读取和更新他们的个人资料_ +- [BrightID - 以太坊上的去中心化身份](https://www.youtube.com/watch?v=D3DbMFYGRoM) — _Bankless 播客节目,讨论以太坊的去中心化身份解决方案 BrightID_ +- [链下互联网:去中心化身份和可验证凭证](https://www.youtube.com/watch?v=EZ_Bb6j87mg) — Evin McMullen 在 2022 年 EthDenver 上的演讲 +- [可验证凭证解说](https://www.youtube.com/watch?v=ce1IdSr-Kig) - Tamino Baumann 制作的 YouTube 解说视频(含演示) ### 社区 {#communities} -- [GitHub 上的 ERC-725 联盟](https://github.com/erc725alliance) — _支持 ERC725 标准管理以太坊区块链上的身份_ -- [EthID Discord 服务器](https://discord.com/invite/ZUyG3mSXFD) — _使用以太坊登录的爱好者和开发者社区_ -- [Veramo Labs](https://discord.gg/sYBUXpACh4) - _开发者社区,帮助为应用程序构建可验证数据框架_ -- [walt.id](https://discord.com/invite/AW8AgqJthZ) — _一个由开发者和构建者组成的社区,致力于研究跨各种行业的去中心化身份用例_ +- [GitHub 上的 ERC-725 联盟](https://github.com/erc725alliance) — _支持在以太坊区块链上管理身份的 ERC725 标准_ +- [EthID Discord 服务器](https://discord.com/invite/ZUyG3mSXFD) — _致力于“使用以太坊登录”和“以太坊关注协议”的爱好者和开发人员社区_ +- [Veramo Labs](https://discord.gg/sYBUXpACh4) — _一个为应用程序构建可验证数据框架的开发人员社区_ +- [walt.id](https://discord.com/invite/AW8AgqJthZ) — _一个由开发人员和构建者组成的社区,致力于研究跨各种行业的去中心化身份用例_ diff --git a/public/content/translations/zh/defi/index.md b/public/content/translations/zh/defi/index.md index 679662b44bf..77a43d0129a 100644 --- a/public/content/translations/zh/defi/index.md +++ b/public/content/translations/zh/defi/index.md @@ -1,16 +1,16 @@ --- -title: 去中心化金融 (DeFi) -metaTitle: 什么是去中心化金融? 去中心化金融的优势和作用 -description: 以太坊上的去中心化金融简介 +title: "去中心化金融 (DeFi)" +metaTitle: "什么是去中心化金融? 去中心化金融的优势和作用" +description: "以太坊上的去中心化金融简介" lang: zh template: use-cases emoji: ":money_with_wings:" image: /images/use-cases/defi.png -alt: 由乐高积木拼成的以太坊徽标。 +alt: "由乐高积木拼成的以太坊徽标。" sidebarDepth: 2 -summaryPoint1: 当前金融体系的全球性、开放性替代方案。 -summaryPoint2: 允许用户进行借贷、储蓄、投资、交易等等的产品。 -summaryPoint3: 基于开源技术,任何人都可以来编程。 +summaryPoint1: "当前金融体系的全球性、开放性替代方案。" +summaryPoint2: "允许用户进行借贷、储蓄、投资、交易等等的产品。" +summaryPoint3: "基于开源技术,任何人都可以来编程。" --- 去中心化金融是专为互联网时代构建的开放式全球金融系统,可替代不透明、控制严格并由几十年前的基础设施和流程支撑的系统。 让你可以控制和了解自己的资金。 让你有机会接触全球市场,并可以替代当地货币或银行业务。 去中心化金融产品向任何有互联网连接的人开放金融服务,产品主要由用户创造和维护。 迄今为止,价值数百亿美元的加密货币已经通过去中心化金融应用程序流动,而且每天都在增长。 @@ -23,7 +23,7 @@ summaryPoint3: 基于开源技术,任何人都可以来编程。 -## 去中心化金融与传统金融 {#defi-vs-tradfi} +## DeFi 与传统金融 {#defi-vs-tradfi} 了解去中心化金融潜力的最佳方法是了解目前存在的问题。 @@ -36,9 +36,9 @@ summaryPoint3: 基于开源技术,任何人都可以来编程。 - 由于内部的人工流程,资金转移可能需要几天时间。 - 金融服务存在溢价,因为中介机构需要分成。 -### 对比 {#defi-comparison} +### 比较 {#defi-comparison} -| 去中心化金融 | 传统金融 | +| 去中心化金融 (DeFi) | 传统金融 | | --------------------------------- | ------------------------------------ | | 你持有你的钱。 | 资金由机构持有。 | | 你可以控制自己的资金流向和使用方式。 | 你必须相信机构不会出现资金管理不善问题,比如不会将钱借给高风险借款人。 | @@ -56,17 +56,17 @@ summaryPoint3: 基于开源技术,任何人都可以来编程。 从某种程度来讲,比特币是第一款去中心化金融应用程序。 比特币让你真正拥有和掌控价值,并可将其发送到世界任何地方。 为实现这一点,它提供了一种方式,让众多互不信任的人在无需可信赖中介的情况下,就帐户的账本达成一致。 比特币向所有人公开,任何人都无权更改其规则。 比特币的规则(例如稀缺性和开放性),都写入了技术中。 与传统金融不同:在传统金融中,政府可以印钞使你的存款贬值,而机构则可以关闭市场。 -以太坊便以此为基础。 就像比特币一样,规则不会因你而改变,而且每个人都可以得到。 使用[智能合约](/glossary/#smart-contract)技术还可以让这种数字货币可编程,使其功能不仅仅限于储蓄和交易。 +以太坊便以此为基础。 就像比特币一样,规则不会因你而改变,而且每个人都可以得到。 但它也使得这种数字货币可编程,通过使用[智能合约](/glossary/#smart-contract),你可以超越储存和发送价值的范畴。 ## 可编程货币 {#programmable-money} -这听起来很奇怪……“我为什么会想对钱进行编程”? 然而,这只是以太坊代币的一个默认功能。 任何人都可以对逻辑编程,以生成支付。 这样,你就可以将比特币的控制权和安全性与传统金融机构提供的服务相结合。 然后,你就可以用加密货币做一些比特币做不到的事情,比如借贷、预约付款、投资指数基金等等。 +这听起来很奇怪…… “我为什么要对我的钱进行编程”? 然而,这只是以太坊代币的一个默认功能。 任何人都可以对逻辑编程,以生成支付。 这样,你就可以将比特币的控制权和安全性与传统金融机构提供的服务相结合。 然后,你就可以用加密货币做一些比特币做不到的事情,比如借贷、预约付款、投资指数基金等等。 - +
如果你不熟悉以太坊,请尝试我们推荐的去中心化金融应用程序。
探索去中心化金融应用程序 @@ -78,15 +78,15 @@ summaryPoint3: 基于开源技术,任何人都可以来编程。 大多数金融服务都有去中心化的替代方案。 但以太坊也为打造全新的金融产品开辟了机会。 这个清单还在不断增长。 -- [向世界各地汇款](#send-money) +- [向全球汇款](#send-money) - [在全球范围内流转资金](#stream-money) - [获取稳定货币](#stablecoins) - [抵押借款](#lending) - [无抵押借款](#flash-loans) -- [开始加密货币存款](#saving) +- [开始加密货币储蓄](#saving) - [交易代币](#swaps) - [扩充你的投资组合](#investing) -- [为你的想法提供资金](#crowdfunding) +- [为你的想法募资](#crowdfunding) - [购买保险](#insurance) - [管理你的投资组合](#aggregators) @@ -94,17 +94,17 @@ summaryPoint3: 基于开源技术,任何人都可以来编程。 ### 向世界各地快速汇款 {#send-money} -作为一个区块链,以太坊设计用于让用户在全球范围内安全地发送交易。 与比特币一样,以太坊使得向世界各地发送资金就像发送电子邮件一样容易。 只需从钱包中输入收款人的[以太坊域名服务名称](/glossary/#ens)(如 bob.eth)或他们的帐户地址,你的付款(通常)将在几分钟内直接到达对方帐户。 要发送或接收付款,你将需要一个[钱包](/wallets/)。 +作为一个区块链,以太坊设计用于让用户在全球范围内安全地发送交易。 与比特币一样,以太坊使得向世界各地发送资金就像发送电子邮件一样容易。 只需在你的钱包中输入收款人的 [ENS 名称](/glossary/#ens)(如 bob.eth)或其账户地址,你的付款(通常)将在几分钟内直接到账。 要发送或接收付款,你将需要一个[钱包](/wallets/)。 - 查看支付 dapp + 查看支付去中心化应用程序 #### 在全球范围内流转资金... {#stream-money} 你也可以通过以太坊汇款。 这可以让你秒速支付某人的工资,让他们可以在需要时获得资金。 或者立刻租用一些物品,如储物柜或电动滑板车。 -而且,如果你因为以太币的价值波动过大而不想发送或流式传输[以太币](/glossary/#ether),以太坊上还有其他可供选择的货币:[稳定币](/glossary/#stablecoin)。 +而且,如果你因为 [ETH](/glossary/#ether) 的价值波动过大而不想发送或流式传输它,以太坊上还有其他可供选择的货币:[稳定币](/glossary/#stablecoin)。 @@ -128,24 +128,24 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 - 基于资金池,贷款人向借款人可以借贷的资金池提供资金(流动性)。 - 查看借款 dapp + 查看借款去中心化应用程序 选择去中心化贷款人具有许多优势... -#### 隐私借贷 {#borrowing-privacy} +#### 私密借款 {#borrowing-privacy} 今天,贷款和借钱都围绕着相关个人进行。 在放贷前,银行需要了解你是否有能力偿还贷款。 -去中心化借贷无需任何一方表明自己的身份即可进行。 但是,借款人必须提供抵押品,如果他们没有偿还贷款,贷款人将自动获得抵押品。 有的贷款人甚至接受[非同质化代币](/glossary/#nft)作为抵押品。 非同质化代币是指绘画等独特资产。 [关于非同质化代币的更多信息](/nft/) +去中心化借贷无需任何一方表明自己的身份即可进行。 但是,借款人必须提供抵押品,如果他们没有偿还贷款,贷款人将自动获得抵押品。 有些贷款人甚至接受 [NFT](/glossary/#nft) 作为抵押品。 非同质化代币是指绘画等独特资产。 [关于 NFT 的更多信息](/nft/) 这允许你在不进行征信调查或透露私人信息的情况下借钱。 -#### 获得全球资金 {#access-global-funds} +#### 获取全球资金 {#access-global-funds} 当你选择去中心化贷款人时,可以使用来自全球各地的存款,而不仅仅是选定银行或机构保管的资金。 这使人们更容易获得贷款,并提高利率。 -#### 税收优惠 {#tax-efficiencies} +#### 税收效率 {#tax-efficiencies} 借贷可以让你获得所需资金,而无需出售你的以太币(该行为需要征税)。 然而,你可以使用以太币作为抵押品,借入稳定币。 这不仅为你提供所需的现金流,你还可以继续持有自己的以太币。 当你需要现金时,稳定币是更好的代币,因为它们不会像以太币一样波动。 [关于稳定币的更多信息](#stablecoins) @@ -178,19 +178,19 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 -### 开始使用加密货币存款 {#saving} +### 开始使用加密货币储蓄 {#saving} -#### 借款 {#lending} +#### 出借 {#lending} 你可以通过借出加密货币来赚取利息,并看到资金的实时增长。 现在的利率比当地银行可能高出许多(如果有幸能够使用当地的银行系统)。 下面是一个示例: -- 你借出 100 Dai [稳定币](/stablecoins/),借给类似 Aave 的产品。 +- 你将 100 Dai(一种[稳定币](/stablecoins/))出借给像 Aave 这样的产品。 - 你会收到 100 个 Aave Dai (aDai),代表你已借出的 Dai。 -- 你的 aDai 将根据利率增加,你可以看到钱包里的余额在增长。 根据[年利率](/glossary/#apr),你的钱包余额在几天甚至几小时后会显示为 100.1234 这样的数字。 +- 你的 aDai 将根据利率增加,你可以看到钱包里的余额在增长。 取决于 [APR](/glossary/#apr),几天甚至几小时后,你的钱包余额就会显示为 100.1234 之类的数字! - 你可以随时提取与 aDai 余额等额的普通 Dai。 - 查看借款 dapp + 查看出借去中心化应用程序 #### 无损彩票 {#no-loss-lotteries} @@ -218,7 +218,7 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 例如,如果你想使用无损彩票 PoolTogether(如上所述),则需要类似 Dai 或 USDC 的代币。 DEX 允许你将以太币换成这些代币,并在完成交易后再换回来。 - 查看代币兑换 + 查看代币交易所 @@ -230,7 +230,7 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 使用中心化交易所时,你必须在交易前存入资产,并相信交易所会妥善处理这些资产。 当你存入资产时,它们会面临风险,因为中心化交易所对黑客来说是诱人目标。 - 查看更多交易 dapp + 查看交易去中心化应用程序 @@ -239,7 +239,7 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 以太坊上有一些基金管理产品,它们会尝试根据你选择的策略为你的投资组合增值。 自动完成而且对每个人都开放,没有管理人员从利润中抽成。 -一个很好的示例是[去中心化金融指数基金](https://defipulse.com/blog/defi-pulse-index/)。 这是一支自动再平衡基金,可确保你的投资组合总是包含市值最高的去中心化金融代币。 你无需管理任何细节,并且可以随时从基金中提款。 +一个很好的例子是 [DeFi Pulse Index 基金 (DPI)](https://defipulse.com/blog/defi-pulse-index/)。 这是一支自动再平衡基金,可确保你的投资组合总是包含市值最高的去中心化金融代币。 你无需管理任何细节,并且可以随时从基金中提款。 查看投资去中心化应用程序 @@ -247,7 +247,7 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 -### 为你的想法提供资金 {#crowdfunding} +### 为你的想法募资 {#crowdfunding} 以太坊是一个理想的众筹平台: @@ -256,10 +256,10 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 - 募捐者可以设置自动退款,例如,如果有未达到特定的最后期限和最低金额,就可以自动退款。 - 查看更多众筹去中心化应用程序 + 查看众筹去中心化应用程序 -#### 二次方融资 {#quadratic-funding} +#### 二次方募资 {#quadratic-funding} 以太坊是开源软件,到目前为止,很多工作都由社区资助。 这催生了一种有趣的新型募资模式:二次方融资。 这有可能改进我们在未来为各种公共产品募资的方式。 @@ -273,7 +273,7 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 这意味着获得 100 笔 1 美元捐款的项目 A 最终可能比获得 1 笔 1 万美元捐款的项目 B 获得更多资金(取决于匹配池的大小)。 - 关于二次方融资的更多信息 + 关于二次方募资的更多信息 @@ -282,7 +282,7 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 去中心化保险旨在使保险更便宜、支付速度更快且更加透明。 随着自动化程度的提高,保险的价格更加低廉,赔付的速度也快了很多。 用来决定你的索赔的数据完全透明。 -就像任何软件一样,以太坊产品也可能出现漏洞。 因此,目前该领域中的许多保险产品都致力于保护用户免受资金损失。 然而,一些项目开始构建全面覆盖我们生活中可能出现的各种情况的保险方案。 Etherisc 的作物保护就是一个很好的例子,其目的是[保护肯尼亚的小农户对抗干旱和洪水侵袭](https://blog.etherisc.com/etherisc-teams-up-with-chainlink-to-deliver-crop-insurance-in-kenya-137e433c29dc)。 去中心化保险可以为那些经常被传统保险拒之门外的农民提供更便宜的保险。 +就像任何软件一样,以太坊产品可能出现漏洞。 因此,目前该领域中的许多保险产品都致力于保护用户免受资金损失。 然而,一些项目开始构建全面覆盖我们生活中可能出现的各种情况的保险方案。 一个很好的例子是 Etherisc 的农作物保险,旨在[保护肯尼亚的小农户免受干旱和洪水的影响](https://blog.etherisc.com/etherisc-teams-up-with-chainlink-to-deliver-crop-insurance-in-kenya-137e433c29dc)。 去中心化保险可以为那些经常被传统保险拒之门外的农民提供更便宜的保险。 查看保险去中心化应用程序 @@ -290,7 +290,7 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 -### 聚集者和投资组合管理 {#aggregators} +### 聚合器和投资组合经理 {#aggregators} 拥有了这么多种服务,你需要一种方法来跟踪跟踪所有投资、贷款和交易。 有许多产品可以让你集中协调所有去中心化金融活动。 这就是去中心化金融开放架构的魅力所在。 团队可以创建界面,你不仅可以看到各个产品中的余额,也可以使用其功能。 当你探索更多的去中心化金融时,可能会发现这个很有用。 @@ -312,7 +312,7 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 这确实意味着,目前需要信任以太坊社区中能够读取代码的技术员。 基于开源的社区有助于控制开发者,但是随着时间的推移,这种需求将逐渐减少,因为智能合约变得更易于阅读。并且开发了其他方法来证明代码的可信赖性。 -## 以太坊与去中心化金融 {#ethereum-and-defi} +## 以太坊和 DeFi {#ethereum-and-defi} 以太坊为去中心化金融提供了良好基础,原因如下: @@ -324,13 +324,13 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 你可以把去中心化金融看成分层结构: 1. 区块链 - 以太坊包含交易历史和帐户状态。 -2. 资产 - [以太币](/what-is-ether/)和其他代币。 -3. 协议 — 提供功能的[智能合约](/glossary/#smart-contract),例如,一项提供去中心化资产借贷的服务。 -4. [应用程序](/apps/) - 我们用来管理和访问协议的产品。 +2. 资产 – [ETH](/what-is-ether/) 和其他代币(货币)。 +3. 协议——提供功能的[智能合约](/glossary/#smart-contract),例如允许去中心化资产出借的服务。 +4. [应用程序](/apps/) – 我们用来管理和访问协议的产品。 -注意:许多去中心化金融使用 [ERC-20 标准](/glossary/#erc-20)。 去中心化金融 (DeFi) 中的应用程序使用一种包装的以太币,称为包装以太币 (WETH)。 [了解更多关于包装以太币的信息](/wrapped-eth)。 +注意:许多 DeFi 都使用 [ERC-20 标准](/glossary/#erc-20)。 去中心化金融 (DeFi) 中的应用程序使用一种包装的以太币,称为包装以太币 (WETH)。 [了解更多关于封装以太币的信息](/wrapped-eth)。 -## 构建去中心化金融 {#build-defi} +## 构建 DeFi {#build-defi} 去中心化金融是一场开源行动。 去中心化金融协议和应用都是开放的,你可以自行检查、分叉和创新。 由于这个分层堆栈(他们都共享相同的基础区块链和资产),协议可以混合和匹配以解锁独特的组合机会。 @@ -338,27 +338,28 @@ Dai 或 USDC 等代币的价值和美元的差距通常保持在几美分以内 关于构建去中心化应用程序的更多信息 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -### 去中心化金融数据 {#defi-data} +### DeFi 数据 {#defi-data} - [DeFi Prime](https://defiprime.com/) - [DeFi Llama](https://defillama.com/) -### 去中心化金融相关文章 {#defi-articles} +### DeFi 文章 {#defi-articles} -- [去中心化金融 (DeFi) 初学者指南](https://blog.coinbase.com/a-beginners-guide-to-decentralized-finance-defi-574c68ff43c4) – _Sid Coelho-Prabhu,2020 年 1 月 6 日_ +- [DeFi 新手指南](https://blog.coinbase.com/a-beginners-guide-to-decentralized-finance-defi-574c68ff43c4) – _Sid Coelho-Prabhu,2020 年 1 月 6 日_ +- [EEA DeFi 风险评估指南](https://entethalliance.org/specs/defi-risks/) – 一份行业支持的概述,介绍了如何识别和评估 DeFi 协议中的关键风险。 ### 视频 {#videos} -- [Finematics - 去中心化金融教育](https://finematics.com/) - _关于去中心化金融的视频_ -- [The Defiant](https://www.youtube.com/playlist?list=PLaDcID4s1KronHMKojfjwiHL0DdQEPDcq) - _去中心化金融基础:在这个偶尔令人困惑的空间里,你开始需要了解的一切。_ -- [Whiteboard Crypto](https://youtu.be/17QRFlml4pA) _ - 什么是去中心化金融?_ +- [Finematics - 去中心化金融教育](https://finematics.com/) – _关于 DeFi 的视频_ +- [The Defiant](https://www.youtube.com/playlist?list=PLaDcID4s1KronHMKojfjwiHL0DdQEPDcq) - _DeFi 基础知识:在这个时而令人费解的领域,入门所需了解的一切。_ +- [Whiteboard Crypto](https://youtu.be/17QRFlml4pA) _什么是 DeFi?_ ### 社区 {#communities} -- [去中心化金融 Llama Discord 服务器](https://discord.defillama.com/) -- [去中心化金融 Pulse Discord 服务器](https://discord.gg/Gx4TCTk) +- [DeFi Llama Discord 服务器](https://discord.defillama.com/) +- [DeFi Pulse Discord 服务器](https://discord.gg/Gx4TCTk) diff --git a/public/content/translations/zh/desci/index.md b/public/content/translations/zh/desci/index.md index 5fcdd41bfa9..f105a6451d7 100644 --- a/public/content/translations/zh/desci/index.md +++ b/public/content/translations/zh/desci/index.md @@ -1,88 +1,89 @@ --- -title: 去中心化科学 (DeSci) -description: 以太坊去中心化科学概览 +title: "去中心化科学 (DeSci)" +description: "以太坊去中心化科学概览" lang: zh template: use-cases emoji: ":microscope:" sidebarDepth: 2 image: /images/future_transparent.png alt: "" -summaryPoint1: 当前科学体系的全球性、开放性替代方案。 -summaryPoint2: 一种能帮助科学家做诸多事情的技术,例如筹集资金、进行实验、分享数据、传播见解等。 -summaryPoint3: 它以开放科学运动为基础。 +summaryPoint1: "当前科学体系的全球性、开放性替代方案。" +summaryPoint2: "一种能帮助科学家做诸多事情的技术,例如筹集资金、进行实验、分享数据、传播见解等。" +summaryPoint3: "它以开放科学运动为基础。" --- ## 什么是去中心化科学 (DeSci)? {#what-is-desci} -去中心化科学 (DeSci) 是一项运动,旨在使用 [Web3](/glossary/#web3) 堆栈构建用于公平、平等地资助、创作、审查、确认、存储和传播科学知识的公共基础设施。 +去中心化科学 (DeSci) 是一项旨在使用 [Web3](/glossary/#web3) 技术栈,为科学知识的资助、创造、评审、认可、存储和传播建立公平公正的公共基础设施的运动。 去中心化科学旨在创建一个生态系统,激励科学家公开分享他们的研究,并因其工作获得荣誉,同时允许任何人轻松了解研究并为研究做出贡献。 去中心化科学的理念是,每个人都应能接触科学知识,同时科学研究的过程应该透明化。 去中心化科学正在创建一个更加去中心化和分布式的科学研究模式,让它能够更加抵制中心机构的审查和控制。 去中心化科学希望通过去中心化获取资金、科学工具和交流的通道,创造一个让新的和非传统的想法能蓬勃发展的环境。 -去中心化科学允许更加多样化的资助来源(从[去中心化自治组织](/glossary/#dao)、[二次捐赠](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2003531)到众筹等等),让数据和方法更加容易获得,并为可复现性提供激励。 +去中心化科学允许更多样化的资金来源(从 [DAO](/glossary/#dao)、[二次捐赠](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2003531) 到众筹等等),让数据和方法更容易获取,并为可复现性提供激励。 ### Juan Benet - 去中心化科学运动 -## 去中心化科学如何改善科学 {#desci-improves-science} +## DeSci 如何改进科学 {#desci-improves-science} 一份关于科学关键问题的不完整清单以及去中心化科学如何帮助解决这些问题 -| **去中心化科学** | **传统科学** | -| ------------------------------------------------- | -------------------------------------- | -| 资金的分配由**公众决定**,使用类似于二次捐赠或去中心化自治组织等机制。 | 小型、封闭的**中心化群体**控制资金的分配。 | -| 你可以与**全球**同行在充满活力的团队中合作。 | 资助组织和你所在的机构会**限制**你的合作。 | -| 资助决定在线上作出并且是**透明的**。 探索新的资助机制。 | 资助决定需要很长时间才能作出,**透明度也有限**。 资助机制很少。 | -| 通过使用 [Web3](/glossary/#web3) 技术,共享实验室服务变得更加简单和透明。 | 共享实验室资源往往是**缓慢和不透明的**。 | -| 可以开发**新的发表模型**,使用 Web3 基元实现信任、透明和全民访问。 | 通过已有的途径发表,这些途径往往被认为**效率低下并且存在偏见的和剥削**。 | -| 你可以**通过同行评审工作赢得代币和声誉**。 | **你的同行评审工作是没有报酬的**,营利性出版商从中获益。 | -| **你自己拥有你创作内容的知识产权**,并根据透明性条款分发。 | **你所在的机构拥有你产出内容的知识产权**。 知识产权的获取不是透明的。 | -| 通过将所有步骤都放在链上,**分享所有的研究**,包括未成功的尝试所产生的数据。 | **发表偏见**意味着研究人员更有可能分享那些取得成功结果的实验。 | +| **去中心化科学** | **传统科学** | +| ------------------------------------------------------ | ----------------------------------- | +| 资金的分配**由公众决定**,使用的是二次捐赠或 DAO 等机制。 | 小型的、封闭的**中心化团体**控制着资金的分配。 | +| 你可以在充满活力的团队中与**来自全球各地**的同行协作。 | 资助组织和你所在的机构会**限制**你的协作。 | +| 资金决策在线上做出,并且过程**透明**。 探索新的资助机制。 | 资助决策周转时间长,且**透明度有限**。 资助机制很少。 | +| 使用 [Web3](/glossary/#web3) 技术,共享实验室服务变得更容易、更透明。 | 共享实验室资源通常**缓慢且不透明**。 | +| 可以开发**新的发表模型**,使用 Web3 基元实现信任、透明和普遍访问。 | 你通过公认**低效、有偏见和具剥削性**的既定渠道发表。 | +| 你可以通过**同行评审工作赚取代币和声誉**。 | 你的**同行评审工作是无偿的**,使营利性出版商受益。 | +| **你拥有自己产生的知识产权 (IP)**,并根据透明的条款进行分发。 | **你所在的机构拥有你产生的知识产权**。 知识产权的获取不是透明的。 | +| 通过将所有步骤都上链,**分享所有研究**,包括不成功的研究数据。 | **发表偏见**意味着研究人员更倾向于分享取得成功结果的实验。 | -## 以太坊与去中心化科学 {#ethereum-and-desci} +## 以太坊和 DeSci {#ethereum-and-desci} 一个去中心化的科学系统将需要强大的安全性、最小的货币和交易成本,以及一个丰富的应用开发生态系统。 以太坊提供构建去中心化科学技术所需的一切。 -## 去中心化科学使用案例 {#use-cases} +## DeSci 用例 {#use-cases} 去中心化科学正在构建一些科学工具,让传统的学术界能够进入数字世界。 以下是一些 Web3 在科学社区的使用案例。 ### 出版 {#publishing} -科学出版是一个比较出名的问题,它由出版社进行管理,依靠科学家、评审人和编辑者这些免费劳动力来产生论文,然后收取高额的出版费。 普通大众通常已经通过税收间接支付了工作成果和出版费用,但仍需要再次向出版商付费来获取同一个工作成果。 发表个人科学论文的总费用通常是五位数 ($USD),这违背了科学知识作为[公共物品](/glossary/#public-goods)的总体概念,同时一小部分出版商获取了巨大的利益。 +科学出版是一个比较出名的问题,它由出版社进行管理,依靠科学家、评审人和编辑者这些免费劳动力来产生论文,然后收取高额的出版费。 普通大众通常已经通过税收间接支付了工作成果和出版费用,但仍需要再次向出版商付费来获取同一个工作成果。 发表单篇科学论文的总费用通常高达五位数(美元),这破坏了科学知识作为[公共物品](/glossary/#public-goods)的整体概念,同时为一小部分出版商创造了巨额利润。 -免费和公开的平台以预打印服务器的形式存在,[比如 ArXiv](https://arxiv.org/)。 然而,这些平台缺乏质量控制、[反女巫机制](/glossary/#anti-sybil),通常没有追踪文章水平的指标,这意味着他们仅仅只是在提交给传统出版商之前宣传一下作品。 在 SciHub 上也可以免费获取公开发表的论文,但这不是合法的,并且通常是在出版商已经拿到付款和作品已被严格的版权法所保护之后。 因此,要使论文和数据可访问且具有内在合法性机制和激励模式,就需要填补巨大的空白。 创造这种系统的工具就在 Web3 中。 +免费和开放获取的平台以预印本服务器的形式存在,[例如 ArXiv](https://arxiv.org/)。 然而,这些平台缺乏质量控制和[抗女巫机制](/glossary/#anti-sybil),并且通常不跟踪文章级别的指标,这意味着它们通常只用于在提交给传统出版商之前宣传作品。 在 SciHub 上也可以免费获取公开发表的论文,但这不是合法的,并且通常是在出版商已经拿到付款和作品已被严格的版权法所保护之后。 因此,要使论文和数据可访问且具有内在合法性机制和激励模式,就需要填补巨大的空白。 创造这种系统的工具就在 Web3 中。 -### 可复现性与可复制性 {#reproducibility-and-replicability} +### 可复现性和可复制性 {#reproducibility-and-replicability} 可复现性和可复制性是高质量科学发现的基础。 - 同一团队使用同一种方法能连续多次获得可复现的结果。 - 不同的团队在同样的实验条件下能获得可复制的结果。 -新的 Web3 原生工具能确保可复现性和可复制性是发现的基础。 我们可以将高质量的科学纳入学术界的技术结构。 Web3 提供了为每个分析组件创建[认证](/glossary/#attestation)的能力:原始数据、计算引擎和应用结果。 共识系统的美妙之处在于,当创建一个可信网络来维护这些组件时,每一个网络参与者都将负责复现计算和验证结果。 +新的 Web3 原生工具能确保可复现性和可复制性是发现的基础。 我们可以将高质量的科学纳入学术界的技术结构。 Web3 能够为每个分析组件(原始数据、计算引擎和应用结果)创建[证明](/glossary/#attestation)。 共识系统的美妙之处在于,当创建一个可信网络来维护这些组件时,每一个网络参与者都将负责复现计算和验证结果。 -### 资金赞助 {#funding} +### 资金 {#funding} -目前资助科学的标准模式是,个人或科学家团队向资助机构提出书面申请。 一个由受信任的个人组成的小组对申请进行评分,然后对候选人进行面试,最后再向一小部分申请提供资金。 除了从申请到获得资助的时间有时**长达数年**外,这种模式还特别容易受到审查小组的**偏见、个人利益和政治因素**的影响。 +目前资助科学的标准模式是,个人或科学家团队向资助机构提出书面申请。 一个由受信任的个人组成的小组对申请进行评分,然后对候选人进行面试,最后再向一小部分申请提供资金。 这种模式除了造成瓶颈,导致从申请到获得资助有时需要**等待数年**之外,还众所周知地极易**受到评审小组的偏见、私利和政治的影响**。 研究表明捐赠评审小组往往无法选出高质量的申请,因为同一个提案在不同的评审小组会得到完全不同的结果。 随着资金越来越少,资金集中到了更少的高级研究人员手中,他们的项目更加的保守。 这种效果创造了一个过度竞争的资金环境,助长了不正当的激励机制,并且扼杀了创新。 -通过对由去中心化自治组织和 Web3 开发的不同激励模型进行广泛试验,Web3 有可能打破这一不合理的资金模式。 [可溯源的公益资助](https://medium.com/ethereum-optimism/retroactive-public-goods-funding-33c9b7d00f0c)、[二次方融资](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2003531)、[去中心化自治组织治理](https://www.antler.co/blog/daos-and-web3-governance-the-promise-implications-and-challenges-ahead)和[代币化的激励结构](https://cdixon.org/2017/05/27/crypto-tokens-a-breakthrough-in-open-network-design)是一些可以彻底改变科学资助的 Web3 工具。 +通过对由去中心化自治组织和 Web3 开发的不同激励模型进行广泛试验,Web3 有可能打破这一不合理的资金模式。 [追溯性公共物品募资](https://medium.com/ethereum-optimism/retroactive-public-goods-funding-33c9b7d00f0c)、[二次方募资](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2003531)、[DAO 治理](https://www.antler.co/blog/daos-and-web3-governance-the-promise-implications-and-challenges-ahead)和[代币化激励结构](https://cdixon.org/2017/05/27/crypto-tokens-a-breakthrough-in-open-network-design)都是 Web3 工具,可以彻底改变科学募资。 ### 知识产权所有权和发展 {#ip-ownership} -知识产权 (IP) 是传统科学中的一个大问题:从被卡在大学里或未能在生物技术领域使用,到众所周知的难以估值。 然而,Web3 利用[非同质化代币 (NFT)](/glossary/#nft) 在数字资产(例如科学数据或文章)的所有权方面表现卓越。 +知识产权 (IP) 是传统科学中的一个大问题:从被卡在大学里或未能在生物技术领域使用,到众所周知的难以估值。 然而,Web3 使用[非同质化代币 (NFT)](/glossary/#nft) 在数字资产(如科学数据或文章)所有权方面表现得格外好。 就像非同质化代币可以将未来交易的受益转回给原创作者一样,你可以建立透明的价值归属链,以此奖励研究人员、管理机构(比如去中心化自治组织),甚至是数据收集对象。 -[知识产权-非同质化代币](https://medium.com/molecule-blog/ip-nfts-for-researchers-a-new-biomedical-funding-paradigm-91312d8d92e6)就像一把钥匙,可以打开进行中的研究实验的去中心化数据存储库,还可以插入了同质化代币和[去中心化金融](/glossary/#defi)这些金融领域(从分片化到借贷池和价值评估)。 它也允许一些原生链上实体直接在链上进行研究,比如[VitaDAO](https://www.vitadao.com/) 等去中心化自治组织。 不可转让的[“灵魂绑定”代币](https://vitalik.eth.limo/general/2022/01/26/soulbound.html)的出现,也可能在去中心化科学中发挥重要作用,它允许个人证明与其以太坊地址关联的经验和凭证。 +[IP-NFTs](https://medium.com/molecule-blog/ip-nfts-for-researchers-a-new-biomedical-funding-paradigm-91312d8d92e6) 还可以充当正在进行的研究实验的去中心化数据存储库的密钥,并接入 NFT 和 [DeFi](/glossary/#defi) 金融化(从碎片化到借贷池和价值评估)。 它还允许像 [VitaDAO](https://www.vitadao.com/) 这样的原生链上实体(例如 DAO)直接在链上进行研究。 +不可转让的[“灵魂绑定”代币](https://vitalik.eth.limo/general/2022/01/26/soulbound.html)的出现也可能在 DeSci 中发挥重要作用,它允许个人证明与其以太坊地址相关联的经验和凭证。 ### 数据存储、访问和架构 {#data-storage} 使用 Web3 模式能够更容易地获取科学数据,同时分布式存储也能让研究在灾难性事件中幸存。 -起点必须是这样的一个系统:它可以被任何持有正确的可核验凭证的去中心化身份访问。 这确保敏感数据只能被信任方安全复制,从而让数据得到冗余、抵抗审查、复现结果,甚至提供多方合作和向数据集添加新数据的能力。 类似于[计算机到数据](https://7wdata.be/predictive-analytics/compute-to-data-using-blockchain-to-decentralize-data-science-and-ai-with-the-ocean-protocol)的机密计算方法,提供了另外一种原始数据复制的访问机制,给大多数敏感数据创造了一个可信的研究环境。 可信的研究环境已经[被英国国民医疗服务系统所引用](https://medium.com/weavechain/whats-in-store-for-the-future-of-healthcare-data-b6398745fbbb)。作为一种面向未来的数据隐私与合作的解决方案,这种环境通过创造良好的生态系统,使用标准化的环境来共享代码和实践,让研究者安全地使用数据。 +起点必须是这样的一个系统:它可以被任何持有正确的可核验凭证的去中心化身份访问。 这确保敏感数据只能被信任方安全复制,从而让数据得到冗余、抵抗审查、复现结果,甚至提供多方合作和向数据集添加新数据的能力。 [计算到数据](https://7wdata.be/predictive-analytics/compute-to-data-using-blockchain-to-decentralize-data-science-and-ai-with-the-ocean-protocol)等机密计算方法为原始数据复制提供了替代访问机制,为最敏感的数据创建了可信研究环境。 可信研究环境已[被英国国家医疗服务体系 (NHS) 引用](https://medium.com/weavechain/whats-in-store-for-the-future-of-healthcare-data-b6398745fbbb),被视为一种面向未来的数据隐私和协作解决方案,它通过创建一个生态系统,让研究人员可以使用标准化的环境共享代码和实践,从而在现场安全地处理数据。 灵活的 Web3 数据解决方案支持上述场景,也为真正开放的科学奠定基础。研究者在 Web3 中可以创造公共利益,无需访问权限和费用。 Web3 的公共数据解决方案,比如星际文件系统、Arweave和菲乐币,也专门为去中心化做了优化。 例如 dClimate,让所有人获取气候和天气数据,包括来自气象站和气候预测模型的数据。 @@ -90,48 +91,49 @@ summaryPoint3: 它以开放科学运动为基础。 探索项目并加入去中心化科学社区。 -- [DeSci.Global:全球事件和会议日历](https://desci.global) -- [科学电报区块链](https://t.me/BlockchainForScience) -- [Molecule:资助和为你的研究项目筹资](https://www.molecule.xyz/) -- [VitaDAO:通过赞助的研究协议获取资金用于长寿研究](https://www.vitadao.com/) -- [ResearchHub:发表科学成果及与同行对话](https://www.researchhub.com/) -- [dClimate 应用程序接口:查询由去中心化社区收集的气候数据](https://www.dclimate.net/) -- [去中心化科学基金:去中心化出版工具构建者](https://descifoundation.org/) -- [DeSci.World:用户浏览和参与去中心化科学的一站式商店](https://desci.world) -- [OceanDAO:由去中心化自治组织管理的数据相关科学的拨款](https://oceanprotocol.com/) +- [DeSci.Global:全球活动和聚会日历](https://desci.global) +- [科学区块链电报群](https://t.me/BlockchainForScience) +- [Molecule:资助你的研究项目或为其筹集资金](https://www.molecule.xyz/) +- [VitaDAO:通过赞助研究协议为长寿研究获得资金](https://www.vitadao.com/) +- [ResearchHub:发布科学成果并与同行交流](https://www.researchhub.com/) +- [dClimate API:查询由去中心化社区收集的气候数据](https://www.dclimate.net/) +- [DeSci 基金会:DeSci 出版工具构建者](https://descifoundation.org/) +- [DeSci.World:供用户查看和参与去中心化科学的一站式平台](https://desci.world) +- [OceanDAO:由 DAO 治理的、面向数据相关科学的资金](https://oceanprotocol.com/) - [Opscientia:开放的去中心化科学工作流程](https://opsci.io/research/) -- [Bio.xyz:为给你的生物技术去中心化自治组织或去中心化科学项目筹资](https://www.bio.xyz/) -- [Fleming Protocol:推动协作式生物医学发现的开源数据经济](http://flemingprotocol.io/) -- [Active Inference Institute](https://www.activeinference.org/) -- [IdeaMarkets:实现去中心化科学的诚信](https://ideamarket.io/) -- [DeSci Labs](https://www.desci.com/) -- [ValleyDAO:一个开放的全球化社区,为合成生物学研究提供资金和转译支持](https://www.valleydao.bio) -- [Cerebrum DAO:寻找和培育促进大脑健康和避免神经变性的解决方案](https://www.cerebrumdao.com/) -- [CryoDAO:资助低温保存领域的登月研究](https://www.cryodao.org) - -我们欢迎提出新项目加入到列表中 - 开始前,请查看我们的[上架政策](/contributing/adding-desci-projects/)! - -## 延伸阅读 {#further-reading} - -- [DeSci Wiki 由 Jocelynn Pearl 和 Ultrarare 提供](https://docs.google.com/document/d/1aQC6zn-eXflSmpts0XGE7CawbUEHwnL6o-OFXO52PTc/edit#) -- [由 Jocelynn Pearl 为 a16z 自建媒体网站 Future 写的一份去中心化生物技术指南](https://future.a16z.com/a-guide-to-decentralized-biotech/) -- [去中心化科学实例](https://gitcoin.co/blog/desci-the-case-for-decentralised-science/) -- [去中心化科学指南](https://future.com/what-is-decentralized-science-aka-desci/) +- [Bio.xyz:为你的生物技术 DAO 或 DeSci 项目获得资金](https://www.bio.xyz/) +- [Fleming Protocol:促进协作性生物医学发现的开源数据经济](http://flemingprotocol.io/) +- [主动推理研究所](https://www.activeinference.org/) +- [IdeaMarkets:实现去中心化科学信誉](https://ideamarket.io/) +- [DeSci 实验室](https://www.desci.com/) +- [ValleyDAO:一个为合成生物学研究提供资金和转化支持的开放性全球社区](https://www.valleydao.bio) +- [Cerebrum DAO:寻找和培育解决方案,以促进大脑健康和预防神经退行性病变](https://www.cerebrumdao.com/) +- [CryoDAO:资助人体冷冻领域的“登月”研究](https://www.cryodao.org) +- [Elata:对精神科药物的未来发表意见](https://www.elata.bio/) + +我们欢迎大家推荐要列出的新项目——请查看我们的[收录政策](/contributing/adding-desci-projects/)以开始! + +## 扩展阅读{#further-reading} + +- [DeSci Wiki,作者 Jocelynn Pearl 和 Ultrarare](https://docs.google.com/document/d/1aQC6zn-eXflSmpts0XGE7CawbUEHwnL6o-OFXO52PTc/edit#) +- [Jocelynn Pearl 为 a16z future 撰写的去中心化生物技术指南](https://future.a16z.com/a-guide-to-decentralized-biotech/) +- [DeSci 的理由](https://gitcoin.co/blog/desci-the-case-for-decentralised-science/) +- [DeSci 指南](https://future.com/what-is-decentralized-science-aka-desci/) - [去中心化科学资源](https://www.vincentweisser.com/desci) -- [Molecule 的生物制药知识产权-非同质化代币 - 技术描述](https://www.molecule.xyz/blog/molecules-biopharma-ip-nfts-a-technical-description) -- [Jon Starr 的《构建去信任科学系统》](https://medium.com/@jringo/building-systems-of-trustless-science-1cd2d072f673) -- [Paul Kohlhaas - 去中心化科学:去中心化科学的未来(播客)](https://anchor.fm/andrew-steinwold/episodes/Paul-Kohlhaas---DeSci-The-Future-of-Decentralized-Science---Zima-Red-ep-117-e1h683a) -- [去中心化科学的主动推理本体论:从情境意义建构到认知共享](https://zenodo.org/record/6320575) -- [Samuel Akinosho 的《去中心化科学:研究的未来》](https://lucidsamuel.medium.com/desci-the-future-of-research-b76cfc88c8ec) -- [Nadia 的《科学基金(结语:去中心化科学和新的加密原语)》](https://nadia.xyz/science-funding) +- [Molecule 的生物制药 IP-NFT——技术说明](https://www.molecule.xyz/blog/molecules-biopharma-ip-nfts-a-technical-description) +- [Jon Starr 撰写的“构建免信任科学系统”](https://medium.com/@jringo/building-systems-of-trustless-science-1cd2d072f673) +- [Paul Kohlhaas - DeSci:去中心化科学的未来(播客)](https://anchor.fm/andrew-steinwold/episodes/Paul-Kohlhaas---DeSci-The-Future-of-Decentralized-Science---Zima-Red-ep-117-e1h683a) +- [去中心化科学的主动推理本体论:从情境化意义建构到认知共享](https://zenodo.org/record/6320575) +- [Samuel Akinosho 撰写的“DeSci:研究的未来”](https://lucidsamuel.medium.com/desci-the-future-of-research-b76cfc88c8ec) +- [Nadia 撰写的“科学募资”(结语:DeSci 和新的加密原语)](https://nadia.xyz/science-funding) - [去中心化正在颠覆药物开发](https://medium.com/id-theory/decentralisation-is-disrupting-drug-development-28b5ba5d447f) -- [什么是去中心化科学 (DeSci)?](https://usadailytimes.com/2022/09/12/what-is-desci-decentralized-science/) +- [什么是 DeSci——去中心化科学?](https://usadailytimes.com/2022/09/12/what-is-desci-decentralized-science/) -### 相关视频 {#videos} +### 视频 {#videos} - [什么是去中心化科学?](https://www.youtube.com/watch?v=-DeMklVWNdA) -- [Vitalik Buterin 和科学家 Aubrey de Grey 之间关于长寿研究和加密技术的交集的对话](https://www.youtube.com/watch?v=x9TSJK1widA) -- [科学出版业存在不合理现象。 Web3 能解决这个问题吗?](https://www.youtube.com/watch?v=WkvzYgCvWj8) -- [Juan Benet - 去中心化科学、独立实验室以及大规模数据科学](https://www.youtube.com/watch?v=zkXM9H90g_E) -- [Sebastian Brunemeier - 去中心化科学如何改变生物医学研究和风险资本](https://www.youtube.com/watch?v=qB4Tc3FcVbM) -- [Paige Donner - 使用 Web3 和区块链打造开放科学的工具](https://www.youtube.com/watch?v=nC-2QWQ-lgw&t=17s) +- [Vitalik Buterin 与科学家 Aubrey de Grey 关于长寿研究和加密技术交叉点的对话](https://www.youtube.com/watch?v=x9TSJK1widA) +- [科学出版已然崩坏。](https://www.youtube.com/watch?v=WkvzYgCvWj8) Web3 能修复它吗?](https://www.youtube.com/watch?v=WkvzYgCvWj8) +- [Juan Benet - DeSci、独立实验室和大规模数据科学](https://www.youtube.com/watch?v=zkXM9H90g_E) +- [Sebastian Brunemeier - DeSci 如何改变生物医学研究和风险投资](https://www.youtube.com/watch?v=qB4Tc3FcVbM) +- [Paige Donner - 用 Web3 和区块链为开放科学赋能](https://www.youtube.com/watch?v=nC-2QWQ-lgw&t=17s) diff --git a/public/content/translations/zh/developers/docs/accounts/index.md b/public/content/translations/zh/developers/docs/accounts/index.md index 85bab19bd78..62c534731e7 100644 --- a/public/content/translations/zh/developers/docs/accounts/index.md +++ b/public/content/translations/zh/developers/docs/accounts/index.md @@ -1,21 +1,21 @@ --- -title: 以太坊帐户 -description: 对 以太坊帐户的解释--它们的数据结构以及它们与密钥对密码学的关系。 +title: "以太坊帐户" +description: "对 以太坊帐户的解释--它们的数据结构以及它们与密钥对密码学的关系。" lang: zh --- -一个以太坊帐户是一个具有以太币 (ETH) 余额的实体,可以在以太坊上发送交易。 帐户可以由用户控制,也可以作为智能合约部署。 +以太坊帐户是拥有以太币 (ETH) 余额,能够在以太坊网络上发送消息的实体。 帐户可以由用户控制,也可以作为智能合约部署。 ## 前提条件 {#prerequisites} -为了帮助你更好地理解这个页面,我们建议你首先阅读我们的[以太坊简介](/developers/docs/intro-to-ethereum/)。 +为了帮助你更好地理解本页内容,我们建议你先阅读我们的[以太坊简介](/developers/docs/intro-to-ethereum/)。 -## 帐户类型 {#types-of-account} +## 账户类型 {#types-of-account} 以太坊有两种帐户类型: - 外部所有的帐户 (EOA) – 由任何拥有私钥的人控制 -- 合约帐户 – 部署到网络上的智能合约,由代码控制。 了解[智能合约](/developers/docs/smart-contracts/)。 +- 合约帐户 – 部署到网络上的智能合约,由代码控制。 了解[智能合约](/developers/docs/smart-contracts/) 这两种帐户类型都能: @@ -24,7 +24,7 @@ lang: zh ### 主要区别 {#key-differences} -**外部持有** +**外部所有的** - 创建帐户是免费的 - 可以发起交易 @@ -34,22 +34,23 @@ lang: zh **合约** - 创建合约存在成本,因为需要使用网络存储空间 -- 只能在收到交易时发送交易 +- 仅能在收到交易后发送消息 - 从外部帐户向合约帐户发起的交易能触发可执行多种操作的代码,例如转移代币甚至创建新合约 - 合约帐户没有私钥。 相反,它们由智能合约代码逻辑控制 -## 理解帐户 {#an-account-examined} +## 账户剖析 {#an-account-examined} 以太坊帐户有四个字段: -- `nonce` - 一个计数器,用来显示外部帐户发送的交易数量或合约帐户创建的合约数量。 每个帐户只能执行具有一个给定随机数的一笔交易,以防范重放攻击,重放攻击指多次广播和重复执行已签署的交易。 -- `balance` – 这个地址拥有的 Wei 数量。 Wei 是以太币的计数单位,每个 ETH 有 1e+18 个 Wei。 -- `codeHash` - 该哈希表示以太坊虚拟机 (EVM) 上的帐户_代码_。 合约帐户具有编程的代码片段,可以执行不同的操作。 如果帐户收到消息调用,则执行此 EVM 代码。 与其他帐户字段不同,不能更改。 所有代码片段都被保存在状态数据库的相应哈希下,供后续检索。 此哈希值称为 codeHash。 对于外部所有的帐户,codeHash 字段是空字符串的哈希。 -- `storageRoot` – 有时被称为存储哈希。 Merkle Patricia trie 根节点的 256 位哈希已编码了帐户的存储内容(256 位整数值映射),并编码为 Trie,作为来自 256 的 Keccak 256 位哈希的映射位整数键,用于 RLP 编码的256位整数值。 此 Trie 对此帐户存储内容的哈希进行编码,默认情况下为空。 +- `nonce` – 一个计数器,用于表示从外部持有账户发送的交易数量,或由合约账户创建的合约数量。 每个帐户只能执行具有一个给定随机数的一笔交易,以防范重放攻击,重放攻击指多次广播和重复执行已签署的交易。 +- `balance` – 此地址拥有的 wei 数量。 Wei 是以太币的计数单位,每个 ETH 有 1e+18 个 Wei。 +- `codeHash` – 此哈希是指以太坊虚拟机 (EVM) 上某个账户的_代码_。 合约帐户具有编程的代码片段,可以执行不同的操作。 如果帐户收到消息调用,则执行此 EVM 代码。 与其他帐户字段不同,不能更改。 所有代码片段都被保存在状态数据库的相应哈希下,供后续检索。 此哈希值称为 codeHash。 对于外部所有的帐户,codeHash 字段是空字符串的哈希。 +- `storageRoot` – 有时称为存储哈希。 一个 [默克尔-帕特里夏树](/developers/docs/data-structures-and-encoding/patricia-merkle-trie/) 根节点的 256 位哈希,它对账户的存储内容(一个 256 位整数值的映射)进行编码,并作为从 256 位整数键的 Keccak-256 哈希到 RLP 编码的 256 位整数值的映射编码到树中。 此 Trie 对此帐户存储内容的哈希进行编码,默认情况下为空。 -![显示帐户组成部分的图表](./accounts.png) _示意图节选自[以太坊虚拟机图解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![显示账户构成的图表](./accounts.png) +_图表改编自 [图解以太坊 EVM](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ -## 外部持有的帐户和密钥对 {#externally-owned-accounts-and-key-pairs} +## 外部持有账户和密钥对 {#externally-owned-accounts-and-key-pairs} 帐户由一对加密密钥组成:公钥和私钥。 它们有助于证明交易实际上是由发送者签名的,并防止伪造。 你的私钥是你用来签名交易的密钥,所以它保障你对与自己帐户相关的资金进行管理。 你从未真正持有加密货币,你持有私钥 – 资金总是在以太坊的账本上。 @@ -57,7 +58,7 @@ lang: zh 如果 Alice 想要从她自己的帐户发送 ETH 到 Bob 的帐户,Alice 需要创建交易请求并将其发送到网络进行验证。 以太坊对公钥加密的使用确保了 Alice 可以证明她最初发起了交易请求。 没有加密机制,恶意对手 Eve 可以简单地公开广播一个看起来像“从 Alice 的帐户发送 5 ETH 到 Eve 帐户”的请求。而且没有人能够证实请求不是由 Alice 发送。 -## 帐户创建 {#account-creation} +## 账户创建 {#account-creation} 当你想要创建一个帐户时,大多数程序库会生成一个随机私钥。 @@ -67,36 +68,36 @@ lang: zh `fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036415f` -使用[椭圆曲线加密法](https://wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)从私钥生成公钥。 通过获取公钥 Keccak-256 哈希的最后 20 个字节并校验码前面添加 `0x`,可以为帐户获取公共地址。 +公钥是使用[椭圆曲线数字签名算法](https://wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)通过私钥生成的。 提取公钥 Keccak-256 哈希的最后 20 个字节,并在开头添加 `0x`,即可获得账户的公共地址。 -这意味着外部帐户 (EOA) 有一个 42 字符的地址( 20 字节区块,即 40 个十六进制字符,加上 `0x` 前缀)。 +这意味着外部持有账户 (EOA) 有一个 42 个字符的地址(一个 20 字节的段,即 40 个十六进制字符,再加上 `0x` 前缀)。 例如: `0x5e97870f263700f46aa00d967821199b9bc5a120` -下面的示例显示如何使用一种名为 [Clef](https://geth.ethereum.org/docs/tools/clef/introduction) 的签名工具生成一个新帐户。 Clef 是一个集成在以太坊客户端 [Geth](https://geth.ethereum.org) 中的帐户管理和签名工具。 `clef newaccount` 命令创建一个新的密钥对并保存在加密的密钥库中。 +以下示例显示了如何使用名为 [Clef](https://geth.ethereum.org/docs/tools/clef/introduction) 的签名工具来生成新账户。 Clef 是一款账户管理和签名工具,与以太坊客户端 [Geth](https://geth.ethereum.org) 捆绑提供。 `clef newaccount` 命令会创建一个新的密钥对,并将其保存在一个加密的密钥库中。 ``` -> clef newaccount --keystore +> clef newaccount --keystore <路径> -Please enter a password for the new account to be created: -> +请输入要创建的新账户的密码: +> <密码> ------------ -INFO [10-28|16:19:09.156] Your new key was generated address=0x5e97870f263700f46aa00d967821199b9bc5a120 -WARN [10-28|16:19:09.306] Please backup your key file path=/home/user/go-ethereum/data/keystore/UTC--2022-10-28T15-19-08.000825927Z--5e97870f263700f46aa00d967821199b9bc5a120 -WARN [10-28|16:19:09.306] Please remember your password! -生成帐户 0x5e97870f263700f46aa00d967821199b9bc5a120 +INFO [10-28|16:19:09.156] 您的新密钥已生成 address=0x5e97870f263700f46aa00d967821199b9bc5a120 +WARN [10-28|16:19:09.306] 请备份您的密钥文件 path=/home/user/go-ethereum/data/keystore/UTC--2022-10-28T15-19-08.000825927Z--5e97870f263700f46aa00d967821199b9bc5a120 +WARN [10-28|16:19:09.306] 请记住您的密码! +已生成账户 0x5e97870f263700f46aa00d967821199b9bc5a120 ``` -[Geth 相关文档](https://geth.ethereum.org/docs) +[Geth 文档](https://geth.ethereum.org/docs) -可以通过你的私钥获取公钥,但你不能通过公钥获取私钥。 确保私钥的安全性,以及顾名思义,**私密性**,至关重要。 +可以通过你的私钥获取公钥,但你不能通过公钥获取私钥。 保护好私钥的安全至关重要,并且顾名思义,一定要保持**私密**。 你需要一个私钥来签署消息和交易并输出签名。 然后其他人可以使用签名获取你的公钥,证明信息的作者。 在你的应用程序中,你可以使用 JavaScript 程序库向网络发送交易。 -## 合约帐户 {#contract-accounts} +## 合约账户 {#contract-accounts} 合约帐户也有一个 42 个字符组成的十六进制地址: @@ -110,13 +111,13 @@ WARN [10-28|16:19:09.306] Please remember your password! 以太坊还有一另种类型的密钥,它们是在以太坊从工作量证明过渡到权益证明共识时引入的。 它们是“BLS”密钥,用来识别验证者。 这些密钥可以有效地聚合,减少网络达成共识所需要的带宽。 没有这种密钥集合,验证者的最小质押金额将会高出许多。 -[更多关于验证者密钥的信息](/developers/docs/consensus-mechanisms/pos/keys/)。 +[关于验证者密钥的更多信息](/developers/docs/consensus-mechanisms/pos/keys/)。 ## 关于钱包的说明 {#a-note-on-wallets} 帐户和钱包不同。 钱包是一个界面或应用程序,可让你与以太坊帐户(外部帐户或合约帐户)进行交互。 -## 视频演示 {#a-visual-demo} +## 可视化演示 {#a-visual-demo} 跟随 Austin 了解哈希函数和密钥对。 @@ -124,13 +125,13 @@ WARN [10-28|16:19:09.306] Please remember your password! -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [了解以太坊帐户](https://info.etherscan.com/understanding-ethereum-accounts/) - etherscan +- [了解以太坊账户](https://info.etherscan.com/understanding-ethereum-accounts/) - Etherscan -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [智能合约](/developers/docs/smart-contracts/) - [交易](/developers/docs/transactions/) diff --git a/public/content/translations/zh/developers/docs/apis/backend/index.md b/public/content/translations/zh/developers/docs/apis/backend/index.md index abf79b3467f..c1e1a9ab72f 100644 --- a/public/content/translations/zh/developers/docs/apis/backend/index.md +++ b/public/content/translations/zh/developers/docs/apis/backend/index.md @@ -1,31 +1,31 @@ --- -title: 后端应用程序接口库 -description: 以太坊客户端应用程序接口的介绍,使你能够从你的应用程序中与区块链进行交互。 +title: "后端应用程序接口库" +description: "以太坊客户端应用程序接口的介绍,使你能够从你的应用程序中与区块链进行交互。" lang: zh --- -为了使软件应用程序能够与以太坊区块链进行交互(例如:读取区块链数据或发送交易信息到网络),软件必须连接到以太坊节点。 +软件应用程序要与以太坊区块链交互(即读取区块链数据和/或向网络发送交易),就必须连接到以太坊节点。 -为此,每个以太坊客户端都执行[JSON-RPC](/developers/docs/apis/json-rpc/)规范,以使应用程序可以依赖统一的[方法](/developers/docs/apis/json-rpc/#json-rpc-methods)集。 +为此,每个以太坊客户端都实现了 [JSON-RPC](/developers/docs/apis/json-rpc/) 规范,因此提供了一套统一的[方法](/developers/docs/apis/json-rpc/#json-rpc-methods),可供应用程序依赖。 -如果你想使用特定的编程语言去连接以太坊的节点,你可自行选择,但是在社区中已有几个方便的库,可以更方便地实现应用程序与以太坊的连接。 通过这些库,开发者可以方便地写下直观的一行函数来初始化(后端的)JSON RPC 请求并用于与以太坊进行交互。 +如果你想使用特定的编程语言去连接以太坊的节点,你可自行选择,但是在社区中已有几个方便的库,可以更方便地实现应用程序与以太坊的连接。 借助这些程序库,开发者可以编写直观的单行方法来初始化与以太坊交互的 JSON-RPC 请求(在后台运行)。 -## 前置要求 {#prerequisites} +## 前提条件 {#prerequisites} -了解[以太坊堆栈](/developers/docs/ethereum-stack/)和[以太坊客户端](/developers/docs/nodes-and-clients/)可能会对你有所帮助。 +了解[以太坊技术堆栈](/developers/docs/ethereum-stack/)和[以太坊客户端](/developers/docs/nodes-and-clients/)可能会有所帮助。 ## 为什么要使用库? {#why-use-a-library} -这些库降低了与一个以太坊节点交互的复杂性。 它们还提供实用的函数(例如:将 ETH 转化为 Gwei),而作为开发者,你可以花费更少的时间来处理以太坊客户端的复杂问题,从而将更多的时间集中于处理你的应用程序的独特功能。 +这些库降低了与一个以太坊节点直接交互的复杂性。 它们还提供实用功能(例如,将 ETH 转换为 Gwei),这样,作为开发者,你就可以花更少的时间处理以太坊客户端的复杂性,而将更多时间专注于应用程序的独特功能。 -## 可用的库 {#available-libraries} +## 可用程序库 {#available-libraries} ### 基础设施和节点服务 {#infrastructure-and-node-services} -**Alchemy -** **_以太坊开发平台_** +**Alchemy -** **_以太坊开发平台。_** - [alchemy.com](https://www.alchemy.com/) -- [相关文档](https://docs.alchemy.com/) +- [相关文档](https://www.alchemy.com/docs/) - [GitHub](https://github.com/alchemyplatform) - [Discord](https://discord.com/invite/alchemyplatform) @@ -35,11 +35,11 @@ lang: zh - [相关文档](https://docs.allthatnode.com) - [Discord](https://discord.gg/GmcdVEUbJM) -**Blast by Bware Labs -** **_面向以太坊主网和测试网的去中心化应用程序接口。_** +**Bware Labs 的 Blast -** **_适用于以太坊主网和测试网的去中心化应用程序接口。_** - [blastapi.io](https://blastapi.io/) - [相关文档](https://docs.blastapi.io) -- [Discord](https://discord.gg/bwarelabs) +- [Discord](https://discord.gg/SaRqmRUjjQ) **BlockPi -** **_提供更高效、更快速的 RPC 服务_** @@ -48,17 +48,22 @@ lang: zh - [GitHub](https://github.com/BlockPILabs) - [Discord](https://discord.com/invite/xTvGVrGVZv) -**Cloudflare 以太坊网关。** +**Cloudflare 以太坊网关.** - [cloudflare-eth.com](https://www.cloudflare.com/application-services/products/web3/) **Etherscan - 区块浏览器和交易应用程序接口** + - [相关文档](https://docs.etherscan.io/) -**GetBlock -** **_ 用于 Web3 开发的区块链即服务_** +**Blockscout - 开源区块浏览器** + +- [相关文档](https://docs.blockscout.com/) + +**GetBlock-** **_适用于 Web3 开发的区块链即服务_** - [GetBlock.io](https://getblock.io/) -- [相关文档](https://getblock.io/docs/) +- [相关文档](https://docs.getblock.io/) **Infura -** **_以太坊应用程序接口即服务。_** @@ -66,15 +71,15 @@ lang: zh - [相关文档](https://docs.infura.io/api) - [GitHub](https://github.com/INFURA) -**Node RPC - _经济高效的以太坊虚拟机 JSON-RPC 供应商_** +**Node RPC - _经济高效的 EVM JSON-RPC 提供商_** - [noderpc.xyz](https://www.noderpc.xyz/) - [相关文档](https://docs.noderpc.xyz/node-rpc) -**NOWNodes - _全节点和全区块浏览器。_** +**NOWNodes - _全节点和区块浏览器。_** - [NOWNodes.io](https://nownodes.io/) -- [相关文档](https://documenter.getpostman.com/view/13630829/TVmFkLwy#intro) +- [相关文档](https://nownodes.gitbook.io/documentation) **QuickNode -** **_区块链基础设施即服务。_** @@ -88,7 +93,7 @@ lang: zh - [相关文档](https://rivet.cloud/docs/) - [GitHub](https://github.com/openrelayxyz/ethercattle-deployment) -**Zmok -** **_注重速度的以太坊节点即 JSON-RPC/WebSockets 应用程序接口。_** +**Zmok -** **_高速以太坊节点,提供 JSON-RPC/WebSockets API。_** - [zmok.io](https://zmok.io/) - [GitHub](https://github.com/zmok-io) @@ -97,35 +102,35 @@ lang: zh ### 开发工具 {#development-tools} -**Ethers-kt - ****_ 面向基于以太坊虚拟机区块链的高性能异步 Kotlin/Java/Android 库。_** +**ethers-kt -** **_用于基于 EVM 的区块链的异步、高性能 Kotlin/Java/Android 库。_** - [GitHub](https://github.com/Kr1ptal/ethers-kt) - [示例](https://github.com/Kr1ptal/ethers-kt/tree/master/examples) - [Discord](https://discord.gg/rx35NzQGSb) -**Nethereum -** **_面向区块链的开源 .NET 集成库。_** +**Nethereum -** **_一个面向区块链的开源 .NET 集成库。_** - [GitHub](https://github.com/Nethereum/Nethereum) - [相关文档](http://docs.nethereum.com/en/latest/) - [Discord](https://discord.com/invite/jQPrR58FxX) -**Python 工具 -** **_通过 Python 和以太坊交互的各种库。_** +**Python 工具 -** **_通过 Python 与以太坊交互的各种程序库。_** -- [py.ethereum.org](https://python.ethereum.org/) +- [py.ethereum.org](https://snakecharmers.ethereum.org/) - [web3.py GitHub](https://github.com/ethereum/web3.py) -- [web3.py 聊天](https://gitter.im/ethereum/web3.py) +- [web3.py Chat](https://gitter.im/ethereum/web3.py) -**QuikNode -** **_终极区块链开发平台。_** +**Tatum -** **_终极区块链开发平台。_** - [Tatum](https://tatum.io/) - [GitHub](https://github.com/tatumio/) - [相关文档](https://docs.tatum.io/) - [Discord](https://discord.gg/EDmW3kjTC9) -**web3j -** **_面向以太坊的 Java/Android/Kotlin/Scala 集成库。_** +**web3j -** **_一个适用于以太坊的 Java/Android/Kotlin/Scala 集成库。_** - [GitHub](https://github.com/web3j/web3j) -- [相关文档](https://docs.web3j.io/) +- [文档](https://docs.web3j.io/) - [Gitter](https://gitter.im/web3j/web3j) ### 区块链服务 {#blockchain-services} @@ -135,29 +140,29 @@ lang: zh - [blockcypher.com](https://www.blockcypher.com/) - [相关文档](https://www.blockcypher.com/dev/ethereum/) -**公链 -** **_以太坊的一体化 web3 数据基础设施。_** +**Chainbase -** **_适用于以太坊的一体化 Web3 数据基础设施。_** - [chainbase.com](https://chainbase.com/) - [相关文档](https://docs.chainbase.com/) - [Discord](https://discord.gg/Wx6qpqz4AF) -**Chainstack -** **_共享及专用的以太坊节点即服务。_** +**Chainstack -** **_弹性且专用的以太坊节点即服务。_** - [chainstack.com](https://chainstack.com) -- [相关文档](https://docs.chainbase.com/docs) -- [以太坊应用程序接口参考](https://docs.chainstack.com/reference/ethereum-getting-started) +- [相关文档](https://docs.chainstack.com/) +- [以太坊 API 参考](https://docs.chainstack.com/reference/ethereum-getting-started) -**Coinbase 云节点 -** **_区块链基础设施应用程序接口。_** +**Coinbase Cloud Node -** **_区块链基础设施应用程序接口。_** -- [Coinbase 云节点](https://www.coinbase.com/cloud) -- [相关文档](https://docs.cloud.coinbase.com/) +- [Coinbase 云节点](https://www.coinbase.com/developer-platform) +- [相关文档](https://docs.cdp.coinbase.com/) -**Figment 数据中心 -** **_以太坊主网和测试网的 Web3 应用程序接口服务。_** +**Figment 的 DataHub -** **_支持以太坊主网和测试网的 Web3 API 服务。_** -- [数据中心](https://www.figment.io/) +- [DataHub](https://www.figment.io/) - [相关文档](https://docs.figment.io/) -**Moralis -** **_企业级以太坊虚拟机应用程序接口提供商。_** +**Moralis -** **_企业级 EVM API 提供商。_** - [moralis.io](https://moralis.io) - [相关文档](https://docs.moralis.io/) @@ -165,43 +170,42 @@ lang: zh - [Discord](https://moralis.io/joindiscord/) - [论坛](https://forum.moralis.io/) -**NFTPort -** **_以太坊数据和铸币应用程序接口。_** +**NFTPort -** **_以太坊数据和铸币 API。_** - [nftport.xyz](https://www.nftport.xyz/) - [相关文档](https://docs.nftport.xyz/) - [GitHub](https://github.com/nftport/) - [Discord](https://discord.com/invite/K8nNrEgqhE) -**Tokenview -** **_ 通用多重加密区块链应用程序接口平台。_** +**Tokenview -** **_通用多加密货币区块链 API 平台。_** - [services.tokenview.io](https://services.tokenview.io/) - [相关文档](https://services.tokenview.io/docs?type=api) - [GitHub](https://github.com/Tokenview) -**Watchdata -** **_提供对以太坊区块链简单可靠的API访问。_** +**Watchdata -** **_提供对以太坊区块链简单可靠的 API 访问。_** - [Watchdata](https://watchdata.io/) - [相关文档](https://docs.watchdata.io/) - [Discord](https://discord.com/invite/TZRJbZ6bdn) -**Covalent - ****_适用于 200 多条链的丰富区块链应用程序接口。_** +**Covalent -** **_适用于 200 多条链的丰富区块链 API。_** - [covalenthq.com](https://www.covalenthq.com/) - [相关文档](https://www.covalenthq.com/docs/api/) - [GitHub](https://github.com/covalenthq) - [Discord](https://www.covalenthq.com/discord/) +## 扩展阅读{#further-reading} -## 延伸阅读 {#further-reading} - -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [节点和客户端](/developers/docs/nodes-and-clients/) - [开发框架](/developers/docs/frameworks/) ## 相关教程 {#related-tutorials} -- [设置 Web3js 以在 JavaScript 中使用以太坊区块链](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/) _– 在项目中设置 web3.js 的说明。_ -- [在 JavaScript 中调用智能合约](/developers/tutorials/calling-a-smart-contract-from-javascript/) _使用 DAI 代币,从而借助 JavaScript 调用合约函数。_ +- [设置 Web3.js 以在 JavaScript 中使用以太坊区块链](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/) _– 在项目中设置 web3.js 的说明。_ +- [从 JavaScript 调用智能合约](/developers/tutorials/calling-a-smart-contract-from-javascript/) _– 使用 DAI 代币,了解如何用 JavaScript 调用合约函数。_ diff --git a/public/content/translations/zh/developers/docs/apis/javascript/index.md b/public/content/translations/zh/developers/docs/apis/javascript/index.md index 8f05b3859d3..1fdf22c6274 100644 --- a/public/content/translations/zh/developers/docs/apis/javascript/index.md +++ b/public/content/translations/zh/developers/docs/apis/javascript/index.md @@ -1,24 +1,24 @@ --- -title: JavaScript 应用编程接口库 -description: 以太坊 JavaScript 应用程序接口的介绍,使你能够从你的应用程序中与区块链进行交互。 +title: "JavaScript 应用编程接口库" +description: "以太坊 JavaScript 应用程序接口的介绍,使你能够从你的应用程序中与区块链进行交互。" lang: zh --- -为了使网页应用程序能够与以太坊区块链进行交互(例如:读取区块链数据或发送交易信息到网络),软件必须连接到以太坊节点。 +为了让 Web 应用程序能与以太坊区块链交互(即读取区块链数据和/或向网络发送交易),它必须连接到一个以太坊节点。 -为此,每种以太坊客户端都实现了 [JSON-RPC](/developers/docs/apis/json-rpc/) 规范,因而应用程序可以依赖一组统一的[方法](/developers/docs/apis/json-rpc/#json-rpc-methods)。 +为此,每个以太坊客户端都实现了 [JSON-RPC](/developers/docs/apis/json-rpc/) 规范,因此有一套统一的[方法](/developers/docs/apis/json-rpc/#json-rpc-methods)可供应用程序依赖。 -如果你想要用 JavaScript 连接到一个以太坊节点, 可以使用原生 JavaScript,不过生态系统中存在一些方便的库,使得这个事情变得更加容易。 通过这些库,开发者可以方便地写下直观的一行函数来初始化(后端的)JSON RPC 请求并用于与以太坊进行交互。 +如果你想要用 JavaScript 连接到一个以太坊节点, 可以使用原生 JavaScript,不过生态系统中存在一些方便的库,使得这个事情变得更加容易。 借助这些程序库,开发者可以编写直观的单行方法来初始化与以太坊交互的 JSON-RPC 请求(在后台运行)。 -请注意,[合并](/roadmap/merge/)后,运行节点需要两种互联的以太坊软件 - 执行客户端和共识客户端。 请确保你的节点同时包含执行客户端和共识客户端。 如果你的节点不在本地计算机上(例如,你的节点在 AWS 实例上运行),请相应地更新教程中的 IP 地址。 有关更多信息,请参阅我们关于[运行节点](/developers/docs/nodes-and-clients/run-a-node/)的页面。 +请注意,自[合并](/roadmap/merge/)后,运行一个节点需要两个相互连接的以太坊软件:一个执行客户端和一个共识客户端。 请确保你的节点同时包含执行客户端和共识客户端。 如果你的节点不在本地计算机上(例如,你的节点在 AWS 实例上运行),请相应地更新教程中的 IP 地址。 欲了解更多信息,请参阅我们关于[运行节点](/developers/docs/nodes-and-clients/run-a-node/)的页面。 ## 前提条件 {#prerequisites} -除了了解 JavaScript 外,了解[以太坊堆栈](/developers/docs/ethereum-stack/)和[以太坊客户端](/developers/docs/nodes-and-clients/)也许是有帮助的。 +除了理解 JavaScript,了解[以太坊技术栈](/developers/docs/ethereum-stack/)和[以太坊客户端](/developers/docs/nodes-and-clients/)也可能对您有帮助。 ## 为什么要使用库? {#why-use-a-library} -这些库降低了与一个以太坊节点直接交互的复杂性。 它们还提供实用功能(例如:将以太币转换为 Gwei),因此作为开发者,你可以花费更少的时间处理以太坊客户端的复杂问题,而将更多的时间集中于处理应用程序的独特功能。 +这些库降低了与一个以太坊节点直接交互的复杂性。 它们还提供实用功能(例如,将 ETH 转换为 Gwei),这样,作为开发者,你就可以花更少的时间处理以太坊客户端的复杂性,而将更多时间专注于应用程序的独特功能。 ## 库功能 {#library-features} @@ -26,15 +26,17 @@ lang: zh 使用提供程序,这些库允许你连接到以太坊并读取它的数据,不管是通过 JSON-RPC、INFURA、Etherscan、Alchemy 还是 Metamask。 +> \*\*警告:\*\*Web3.js 已于 2025 年 3 月 4 日归档。 [阅读公告](https://blog.chainsafe.io/web3-js-sunset/)。 对于新项目,请考虑使用 [ethers.js](https://ethers.org) 或 [viem](https://viem.sh) 等替代库。 + **Ethers 示例** ```js -// 一个浏览器提供程序包装了一个标准 Web3 提供程序,后者由 -// MetaMask 作为 window.ethereum 注入每个页面 +// BrowserProvider 封装了一个标准的 Web3 提供程序, +// MetaMask 将其作为 window.ethereum 注入每个页面 const provider = new ethers.BrowserProvider(window.ethereum) -// MetaMask 插件还允许为交易签名, -// 以发送以太币并付款改变区块链内的状态。 +// MetaMask 插件还允许对交易进行签名, +// 以便发送以太币和支付费用来改变区块链内的状态。 // 为此,我们需要帐户签名者... const signer = provider.getSigner() ``` @@ -77,22 +79,22 @@ var web3 = new Web3( 这里提供了 Ethers 中的一个示例 ```js -// 从助记符创建一个钱包实例... +// 从助记词创建钱包实例… mnemonic = "announce room limb pattern dry unit scale effort smooth jazz weasel alcohol" walletMnemonic = Wallet.fromPhrase(mnemonic) -// ...或者来自一个私钥 +// ……或从私钥创建 walletPrivateKey = new Wallet(walletMnemonic.privateKey) walletMnemonic.address === walletPrivateKey.address // true -// 根据签名者应用程序接口,该地址为 Promise +// 根据签名者 API,地址是一个 Promise walletMnemonic.getAddress() // { Promise: '0x71CB05EE1b1F506fF321Da3dac38f25c0c9ce6E1' } -// 钱包地址也可同步使用 +// 钱包地址也可同步获得 walletMnemonic.address // '0x71CB05EE1b1F506fF321Da3dac38f25c0c9ce6E1' @@ -110,12 +112,12 @@ walletMnemonic.mnemonic // phrase: 'announce room limb pattern dry unit scale effort smooth jazz weasel alcohol' // } -// 注意:使用私钥创建的钱包 -// 没有助记词(派生阻止了它) +// 注意:用私钥创建的钱包 +// 没有助记词(派生过程阻止了它) walletPrivateKey.mnemonic // null -// 为信息签名 +// 签署消息 walletMnemonic.signMessage("Hello World") // { Promise: '0x14280e5885a19f60e536de50097e96e3738c7acae4e9e62d67272d794b8127d31c03d9cd59781d4ee31fb4e1b893bd9b020ec67dfa65cfb51e2bdadbb1de26d91c' } @@ -124,12 +126,12 @@ tx = { value: utils.parseEther("1.0"), } -// 为交易签名 +// 签署交易 walletMnemonic.signTransaction(tx) // { Promise: '0xf865808080948ba1f109551bd432803012645ac136ddd64dba72880de0b6b3a7640000801ca0918e294306d177ab7bd664f5e141436563854ebe0a3e523b9690b4922bbb52b8a01181612cec9c431c4257a79b8c9f0c980a2c49bb5a0e6ac52949163eeb565dfc' } -// connect 方法返回连接到提供程序 -// 的 Wallet 的新实例 +// connect 方法返回连接到 +// 提供者的新钱包实例 wallet = walletMnemonic.connect(provider) // 查询网络 @@ -151,7 +153,7 @@ wallet.sendTransaction(tx) - 签署交易 - 以及更多... -### 与智能合约交互的方法 {#interact-with-smart-contract-functions} +### 与智能合约函数交互 {#interact-with-smart-contract-functions} JavaScript 客户端库允许你的应用程序通过读取已编译合约的应用程序二进制接口 (ABI) 来调用智能合约函数。 @@ -164,7 +166,7 @@ contract Test { uint a; address d = 0x12345678901234567890123456789012; - function Test(uint testInt) { a = testInt;} + constructor(uint testInt) { a = testInt;} event Event(uint indexed b, bytes32 c); @@ -213,11 +215,11 @@ contract Test { - 部署一个合约 - 以及更多... -### 实用功能 {#utility-functions} +### 实用函数 {#utility-functions} 这些实用功能为你提供了方便的快捷操作,让以太坊的构建变得更轻松一些。 -以太币的默认价值单位是 Wei。 1 个以太币 = 1,000,000,000,000,000,000 WEI – 这意味着你需要处理很多的数字。 使用 `web3.utils.toWei` 可以将以太币转换为 Wei。 +以太币的默认价值单位是 Wei。 1 个以太币 = 1,000,000,000,000,000,000 WEI – 这意味着你需要处理很多的数字。 `web3.utils.toWei` 可将以太币转换为 Wei。 在 ethers 中,它看起来是这样的: @@ -232,59 +234,56 @@ ethers.utils.formatEther(balance) // '2.337132817842795605' ``` -- [Web3js 实用功能](https://docs.web3js.org/api/web3-utils) -- [Ethers 实用功能](https://docs.ethers.io/v5/api/utils/) +- [Web3.js 实用函数](https://docs.web3js.org/api/web3-utils) +- [Ethers.js 实用函数](https://docs.ethers.org/v6/api/utils/) -## 可用的库 {#available-libraries} +## 可用程序库 {#available-libraries} **Web3.js -** **_以太坊 JavaScript API。_** -- [相关文档](https://docs.web3js.org/) -- [GitHub](https://github.com/ethereum/web3.js/) +- [文档](https://docs.web3js.org) +- [GitHub](https://github.com/ethereum/web3.js) -**Ethers.js -** **_JavaScript 和 TypeScript 中完整的以太坊钱包实现和实用工具。_** +**Ethers.js -** **_在 JavaScript 和 TypeScript 中完整的以太坊钱包实现和实用工具。_** -- [相关文档](https://docs.ethers.io/) -- [GitHub](https://github.com/ethers-io/ethers.js/) +- [Ethers.js 主页](https://ethers.org/) +- [文档](https://docs.ethers.io) +- [GitHub](https://github.com/ethers-io/ethers.js) -**Graph -** **_用于为以太坊和星际文件系统数据建立索引并使用 GraphQL 对其进行查询的协议。_** +**The Graph -** **_一种用于索引以太坊和 IPFS 数据并使用 GraphQL 查询的协议。_** -- [图表](https://thegraph.com/) -- [Graph Explorer](https://thegraph.com/explorer/) -- [相关文档](https://thegraph.com/docs/) -- [GitHub](https://github.com/graphprotocol/) +- [The Graph](https://thegraph.com) +- [Graph浏览器](https://thegraph.com/explorer) +- [文档](https://thegraph.com/docs) +- [GitHub](https://github.com/graphprotocol) - [Discord](https://thegraph.com/discord) -**light.js -** **_针对轻客户端优化的高级响应式 JS 库。_** - -- [GitHub](https://github.com/openethereum/js-libs/tree/master/packages/light.js) - -**Alchemyweb3 -** **_Web3.js 的包装器,带自动重试和增强的应用程序接口。_** - -- [相关文档](https://docs.alchemy.com/reference/api-overview) -- [GitHub](https://github.com/alchemyplatform/alchemy-web3) +**Alchemy SDK -** **_围绕 Ethers.js 构建的、具有增强版 API 的封装器。_** -**Alchemy 非同质化代币应用程序接口 -** **_ 用于提取非同质化代币数据的应用程序接口,包括所有权、元数据属性等数据。_** - -- [相关文档](https://docs.alchemy.com/alchemy/enhanced-apis/nft-api) -- [GitHub](https://github.com/alchemyplatform/alchemy-web3) +- [文档](https://www.alchemy.com/docs) +- [GitHub](https://github.com/alchemyplatform/alchemy-sdk-js) **viem -** **_以太坊的 TypeScript 接口。_** -- [相关文档](https://viem.sh) +- [文档](https://viem.sh) - [GitHub](https://github.com/wagmi-dev/viem) -## 延伸阅读 {#further-reading} +**Drift -** **_带有内置缓存、挂钩和测试模拟功能的 TypeScript 元库。_** + +- [文档](https://ryangoree.github.io/drift/) +- [GitHub](https://github.com/ryangoree/drift/) + +## 扩展阅读{#further-reading} -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [节点和客户端](/developers/docs/nodes-and-clients/) - [开发框架](/developers/docs/frameworks/) ## 相关教程 {#related-tutorials} -- [设置 Web3js 以在 JavaScript 中使用以太坊区块链](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/) _– 在项目中设置 web3.js 的说明。_ -- [在 JavaScript 中调用智能合约](/developers/tutorials/calling-a-smart-contract-from-javascript/) _使用 DAI 代币,从而借助 JavaScript 调用合约函数。_ -- [使用 Web3 和 Alchemy 发送交易](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) _– 从后端发送交易分步指南。_ +- [设置 Web3.js 以在 JavaScript 中使用以太坊区块链](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/) _– 在项目中设置 web3.js 的说明。_ +- [从 JavaScript 调用智能合约](/developers/tutorials/calling-a-smart-contract-from-javascript/) _– 使用 DAI 代币,了解如何用 JavaScript 调用合约函数。_ +- [使用 web3 和 Alchemy 发送交易](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) _– 从后端发送交易的分步指南。_ diff --git a/public/content/translations/zh/developers/docs/apis/json-rpc/index.md b/public/content/translations/zh/developers/docs/apis/json-rpc/index.md index 0d3c4e6928f..6154e84d105 100644 --- a/public/content/translations/zh/developers/docs/apis/json-rpc/index.md +++ b/public/content/translations/zh/developers/docs/apis/json-rpc/index.md @@ -1,32 +1,32 @@ --- -title: JSON-RPC 应用程序接口 -description: 面向以太坊客户端的无状态、轻量级远程过程调用 (RPC) 协议。 +title: "JSON-RPC 应用程序接口" +description: "面向以太坊客户端的无状态、轻量级远程过程调用 (RPC) 协议。" lang: zh --- 为了让软件应用程序与以太坊区块链交互(通过读取区块链数据或向网络发送交易),它必须连接到以太坊节点。 -为此,每种[以太坊客户端](/developers/docs/nodes-and-clients/#execution-clients)均实现了 [JSON-RPC 规范](https://github.com/ethereum/execution-apis),因而应用程序可以依赖一组统一的方法,而与具体节点或客户端实现无关。 +为此,每个[以太坊客户端](/developers/docs/nodes-and-clients/#execution-clients)都会实现 [JSON-RPC 规范](https://github.com/ethereum/execution-apis),因此无论具体的节点或客户端实现如何,应用程序都可以依赖一组统一的方法。 -[JSON-RPC](https://www.jsonrpc.org/specification) 是一种无状态的、轻量级远程过程调用 (RPC) 协议。 它定义了一些数据结构及其处理规则。 它与传输无关,因为这些概念可以在同一进程,通过接口、超文本传输协议或许多不同的消息传递环境中使用。 它使用 JSON (RFC 4627) 作为数据格式。 +[JSON-RPC](https://www.jsonrpc.org/specification) 是一种无状态、轻量级的远程过程调用 (RPC) 协议。 它定义了一些数据结构及其处理规则。 它与传输无关,因为这些概念可以在同一进程,通过接口、超文本传输协议或许多不同的消息传递环境中使用。 它使用 JSON (RFC 4627) 作为数据格式。 ## 客户端实现 {#client-implementations} -每个客户端在执行 JSON-RPC 规范时可以使用不同的编程语言。 更多与特定编程语言相关的详细信息,请查阅[客户端文档](/developers/docs/nodes-and-clients/#execution-clients)。 我们建议查看每个客户端文档以获取最新的应用程序接口支持信息。 +每个客户端在执行 JSON-RPC 规范时可以使用不同的编程语言。 有关特定编程语言的更多详细信息,请参阅各个[客户端文档](/developers/docs/nodes-and-clients/#execution-clients)。 我们建议查看每个客户端文档以获取最新的应用程序接口支持信息。 -## 便利性库 {#convenience-libraries} +## 便捷程序库 {#convenience-libraries} -虽然你可以选择通过 JSON 应用程序接口直接与以太坊客户端交互,但是对于去中心化应用程序开发者来说,常常有更容易的选项。 许多 [JavaScript](/developers/docs/apis/javascript/#available-libraries) 和[后端应用程序接口](/developers/docs/apis/backend/#available-libraries)库已经存在,可以在 JSON-RPC 应用程序接口之上提供封装。 通过这些库,开发者可以用他们选择的语言写下直观的一行函数来初始化(后端的)JSON RPC 请求并用于与以太坊进行交互。 +虽然你可以选择通过 JSON 应用程序接口直接与以太坊客户端交互,但是对于去中心化应用程序开发者来说,常常有更容易的选项。 许多 [JavaScript](/developers/docs/apis/javascript/#available-libraries) 和[后端 API](/developers/docs/apis/backend/#available-libraries) 程序库都提供了 JSON-RPC API 之上的包装器。 通过这些库,开发者可以用他们选择的语言写下直观的一行函数来初始化(后端的)JSON RPC 请求并用于与以太坊进行交互。 -## 共识客户端应用程序接口 {#consensus-clients} +## 共识客户端 API {#consensus-clients} -本页主要处理以太坊执行客户端使用的 JSON-RPC 应用程序接口。 但是,共识客户端也有一个远程过程调用应用程序接口,允许用户直接从节点查询有关节点的信息、请求信标区块、信标状态和其他与共识相关的信息。 此应用程序接口记录在[信标应用程序接口网页](https://ethereum.github.io/beacon-APIs/#/)上。 +本页主要处理以太坊执行客户端使用的 JSON-RPC 应用程序接口。 但是,共识客户端也有一个远程过程调用应用程序接口,允许用户直接从节点查询有关节点的信息、请求信标区块、信标状态和其他与共识相关的信息。 此 API 记录在 [Beacon API 网页](https://ethereum.github.io/beacon-APIs/#/) 上。 -内部应用程序接口还用于节点内的客户端间通信——也就是说,它使共识客户端和执行客户端能够交换数据。 这种内部应用程序接口称为“引擎应用程序接口”,其规范见 [GitHub](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md)。 +内部应用程序接口还用于节点内的客户端间通信——也就是说,它使共识客户端和执行客户端能够交换数据。 这被称为“引擎 API”,其规范可在 [GitHub](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md) 上找到。 ## 执行客户端规范 {#spec} -[阅读 GitHub 上完整的 JSON-RPC 应用程序接口规范](https://github.com/ethereum/execution-apis)。 该应用程序接口在[执行执行应用程序接口网页](https://ethereum.github.io/execution-apis/api-documentation/)上有文档,还包含一个可试验所有可用方法的检查器。 +[在 GitHub 上阅读完整的 JSON-RPC API 规范](https://github.com/ethereum/execution-apis)。 此 API 在 [Execution API 网页](https://ethereum.github.io/execution-apis/)上有文档,还包含一个可试验所有可用方法的检查器。 ## 约定 {#conventions} @@ -46,7 +46,7 @@ lang: zh - 错误:0x0400(不允许有前导零) - 错误:ff(必须有前缀 0x) -### 无格式数据 {#unformatted-data-encoding} +### 未格式化数据 {#unformatted-data-encoding} 当对无格式数据(字节数组、帐户地址、哈希、字节码数组)进行编码时:编码为十六进制,以“0x”为前缀,每字节两个十六进制数字。 @@ -58,9 +58,9 @@ lang: zh - 错误:0xf0f0f(位数必须是偶数) - 错误:004200(必须以 0x 为前缀) -### 默认区块参数 {#default-block} +### 区块参数 {#block-parameter} -以下方法有额外的默认区块参数: +以下方法拥有区块参数: - [eth_getBalance](#eth_getbalance) - [eth_getCode](#eth_getcode) @@ -68,34 +68,34 @@ lang: zh - [eth_getStorageAt](#eth_getstorageat) - [eth_call](#eth_call) -当发出作用于以太坊状态的请求时,最后一个默认区块参数决定了区块的高度。 +当查询以太坊状态的请求被发出时,提供的区块参数决定了区块的高度。 -默认区块参数可以使用以下选项: +区块参数可以使用以下选项: - `HEX String` - 整数区块号 - `String "earliest"` - 表示最早/创世区块 - `String "latest"` - 最新提议的区块 - `String "safe"` - 最新且安全的头部区块 - `String "finalized"` - 最新的最终确定的区块 -- `String "pending"` - 未决状态/交易 +- `String "pending"` - 待处理状态/交易 ## 示例 -在此页面上,我们提供了如何通过命令行工具 [curl](https://curl.se) 使用单个 JSON_RPC 应用程序接口端点的示例。 这些单独的端点示例位于下面的 [Curl 示例](#curl-examples)部分。 在页面下方,我们还提供了一个[端到端示例](#usage-example),用于使用 Geth 节点、JSON_RPC 应用程序接口和 curl 编译和部署智能合约。 +在此页面上,我们提供了如何通过命令行工具 [curl](https://curl.se) 使用单个 JSON_RPC API 端点的示例。 这些单独的端点示例位于下面的 [Curl 示例](#curl-examples)部分。 在页面下方,我们还提供了一个端到端示例,用于使用 Geth 节点、JSON_RPC API 和 curl 编译和部署智能合约。 ## Curl 示例 {#curl-examples} -下面提供了通过向以太坊节点发出 [curl](https://curl.se) 请求来使用 JSON_RPC 应用程序接口的示例。 每个示例都包括对特定端点、其参数、返回类型的描述,以及应该如何使用它的工作示例。 +下面提供了通过向以太坊节点发出 [curl](https://curl.se) 请求来使用 JSON_RPC API 的示例。 每个示例都包括对特定端点、其参数、返回类型的描述,以及应该如何使用它的工作示例。 -Curl 请求可能会返回与内容类型相关的错误消息。 这是因为 `--data` 选项将内容类型设置为 `application/x-www-form-urlencoded`。 如果你的节点确实抱怨此问题,请通过在调用开始时放置 `-H "Content-Type: application/json"` 来手动设置标头。 这些示例也未包括网址/互联网协议与端口组合,该组合必须是 curl 的最后一个参数(例如 `127.0.0.1:8545`)。 包含这些附加数据的完整 curl 请求采用以下形式: +Curl 请求可能会返回与内容类型相关的错误消息。 这是因为 --data 选项将内容类型设置为 `application/x-www-form-urlencoded`。 如果你的节点确实抱怨此问题,请通过在调用开始时放置 `-H "Content-Type: application/json"` 来手动设置标头。 这些示例也不包括 URL/IP 和端口组合,它必须是提供给 curl 的最后一个参数(例如 `127.0.0.1:8545`)。 包含这些附加数据的完整 curl 请求采用以下形式: ```shell curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":67}' 127.0.0.1:8545 ``` -## Gossip、State、History {#gossip-state-history} +## Gossip、状态、历史 {#gossip-state-history} -少数核心 JSON-RPC 方法需要来自以太坊网络的数据,并且整齐地分为三个主要类别:_Gossip、State 和 History_。 使用这些部分中的链接跳转到每个方法,或使用目录浏览整个方法列表。 +少数核心 JSON-RPC 方法需要来自以太坊网络的数据,并可以清晰地归为三大类:_Gossip、状态和历史_。 使用这些部分中的链接跳转到每个方法,或使用目录浏览整个方法列表。 ### Gossip 方法 {#gossip-methods} @@ -104,7 +104,7 @@ curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","metho - [eth_blockNumber](#eth_blocknumber) - [eth_sendRawTransaction](#eth_sendrawtransaction) -### State 方法 {#state_methods} +### 状态方法 {#state_methods} > 用于报告所有已存储数据的当前状态的方法。 “状态”就像一大块共享内存,包括帐户余额、合约数据和燃料估算。 @@ -115,7 +115,7 @@ curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","metho - [eth_call](#eth_call) - [eth_estimateGas](#eth_estimategas) -### History 方法 {#history_methods} +### 历史方法 {#history_methods} > 将每个区块的历史记录追溯到创世块。 这就像一个大的仅附加文件,包括所有区块头、区块体、叔块和交易收据 @@ -134,9 +134,9 @@ curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","metho ## JSON-RPC 应用程序接口实战 -你可以使用[实战工具](https://ethereum-json-rpc.com)来发现与尝试应用程序接口方法。 它还为你展示了各个节点提供商支持哪些方法和网络。 +你可以使用[演练场工具](https://ethereum-json-rpc.com)来发现和试用 API 方法。 它还为你展示了各个节点提供商支持哪些方法和网络。 -## JSON-RPC 应用程序接口方法 {#json-rpc-methods} +## JSON-RPC API 方法 {#json-rpc-methods} ### web3_clientVersion {#web3_clientversion} @@ -153,9 +153,9 @@ curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","metho **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":67}' -// Result +// 结果 { "id":67, "jsonrpc":"2.0", @@ -182,9 +182,9 @@ params: ["0x68656c6c6f20776f726c64"] **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"web3_sha3","params":["0x68656c6c6f20776f726c64"],"id":64}' -// Result +// 结果 { "id":64, "jsonrpc": "2.0", @@ -202,20 +202,20 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"web3_sha3","params":["0x68656c6c **返回值** -`String` - 当前网络 id。 +`String` - 当前网络 ID。 -当前网络 ID 的完整列表可在 [chainlist.org](https://chainlist.org) 获得。 下面是部分常见网络 ID: +当前网络 ID 的完整列表可在 [chainlist.org](https://chainlist.org) 上找到。 下面是部分常见网络 ID: - `1`:以太坊主网 - `11155111`:Sepolia 测试网 -- `17000`:Hoodi 测试网 +- `560048`:Hoodi 测试网 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"net_version","params":[],"id":67}' -// Result +// 结果 { "id":67, "jsonrpc": "2.0", @@ -225,7 +225,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"net_version","params":[],"id":67 ### net_listening {#net_listening} -如果客户端正在主动监听网络连接,则返回 `true`。 +如果客户端正在主动侦听网络连接,则返回 `true`。 **参数** @@ -233,14 +233,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"net_version","params":[],"id":67 **返回值** -`Boolean` - 监听时为 `true`,否则为 `false`。 +`布尔值` - 侦听时为 `true`,否则为 `false`。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"net_listening","params":[],"id":67}' -// Result +// 结果 { "id":67, "jsonrpc":"2.0", @@ -258,14 +258,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"net_listening","params":[],"id": **返回值** -`QUANTITY` - 表示已连接的对等点数的整数。 +`QUANTITY` - 已连接对等点的整数。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id":74}' -// Result +// 结果 { "id":74, "jsonrpc": "2.0", @@ -275,7 +275,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id": ### eth_protocolVersion {#eth_protocolversion} -返回当前的以太坊协议版本。 请注意,此方法在 [Geth 中不可用](https://github.com/ethereum/go-ethereum/pull/22064#issuecomment-788682924)。 +返回当前的以太坊协议版本。 请注意,此方法[在 Geth 中不可用](https://github.com/ethereum/go-ethereum/pull/22064#issuecomment-788682924)。 **参数** @@ -288,9 +288,9 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id": **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_protocolVersion","params":[],"id":67}' -// Result +// 结果 { "id":67, "jsonrpc": "2.0", @@ -300,7 +300,11 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_protocolVersion","params":[] ### eth_syncing {#eth_syncing} -返回一个对象,其中包含有关同步状态的数据或 `false`。 +返回包含同步状态数据的对象,或者返回 `false`。 + + + 在 playground 中尝试端点 + **参数** @@ -310,11 +314,11 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_protocolVersion","params":[] 准确的返回数据因客户端实现而异。 节点未进行同步时,所有客户端返回 `False`,并且所有客户端返回以下字段。 -`Object|Boolean`,具有同步状态数据的对象,或 `FALSE`(不进行同步时): +`Object|Boolean`,一个包含同步状态数据的对象;如果未同步,则为 `FALSE`: -- `startingBlock`: `QUANTITY` - 导入开始进行的区块(只有当同步进行到其区块头时才会被重置) -- `currentBlock`: `QUANTITY` - 当前区块,同 eth_blockNumber -- `highestBlock`: `QUANTITY` - 估计的最高区块 +- `startingBlock`:`QUANTITY` - 导入开始时的区块(仅在同步达到其头部后才会重置) +- `currentBlock`:`QUANTITY` - 当前区块,与 eth_blockNumber 相同 +- `highestBlock`:`QUANTITY` - 估算的最高区块 然而,各个客户端还可能提供额外数据。 例如 Geth 返回以下字段: @@ -362,9 +366,9 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_protocolVersion","params":[] **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -374,7 +378,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1} highestBlock: '0x454' } } -// Or when not syncing +// 或者在未同步时 { "id":1, "jsonrpc": "2.0", @@ -386,7 +390,11 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1} 返回客户端的 coinbase 地址。 -> **注意:**该方法已于 **v1.14.0** 版本被弃用,并不再受支持。 试图使用该方法会触发“Method not supported(不支持该方法)”错误。 + + 在 playground 中尝试端点 + + +> \*\*注意:\*\*该方法已于 **v1.14.0** 版本被弃用,并不再受支持。 试图使用该方法会触发“Method not supported(不支持该方法)”错误。 **参数** @@ -399,9 +407,9 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1} **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_coinbase","params":[],"id":64}' -// Result +// 结果 { "id":64, "jsonrpc": "2.0", @@ -413,20 +421,24 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_coinbase","params":[],"id":6 返回链 ID,用于签署受重放攻击保护的交易。 + + 在 playground 中尝试端点 + + **参数** 无 **返回值** -`chainId`,十六进制字符串值,代表当前链 ID 的整数。 +`chainId`,十六进制字符串值,表示当前链 ID 的整数。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":67}' -// Result +// 结果 { "id":67, "jsonrpc": "2.0", @@ -438,18 +450,22 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":67 如果客户端正在积极挖掘新区块,则返回 `true`。 此方法只能在工作量证明网络中返回 `true`,并且在[合并](/roadmap/merge/)后可能无法用于某些客户端。 + + 在 playground 中尝试端点 + + **参数** 无 **返回值** -`Boolean` - 如果客户端正在挖矿,则返回 `true`,否则返回 `false`。 +`布尔值` - 如果客户端正在挖矿,则返回 `true`,否则返回 `false`。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_mining","params":[],"id":71}' // { @@ -463,20 +479,24 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_mining","params":[],"id":71} 返回节点挖矿时使用的每秒哈希数。 此方法只能在工作量证明网络中返回 `true`,并且在[合并](/roadmap/merge/)后可能无法用于某些客户端。 + + 在 playground 中尝试端点 + + **参数** 无 **返回值** -`QUANTITY` - 每秒哈希数。 +`QUANTITY` - 每秒的哈希数。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_hashrate","params":[],"id":71}' -// Result +// 结果 { "id":71, "jsonrpc": "2.0", @@ -488,20 +508,24 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_hashrate","params":[],"id":7 返回当前燃料价格的估计值,以 wei 为单位。 例如,Besu 客户端检查最后 100 个区块,并默认返回燃料单价中位数。 + + 在 playground 中尝试端点 + + **参数** 无 **返回值** -`QUANTITY` - 表示当前燃料价格(以 wei 为单位)的整数。 +`QUANTITY` - 以 wei 为单位的当前燃料价格的整数。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":73}' -// Result +// 结果 { "id":73, "jsonrpc": "2.0", @@ -513,20 +537,24 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":7 返回客户端拥有的地址列表。 + + 在 playground 中尝试端点 + + **参数** 无 **返回值** -`Array of DATA`,20 字节 - 客户端拥有的地址。 +`DATA 数组`,20 字节 - 客户端拥有的地址。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -538,20 +566,24 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1 返回最新区块的编号。 + + 在 playground 中尝试端点 + + **参数** 无 **返回值** -`QUANTITY` - 表示客户端所在的当前区块编号的整数。 +`QUANTITY` - 客户端所在的当前区块编号的整数。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":83}' -// Result +// 结果 { "id":83, "jsonrpc": "2.0", @@ -563,10 +595,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id 返回给定地址的帐户余额。 + + 在 playground 中尝试端点 + + **参数** -1. `DATA`,20 字节 - 需要检查余额的地址。 -2. `QUANTITY|TAG` - 整数区块号,或字符串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,参见[默认区块参数](/developers/docs/apis/json-rpc/#default-block) +1. `DATA`,20 字节 - 要查询余额的地址。 +2. `QUANTITY|TAG` - 整数区块编号,或字符串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,请参阅[区块参数](/developers/docs/apis/json-rpc/#block-parameter) ```js params: ["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"] @@ -574,14 +610,14 @@ params: ["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"] **返回值** -`QUANTITY` - 表示当前余额的整数(以 wei 为单位)。 +`QUANTITY` - 以 wei 为单位的当前余额的整数。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"],"id":1}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -593,30 +629,35 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x407 从给定地址的存储位置返回值。 + + 在 playground 中尝试端点 + + **参数** -1. `DATA`,20 字节 - 存储地址。 -2. `QUANTITY` - 表示存储位置的整数。 -3. `QUANTITY|TAG` - 整数区块号,或字符串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,参见[默认区块参数](/developers/docs/apis/json-rpc/#default-block) +1. `DATA`,20 字节 - 存储的地址。 +2. `QUANTITY` - 存储中位置的整数。 +3. `QUANTITY|TAG` - 整数区块编号,或字符串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,请参阅[区块参数](/developers/docs/apis/json-rpc/#block-parameter) **返回值** -`DATA` - 此存储位置处的值。 +`DATA` - 此存储位置的值。 -**示例** 正确位置的计算取决于要检索的存储。 考虑通过地址 `0x391694e7e0b0cce554cb130d723a9d27458f9298` 部署在 `0x295a70b2de5e3953354a6a8344e616ed314d7251` 的以下合约。 +**示例** +正确位置的计算取决于要检索的存储。 考虑通过地址 `0x391694e7e0b0cce554cb130d723a9d27458f9298` 部署在 `0x295a70b2de5e3953354a6a8344e616ed314d7251` 的以下合约。 ``` contract Storage { uint pos0; mapping(address => uint) pos1; - function Storage() { + constructor() { pos0 = 1234; pos1[msg.sender] = 5678; } } ``` -检索 pos0 的值比较简单: +检索 pos0 的值很简单: ```js curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x0", "latest"], "id": 1}' localhost:8545 @@ -658,30 +699,34 @@ curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": [ ### eth_getTransactionCount {#eth_gettransactioncount} -返回从一个地址_发送_的交易数量。 +返回从某个地址_发送_的交易数量。 + + + 在 playground 中尝试端点 + **参数** 1. `DATA`,20 字节 - 地址。 -2. `QUANTITY|TAG` - 整数区块号,或字符串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,参见[默认区块参数](/developers/docs/apis/json-rpc/#default-block) +2. `QUANTITY|TAG` - 整数区块编号,或字符串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,请参阅[区块参数](/developers/docs/apis/json-rpc/#block-parameter) ```js params: [ "0x407d73d8a49eeb85d32cf465507dd71d507100c1", - "latest", // state at the latest block + "latest", // 最新区块的状态 ] ``` **返回值** -`QUANTITY` - 表示从该地址发送的交易数量的整数。 +`QUANTITY` - 从此地址发送的交易数量的整数。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0x407d73d8a49eeb85d32cf465507dd71d507100c1","latest"],"id":1}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -693,6 +738,10 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params 返回匹配给定区块哈希的区块中的交易数量。 + + 在 playground 中尝试端点 + + **参数** 1. `DATA`,32 字节 - 区块的哈希 @@ -703,7 +752,7 @@ params: ["0xd03ededb7415d22ae8bac30f96b2d1de83119632693b963642318d87d1bece5b"] **返回值** -`QUANTITY` - 表示此区块中的交易数量的整数。 +`QUANTITY` - 此区块中交易数量的整数。 **示例** @@ -722,9 +771,13 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockTransactionCountByHa 返回匹配给定区块编号的区块中的交易数量。 + + 在 playground 中尝试端点 + + **参数** -1. `QUANTITY|TAG` - 整数区块号,或字符串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,参见[默认区块参数](/developers/docs/apis/json-rpc/#default-block) +1. `QUANTITY|TAG` - 整数区块编号,或字符串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,请参阅[区块参数](/developers/docs/apis/json-rpc/#block-parameter)。 ```js params: [ @@ -734,7 +787,7 @@ params: [ **返回值** -`QUANTITY` - 表示此区块中的交易数量的整数。 +`QUANTITY` - 此区块中交易数量的整数。 **示例** @@ -753,6 +806,10 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockTransactionCountByNu 返回匹配给定区块哈希的区块中的叔块数量。 + + 在 playground 中尝试端点 + + **参数** 1. `DATA`,32 字节 - 区块的哈希 @@ -763,7 +820,7 @@ params: ["0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2"] **返回值** -`QUANTITY` - 表示此区块中的叔块数量的整数。 +`QUANTITY` - 此区块中叔块数量的整数。 **示例** @@ -782,9 +839,13 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleCountByBlockHash","p 返回匹配给定区块编号的区块中的叔块数量。 + + 在 playground 中尝试端点 + + **参数** -1. `QUANTITY|TAG` - 整数区块号,或字符串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,参见[默认区块参数](/developers/docs/apis/json-rpc/#default-block) +1. `QUANTITY|TAG` - 整数区块编号,或字符串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,请参阅[区块参数](/developers/docs/apis/json-rpc/#block-parameter) ```js params: [ @@ -794,7 +855,7 @@ params: [ **返回值** -`QUANTITY` - 表示此区块中的叔块数量的整数。 +`QUANTITY` - 此区块中叔块数量的整数。 **示例** @@ -813,10 +874,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleCountByBlockNumber", 返回位于给定地址的代码。 + + 在 playground 中尝试端点 + + **参数** 1. `DATA`,20 字节 - 地址 -2. `QUANTITY|TAG` - 整数区块号,或字符串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,参见[默认区块参数](/developers/docs/apis/json-rpc/#default-block) +2. `QUANTITY|TAG` - 整数区块编号,或字符串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,请参阅[区块参数](/developers/docs/apis/json-rpc/#block-parameter) ```js params: [ @@ -827,7 +892,7 @@ params: [ **返回值** -`DATA` - 给定地址处的代码。 +`DATA` - 来自给定地址的代码。 **示例** @@ -844,9 +909,9 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getCode","params":["0xC02aaA ### eth_sign {#eth_sign} -Sign 方法如下计算以太坊特定的签名:`sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))`。 +sign 方法通过 `sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))` 计算以太坊专用签名。 -通过在消息中添加前缀,计算出的签名就可以识别为以太坊特定签名。 这可以防止滥用行为,如恶意去中心化应用程序可以签署任意数据(例如交易)并使用签名冒充受害者。 +通过在消息中添加前缀,计算出的签名就可以识别为以太坊特定签名。 这可以防止滥用,因为恶意去中心化应用程序可以签署任意数据(例如交易)并使用签名冒充受害者。 注意:签名时使用的地址必须已解锁。 @@ -862,9 +927,9 @@ Sign 方法如下计算以太坊特定的签名:`sign(keccak256("\x19Ethereum **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sign","params":["0x9b2055d370f73ec7d8a03e965129118dc8f5bf83", "0xdeadbeaf"],"id":1}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -878,27 +943,27 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sign","params":["0x9b2055d37 **参数** -1. `Object` - 交易对象 +1. `对象` - 交易对象 - `type`: -- `from`: `DATA`,20 字节 - 发送交易的地址。 -- `to`: `DATA`,20 字节 -(创建新合约时可选)将交易定向到的地址。 -- `gas`: `QUANTITY` -(可选,默认值:90000)表示为交易执行提供的燃料的整数。 它将返回未使用的燃料。 -- `gasPrice`: `QUANTITY` -(可选,默认值:待确定)表示用于每笔已支付燃料的 gasPrice 的整数,以 Wei 为单位。 -- `value`: `QUANTITY` -(可选)表示与此交易一起发送的值的整数,以 Wei 为单位。 -- `data`: `DATA` - 合约的编译代码或调用的方法签名和编码参数的哈希。 -- `nonce`: `QUANTITY` -(可选)表示随机数的整数。 它允许覆盖你自己的使用相同随机数的待处理交易。 +- `from`:`DATA`,20 字节 - 交易发送方地址。 +- `to`:`DATA`,20 字节 -(创建新合约时可选)交易接收方地址。 +- `gas`:`QUANTITY` -(可选,默认值:90000)为交易执行提供的燃料整数。 它将返回未使用的燃料。 +- `gasPrice`:`QUANTITY` -(可选,默认值:待定)用于每单位已支付燃料的 gasPrice 整数,以 Wei 为单位。 +- `value`:`QUANTITY` -(可选)随此交易发送的价值的整数,以 Wei 为单位。 +- `data`:`DATA` - 合约的已编译代码或所调用方法签名和编码参数的哈希。 +- `nonce`:`QUANTITY` -(可选)nonce 的整数。 它允许覆盖你自己的使用相同随机数的待处理交易。 **返回值** -`DATA`,由指定帐户签名的 RLP 编码的交易对象。 +`DATA`,由指定账户签名的 RLP 编码交易对象。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"id": 1,"jsonrpc": "2.0","method": "eth_signTransaction","params": [{"data":"0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675","from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155","gas": "0x76c0","gasPrice": "0x9184e72a000","to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567","value": "0x9184e72a"}]}' -// Result +// 结果 { "id": 1, "jsonrpc": "2.0", @@ -908,19 +973,19 @@ curl -X POST --data '{"id": 1,"jsonrpc": "2.0","method": "eth_signTransaction"," ### eth_sendTransaction {#eth_sendtransaction} -创建新的消息调用交易或创建合约(如果数据字段包含代码),然后使用 `from` 中指定的帐户签名。 +如果数据字段包含代码,则创建新的消息调用交易或合约,并使用 `from` 中指定的帐户进行签名。 **参数** -1. `Object` - 交易对象 +1. `对象` - 交易对象 -- `from`: `DATA`,20 字节 - 发送交易的地址。 -- `to`: `DATA`,20 字节 -(创建新合约时可选)将交易定向到的地址。 -- `gas`: `QUANTITY` -(可选,默认值:90000)表示为交易执行提供的燃料的整数。 它将返回未使用的燃料。 -- `gasPrice`: `QUANTITY` -(可选,默认值:待确定)表示用于每个已支付燃料的 gasPrice 的整数。 -- `value`: `QUANTITY` -(可选)表示与此交易一起发送的值的整数。 -- `input`: `DATA` - 合约的编译代码或调用的方法签名和编码参数的哈希。 -- `nonce`: `QUANTITY` -(可选)表示随机数的整数。 它允许覆盖你自己的使用相同随机数的待处理交易。 +- `from`:`DATA`,20 字节 - 交易发送方地址。 +- `to`:`DATA`,20 字节 -(创建新合约时可选)交易接收方地址。 +- `gas`:`QUANTITY` -(可选,默认值:90000)为交易执行提供的燃料整数。 它将返回未使用的燃料。 +- `gasPrice`:`QUANTITY` -(可选,默认值:待定)用于每单位已支付燃料的 gasPrice 整数。 +- `value`:`QUANTITY` -(可选)随此交易发送的价值的整数。 +- `input`:`DATA` - 合约的已编译代码或所调用方法签名和编码参数的哈希。 +- `nonce`:`QUANTITY` -(可选)nonce 的整数。 它允许覆盖你自己的使用相同随机数的待处理交易。 ```js params: [ @@ -938,16 +1003,16 @@ params: [ **返回值** -`DATA`,32 字节 - 交易哈希,或者如果交易尚不可用,则为零哈希。 +`DATA`,32 字节 - 交易哈希;如果交易尚不可用,则为零哈希。 创建合约时,在交易被提议到区块后,使用 [eth_getTransactionReceipt](#eth_gettransactionreceipt) 获取合约地址。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{see above}],"id":1}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -961,7 +1026,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{ **参数** -1. `DATA`,签名的交易数据。 +1. `DATA`,已签名的交易数据。 ```js params: [ @@ -971,16 +1036,16 @@ params: [ **返回值** -`DATA`,32 字节 - 交易哈希,或者如果交易尚不可用,则为零哈希。 +`DATA`,32 字节 - 交易哈希;如果交易尚不可用,则为零哈希。 创建合约时,在交易被提议到区块后,使用 [eth_getTransactionReceipt](#eth_gettransactionreceipt) 获取合约地址。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":[{see above}],"id":1}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -990,20 +1055,24 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params" ### eth_call {#eth_call} -立即执行新的消息调用,但不在区块链上创建交易。 通常用来执行只读智能合约的函数,例如 ERC-20 合约的 `balanceOf` 函数。 +立即执行新的消息调用,但不在区块链上创建交易。 通常用于执行只读智能合约函数,例如 ERC-20 合约的 `balanceOf`。 + + + 在 playground 中尝试端点 + **参数** -1. `Object` - 交易调用对象 +1. `对象` - 交易调用对象 -- `from`: `DATA`,20 字节 -(可选)发送交易的地址。 -- `to`: `DATA`,20 字节 - 将交易定向到的地址。 -- `gas`: `QUANTITY` -(可选)表示为交易执行提供的燃料的整数。 eth_call 消耗零燃料,但某些执行可能需要此参数。 -- `gasPrice`: `QUANTITY` -(可选)表示用于每个已支付燃料的 gasPrice 的整数 -- `value`: `QUANTITY` -(可选)表示与此交易一起发送的值的整数 -- `input`: `DATA` -(可选)方法签名和编码参数的哈希。 有关详细信息,参见 [Solidity 文档中的以太坊合约应用程序二进制接口](https://docs.soliditylang.org/en/latest/abi-spec.html)。 +- `from`:`DATA`,20 字节 -(可选)交易发送方地址。 +- `to`:`DATA`,20 字节 - 交易接收方地址。 +- `gas`:`QUANTITY` -(可选)为交易执行提供的燃料整数。 eth_call 消耗零燃料,但某些执行可能需要此参数。 +- `gasPrice`:`QUANTITY` -(可选)用于每单位已支付燃料的 gasPrice 整数 +- `value`:`QUANTITY` -(可选)随此交易发送的价值的整数 +- `input`:`DATA` -(可选)方法签名和编码参数的哈希。 详情请参阅 [Solidity 文档中的以太坊合约 ABI](https://docs.soliditylang.org/en/latest/abi-spec.html)。 -2. `QUANTITY|TAG` - 整数区块号,或字符串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,参见[默认区块参数](/developers/docs/apis/json-rpc/#default-block) +2. `QUANTITY|TAG` - 整数区块编号,或字符串 `"latest"`、`"earliest"`、`"pending"`、`"safe"` 或 `"finalized"`,请参阅[区块参数](/developers/docs/apis/json-rpc/#block-parameter) **返回值** @@ -1012,9 +1081,9 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params" **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{see above}],"id":1}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -1026,20 +1095,24 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{see above}] 生成并返回允许交易完成所需燃料数量的估算值。 交易不会添加到区块链中。 请注意,出于各种原因,包括以太坊虚拟机的机制和节点性能,估算值可能远远超过交易实际使用的燃料数量。 + + 在 playground 中尝试端点 + + **参数** -参见 [eth_call](#eth_call) 的参数,但所有属性都是可选的。 如果没有指定燃料限制,geth 将使用待处理区块的区块燃料限制作为上限。 因此,当所需燃料数量高于待处理区块的燃料限制时,返回的估算值可能不足以执行调用/交易。 +参见 [eth_call](#eth_call) 参数,但所有属性都是可选的。 如果没有指定燃料限制,geth 将使用待处理区块的区块燃料限制作为上限。 因此,当燃料数量高于待处理区块的燃料限制时,返回的估算值可能不足以执行调用/交易。 **返回值** -`QUANTITY` - 使用的燃料数量。 +`QUANTITY` - 已使用的燃料数量。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_estimateGas","params":[{see above}],"id":1}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -1051,10 +1124,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_estimateGas","params":[{see 根据哈希返回关于区块的信息。 + + 在 playground 中尝试端点 + + **参数** 1. `DATA`,32 字节 - 区块的哈希。 -2. `Boolean` - 如果为 `true` 则返回完整的交易对象,如果为 `false` 则仅返回交易的哈希。 +2. `布尔值` - 如果为 `true`,则返回完整的交易对象;如果为 `false`,则仅返回交易的哈希。 ```js params: [ @@ -1065,39 +1142,38 @@ params: [ **返回值** -`Object` - 区块对象,或 `null`(当没有找到区块时): - -- `number`: `QUANTITY` - 区块编号。 如果是待处理区块,则为 `null`。 -- `hash`: `DATA`,32 字节 - 区块的哈希。 如果是待处理区块,则为 `null`。 -- `parentHash`: `DATA`,32 字节 - 父块的哈希。 -- `nonce`: `DATA`,8 字节 - 已生成的工作量证明的哈希。 如果是待处理区块,则为 `null`。 -- `sha3Uncles`: `DATA`,32 字节 - 区块中的叔块数据的 SHA3。 -- `logsBloom`: `DATA`,256 字节 - 区块日志的布隆过滤器。 如果是待处理区块,则为 `null`。 -- `transactionsRoot`: `DATA`,32 字节 - 区块交易树的根。 -- `stateRoot`: `DATA`,32 字节 - 区块最终状态树的根。 -- `receiptsRoot`: `DATA`,32 字节 - 区块收据树的根。 -- `miner`: `DATA`,20 字节 - 获得挖矿奖励的受益人的地址。 -- `difficulty`: `QUANTITY` - 表示此区块难度的整数。 -- `totalDifficulty`: `QUANTITY` - 表示到此区块为止链的总难度的整数。 -- `extraData`: `DATA` - 此区块的“额外数据”字段。 -- `size`: `QUANTITY` - 表示此区块大小的整数,以字节为单位。 -- `gasLimit`: `QUANTITY` - 此区块允许的最大燃料数量。 -- `gasUsed`: `QUANTITY` - 此区块中所有交易使用的总燃料数量。 -- `timestamp`: `QUANTITY` - 整理区块时的 unix 时间戳。 -- `transactions`: `Array` - 交易对象数组,或 32 字节交易哈希,取决于最后一个给定的参数。 -- `uncles`: `Array` - 叔块哈希数组。 +`对象` - 区块对象;如果未找到区块,则为 `null`: + +- `number`:`QUANTITY` - 区块编号。 如果是待处理区块,则为 null。 +- `hash`:`DATA`,32 字节 - 区块的哈希。 如果是待处理区块,则为 null。 +- `parentHash`:`DATA`,32 字节 - 父块的哈希。 +- `nonce`:`DATA`,8 字节 - 生成的工作量证明的哈希。 如果是待处理区块时,则为 `null`,如果是权益证明区块(自合并起),则为 `0x0`。 +- `sha3Uncles`:`DATA`,32 字节 - 区块中叔块数据的 SHA3。 +- `logsBloom`:`DATA`,256 字节 - 区块日志的布隆过滤器。 如果是待处理区块,则为 null。 +- `transactionsRoot`:`DATA`,32 字节 - 区块交易树的根。 +- `stateRoot`:`DATA`,32 字节 - 区块最终状态树的根。 +- `receiptsRoot`:`DATA`,32 字节 - 区块收据树的根。 +- `miner`:`DATA`,20 字节 - 获得区块奖励的受益人的地址。 +- `difficulty`:`QUANTITY` - 此区块难度的整数。 +- `totalDifficulty`:`QUANTITY` - 截至此区块的链总难度的整数。 +- `extraData`:`DATA` - 此区块的“额外数据”字段。 +- `size`:`QUANTITY` - 此区块大小的整数,以字节为单位。 +- `gasLimit`:`QUANTITY` - 此区块允许的最大燃料数量。 +- `gasUsed`:`QUANTITY` - 此区块中所有交易使用的总燃料数量。 +- `timestamp`:`QUANTITY` - 整理区块时的 unix 时间戳。 +- `transactions`:`数组` - 交易对象数组或 32 字节交易哈希,具体取决于最后一个给定参数。 +- `uncles`:`数组` - 叔块哈希数组。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByHash","params":["0xdc0818cf78f21a8e70579cb46a43643f78291264dda342ae31049421c82d21ae", false],"id":1}' -// Result -{ +// 结果 { -"jsonrpc": "2.0", -"id": 1, -"result": { + "jsonrpc": "2.0", + "id": 1, + "result": { "difficulty": "0x4ea3f27bc", "extraData": "0x476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32", "gasLimit": "0x1388", @@ -1120,7 +1196,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByHash","params":["0 "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncles": [ ] -} + } } ``` @@ -1128,10 +1204,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByHash","params":["0 根据区块编号返回关于区块的信息。 + + 在 playground 中尝试端点 + + **参数** -1. `QUANTITY|TAG` - 整数区块号,或字符串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,参见[默认区块参数](/developers/docs/apis/json-rpc/#default-block) -2. `Boolean` - 如果为 `true` 则返回完整的交易对象,如果为 `false` 则仅返回交易的哈希。 +1. `QUANTITY|TAG` - 整数区块编号,或字符串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,请参阅[区块参数](/developers/docs/apis/json-rpc/#block-parameter)。 +2. `布尔值` - 如果为 `true`,则返回完整的交易对象;如果为 `false`,则仅返回交易的哈希。 ```js params: [ @@ -1140,24 +1220,29 @@ params: [ ] ``` -**返回值** 参见 [eth_getBlockByHash](#eth_getblockbyhash) +**返回值** +请参阅 [eth_getBlockByHash](#eth_getblockbyhash) **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x1b4", true],"id":1}' ``` -结果参见 [eth_getBlockByHash](#eth_getblockbyhash) +结果请参阅 [eth_getBlockByHash](#eth_getblockbyhash) ### eth_getTransactionByHash {#eth_gettransactionbyhash} 根据交易哈希返回关于所请求交易的信息。 + + 在 playground 中尝试端点 + + **参数** -1. `DATA`,32 字节- 交易的哈希 +1. `DATA`,32 字节 - 交易的哈希 ```js params: ["0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"] @@ -1165,29 +1250,29 @@ params: ["0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"] **返回值** -`Object` - 交易对象,或者如果没有找到交易,则为 `null`: - -- `blockHash`: `DATA`,32 字节 - 此交易所在区块的哈希。 如果是待处理区块,则为 `null`。 -- `blockNumber`: `QUANTITY` - 此交易所在区块的区块编号。 如果是待处理区块,则为 `null`。 -- `from`: `DATA`,20 字节 - 发送者的地址。 -- `gas`: `QUANTITY` - 发送者提供的燃料。 -- `gasPrice`: `QUANTITY` - 发送者提供的燃料价格,以 Wei 为单位。 -- `hash`: `DATA`,32 字节 - 交易的哈希。 -- `input`: `DATA` - 与交易一起发送的数据。 -- `nonce`: `QUANTITY` - 发送者在此交易之前进行的交易数量。 -- `to`: `DATA`,20 字节 - 接收者的地址。 如果是合约创建交易,则为 `null`。 -- `transactionIndex`: `QUANTITY` - 表示区块中的交易索引位置的整数。 如果是待处理区块,则为 `null`。 -- `value`: `QUANTITY` - 传输的值,以 Wei 为单位。 -- `v`: `QUANTITY` - 椭圆曲线加密法恢复 ID -- `r`: `QUANTITY` - 椭圆曲线加密法签名 r -- `s`: `QUANTITY` - 椭圆曲线加密法签名 s +`对象` - 交易对象;如果未找到交易,则为 `null`: + +- `blockHash`:`DATA`,32 字节 - 此交易所在区块的哈希。 如果交易待处理,则为 `null`。 +- `blockNumber`:`QUANTITY` - 此交易所在区块的区块编号。 如果交易待处理,则为 `null`。 +- `from`:`DATA`,20 字节 - 发送者的地址。 +- `gas`:`QUANTITY` - 发送者提供的燃料。 +- `gasPrice`:`QUANTITY` - 发送者提供的燃料价格,以 Wei 为单位。 +- `hash`:`DATA`,32 字节 - 交易的哈希。 +- `input`:`DATA` - 随交易发送的数据。 +- `nonce`:`QUANTITY` - 发送者在此交易之前进行的交易数量。 +- `to`:`DATA`,20 字节 - 接收者的地址。 如果是合约创建交易,则为 null。 +- `transactionIndex`:`QUANTITY` - 区块中交易索引位置的整数。 如果交易待处理,则为 `null`。 +- `value`:`QUANTITY` - 以 Wei 为单位的转账价值。 +- `v`:`QUANTITY` - ECDSA 恢复 ID +- `r`:`QUANTITY` - ECDSA 签名 r +- `s`:`QUANTITY` - ECDSA 签名 s **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"],"id":1}' -// Result +// 结果 { "jsonrpc":"2.0", "id":1, @@ -1214,10 +1299,14 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","param 根据区块哈希和交易索引位置返回关于交易的信息。 + + 在 playground 中尝试端点 + + **参数** 1. `DATA`,32 字节 - 区块的哈希。 -2. `QUANTITY` - 表示交易索引位置的整数。 +2. `QUANTITY` - 交易索引位置的整数。 ```js params: [ @@ -1226,7 +1315,8 @@ params: [ ] ``` -**返回值** 参见 [eth_getTransactionByHash](#eth_gettransactionbyhash) +**返回值** +请参阅 [eth_getTransactionByHash](#eth_gettransactionbyhash) **示例** @@ -1235,15 +1325,19 @@ params: [ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByBlockHashAndIndex","params":["0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2", "0x0"],"id":1}' ``` -结果参见 [eth_getTransactionByHash](#eth_gettransactionbyhash) +结果请参阅 [eth_getTransactionByHash](#eth_gettransactionbyhash) ### eth_getTransactionByBlockNumberAndIndex {#eth_gettransactionbyblocknumberandindex} 根据区块编号和交易索引位置返回关于交易的信息。 + + 在 playground 中尝试端点 + + **参数** -1. `QUANTITY|TAG` - 整数区块号,或字符串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,参见[默认区块参数](/developers/docs/apis/json-rpc/#default-block) +1. `QUANTITY|TAG` - 区块编号,或字符串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,请参阅[区块参数](/developers/docs/apis/json-rpc/#block-parameter)。 2. `QUANTITY` - 交易索引位置。 ```js @@ -1253,51 +1347,53 @@ params: [ ] ``` -**返回值** 参见 [eth_getTransactionByHash](#eth_gettransactionbyhash) +**返回值** +请参阅 [eth_getTransactionByHash](#eth_gettransactionbyhash) **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByBlockNumberAndIndex","params":["0x9c47cf", "0x24"],"id":1}' ``` -结果参见 [eth_getTransactionByHash](#eth_gettransactionbyhash) +结果请参阅 [eth_getTransactionByHash](#eth_gettransactionbyhash) ### eth_getTransactionReceipt {#eth_gettransactionreceipt} 根据交易哈希返回交易的收据。 -**注意**:收据不可用于待处理的交易。 +**注意**待处理的交易没有收据。 **参数** -1. `DATA`,32 字节- 交易的哈希 +1. `DATA`,32 字节 - 交易的哈希 ```js params: ["0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5"] ``` -**返回值** `Object` - 交易收据对象,或者如果没有找到收据,则为 `null`: - -- `transactionHash`: `DATA`,32 字节- 交易的哈希。 -- `transactionIndex`: `QUANTITY` - 表示区块中的交易索引位置的整数。 -- `blockHash`: `DATA`,32 字节 - 此交易所在区块的哈希。 -- `blockNumber`: `QUANTITY` - 此交易所在区块的区块编号。 -- `from`: `DATA`,20 字节 - 发送者的地址。 -- `to`: `DATA`,20 字节 - 接收者的地址。 如果是合约创建交易,则为 null。 -- `cumulativeGasUsed` : `QUANTITY` - 当在区块中执行此交易时使用的燃料总量。 -- `effectiveGasPrice` : `QUANTITY` - 为每单位燃料支付的基础费和小费的总和。 -- `gasUsed`: `QUANTITY` - 仅此特定交易使用的燃料数量。 -- `contractAddress`: `DATA`,20 字节 - 如果交易是创建合约的,则为创建的合约地址,否则为 `null`。 -- `logs`: `Array` - 此交易生成的日志对象数组。 -- `logsBloom`: `DATA`,256 字节 - 轻客户端用于快速检索相关日志的布隆过滤器。 -- `type`: `QUANTITY` - 表示交易类型的整数,`0x0` 表示传统交易,`0x1` 表示访问列表类型,`0x2` 表示动态费用。 - -它还返回_以下两者之一_: - -- `root` : `DATA`,32 字节的交易后状态根(拜占庭升级之前) -- `status`: `QUANTITY`,`1`(成功)或 `0`(失败) +**返回值** +`对象` - 交易收据对象;如果未找到收据,则为 `null`: + +- `transactionHash `:`DATA`,32 字节 - 交易的哈希。 +- `transactionIndex`:`QUANTITY` - 区块中交易索引位置的整数。 +- `blockHash`:`DATA`,32 字节 - 此交易所在区块的哈希。 +- `blockNumber`:`QUANTITY` - 此交易所在区块的区块编号。 +- `from`:`DATA`,20 字节 - 发送者的地址。 +- `to`:`DATA`,20 字节 - 接收者的地址。 如果是合约创建交易,则为 null。 +- `cumulativeGasUsed` : `QUANTITY ` - 在区块中执行此交易时使用的燃料总量。 +- `effectiveGasPrice`:`QUANTITY` - 为每单位燃料支付的基础费和小费的总和。 +- `gasUsed `:`QUANTITY ` - 仅此特定交易使用的燃料数量。 +- `contractAddress `:`DATA`,20 字节 - 如果交易是创建合约的,则为创建的合约地址,否则为 `null`。 +- `logs`:`数组` - 此交易生成的日志对象数组。 +- `logsBloom`:`DATA`,256 字节 - 布隆过滤器,供轻客户端快速检索相关日志。 +- `type`:`QUANTITY` - 交易类型的整数,`0x0` 表示传统交易,`0x1` 表示访问列表类型,`0x2` 表示动态费用。 + +它还返回以下任一者: + +- `root` : `DATA` 32 字节的交易后状态根(拜占庭之前) +- `status`:`QUANTITY`,`1`(成功)或 `0`(失败) **示例** @@ -1335,6 +1431,10 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","para 根据哈希和叔块索引位置返回关于区块的叔块的信息。 + + 在 playground 中尝试端点 + + **参数** 1. `DATA`,32 字节 - 区块的哈希。 @@ -1347,7 +1447,8 @@ params: [ ] ``` -**返回值** 参见 [eth_getBlockByHash](#eth_getblockbyhash) +**返回值** +请参阅 [eth_getBlockByHash](#eth_getblockbyhash) **示例** @@ -1356,7 +1457,7 @@ params: [ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleByBlockHashAndIndex","params":["0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2", "0x0"],"id":1}' ``` -结果参见 [eth_getBlockByHash](#eth_getblockbyhash) +结果请参阅 [eth_getBlockByHash](#eth_getblockbyhash) **注意**:叔块不包含个人交易。 @@ -1364,9 +1465,13 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleByBlockHashAndIndex" 根据编号和叔块索引位置返回关于区块的叔块的信息。 + + 在 playground 中尝试端点 + + **参数** -1. `QUANTITY|TAG` - 整数区块号,或字符串 `"earliest"`、`"latest"`、`"pending"`、`"safe"` 或 `"finalized"`,参见[默认区块参数](/developers/docs/apis/json-rpc/#default-block) +1. `QUANTITY|TAG` - 区块编号,或字符串 `"earliest"`、`"latest"`、`"pending"`、`"safe"`、`"finalized"`,请参阅[区块参数](/developers/docs/apis/json-rpc/#block-parameter)。 2. `QUANTITY` - 叔块的索引位置。 ```js @@ -1376,38 +1481,41 @@ params: [ ] ``` -**返回值** 参见 [eth_getBlockByHash](#eth_getblockbyhash) +**返回值** +请参阅 [eth_getBlockByHash](#eth_getblockbyhash) **注意**:叔块不包含个人交易。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getUncleByBlockNumberAndIndex","params":["0x29c", "0x0"],"id":1}' ``` -结果参见 [eth_getBlockByHash](#eth_getblockbyhash) +结果请参阅 [eth_getBlockByHash](#eth_getblockbyhash) ### eth_newFilter {#eth_newfilter} -基于筛选器选项创建一个筛选器对象,以在状态更改(日志)时发出通知。 要检查状态是否已更改,请调用 [eth_getFilterChanges](#eth_getfilterchanges)。 +基于筛选器选项创建一个筛选器对象,以在状态更改(日志)时发出通知。 +要检查状态是否已更改,请调用 [eth_getFilterChanges](#eth_getfilterchanges)。 -**关于指定主题筛选器的说明:** 主题是顺序相关的。 以下主题过滤器将匹配日志中包含主题 [A, B] 的交易: +**关于指定主题筛选器的说明:** +主题是顺序相关的。 以下主题过滤器将匹配日志中包含主题 [A, B] 的交易: - `[]`“任意值” - `[A]`“第一个位置为 A(之后的位置为任意值)” - `[null, B]`“第一个位置为任意值,且第二个位置为 B(之后的位置为任意值)” - `[A, B]`“第一个位置为 A,且第二个位置为 B(之后的位置为任意值)” -- `[[A, B], [A, B]]`“第一个位置为(A OR B),且第二个位置为(A OR B)(之后的位置为任意值)” +- `[[A, B], [A, B]]`“第一个位置为(A 或 B),且第二个位置为(A 或 B)(之后的位置为任意值)” - **参数** -1. `Object` - 筛选器选项: +1. `对象` - 筛选器选项: -- `fromBlock`: `QUANTITY|TAG` -(可选,默认值:`"latest"`)整型区块编号,或者`"latest"`表示最近提议的区块,`"safe"`表示最新的安全区块,`"finalized"`表示最近最终化的区块,或者`"pending"`、`"earliest"`表示尚未在区块中的交易。 -- `toBlock`: `QUANTITY|TAG` - (可选,默认值:`"latest"`)整型区块编号,或者`"latest"`表示最近提议的区块,`"safe"`表示最新的安全区块,`"finalized"`表示最近最终化的区块,或者`"pending"`、`"earliest"`表示尚未在区块中的交易。 -- `address`: `DATA|Array`,20 字节 -(可选)日志起源的合约地址或地址列表。 -- `topics`: `Array of DATA` -(可选)32 字节 `DATA` 主题数组。 主题是顺序相关的。 每个主题也可以是带有“或”选项的 DATA 数组。 +- `fromBlock`:`QUANTITY|TAG` - (可选,默认:`"latest"`)整数区块编号,或 `"latest"` 表示最新提议的区块,`"safe"` 表示最新的安全区块,`"finalized"` 表示最新最终确定的区块,或 `"pending"`、`"earliest"` 表示尚未进入区块的交易。 +- `toBlock`:`QUANTITY|TAG` - (可选,默认:`"latest"`)整数区块编号,或 `"latest"` 表示最新提议的区块,`"safe"` 表示最新的安全区块,`"finalized"` 表示最新最终确定的区块,或 `"pending"`、`"earliest"` 表示尚未进入区块的交易。 +- `address`:`DATA|数组`,20 字节 -(可选)日志起源的合约地址或地址列表。 +- `topics`:`DATA 数组`,-(可选)32 字节 `DATA` 主题数组。 主题是顺序相关的。 每个主题也可以是带有“or”选项的 DATA 数组。 ```js params: [ @@ -1427,14 +1535,15 @@ params: [ ] ``` -**返回值** `QUANTITY` - 筛选器 ID。 +**返回值** +`QUANTITY` - 筛选器 ID。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newFilter","params":[{"topics":["0x12341234"]}],"id":73}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -1444,18 +1553,21 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newFilter","params":[{"topic ### eth_newBlockFilter {#eth_newblockfilter} -在节点中创建一个筛选器,以在新区块到达时发出通知。 要检查状态是否已更改,请调用 [eth_getFilterChanges](#eth_getfilterchanges)。 +在节点中创建一个筛选器,以在新区块到达时发出通知。 +要检查状态是否已更改,请调用 [eth_getFilterChanges](#eth_getfilterchanges)。 -**参数** 无 +**参数** +无 -**返回值** `QUANTITY` - 筛选器 ID。 +**返回值** +`QUANTITY` - 筛选器 ID。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newBlockFilter","params":[],"id":73}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -1465,18 +1577,21 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newBlockFilter","params":[], ### eth_newPendingTransactionFilter {#eth_newpendingtransactionfilter} -在节点中创建一个筛选器,以在新的待处理交易到达时发出通知。 要检查状态是否已更改,请调用 [eth_getFilterChanges](#eth_getfilterchanges)。 +在节点中创建一个筛选器,以在新的待处理交易到达时发出通知。 +要检查状态是否已更改,请调用 [eth_getFilterChanges](#eth_getfilterchanges)。 -**参数** 无 +**参数** +无 -**返回值** `QUANTITY` - 筛选器 ID。 +**返回值** +`QUANTITY` - 筛选器 ID。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newPendingTransactionFilter","params":[],"id":73}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -1486,7 +1601,8 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newPendingTransactionFilter" ### eth_uninstallFilter {#eth_uninstallfilter} -卸载具有给定 ID 的筛选器。 当不再需要监控时应始终调用该方法。 此外,在一段时间内未使用 [eth_getFilterChanges](#eth_getfilterchanges) 请求筛选器时,筛选器便会超时。 +卸载具有给定 ID 的筛选器。 当不再需要监控时应始终调用该方法。 +此外,在一段时间内未使用 [eth_getFilterChanges](#eth_getfilterchanges) 请求筛选器时,筛选器便会超时。 **参数** @@ -1498,14 +1614,15 @@ params: [ ] ``` -**返回值** `Boolean` - 如果成功卸载筛选器,则为 `true`,否则为 `false`。 +**返回值** +`布尔值` - 如果成功卸载筛选器,则为 `true`,否则为 `false`。 **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_uninstallFilter","params":["0xb"],"id":73}' -// Result +// 结果 { "id":1, "jsonrpc": "2.0", @@ -1527,26 +1644,30 @@ params: [ ] ``` -**返回值** `Array` - 日志对象数组,或者如果自上次轮询以来没有任何更改,则为空数组。 +**返回值** +`数组` - 日志对象数组;如果自上次轮询以来没有任何更改,则为空数组。 - 对于使用 `eth_newBlockFilter` 创建的过滤器,返回值是区块哈希(`DATA`,32 字节),例如 `["0x3454645634534..."]`。 + - 对于使用 `eth_newPendingTransactionFilter` 创建的筛选器,返回值是交易哈希(`DATA`,32 字节),例如 `["0x6345343454645..."]`。 + - 对于使用 `eth_newFilter` 创建的过滤器,日志是具有以下参数的对象: - - `removed`: `TAG` - 当日志由于链重组被删除时,为 `true`。 如果是有效日志,则为 `false`。 - - `logIndex`: `QUANTITY` - 表示区块中的日志索引位置的整数。 如果是待处理日志,则为 `null`。 - - `transactionIndex`: `QUANTITY` -表示从中创建日志的交易索引位置的整数。 如果是待处理日志,则为 `null`。 - - `transactionHash`: `DATA`,32 字节 - 从中创建此日志的交易的哈希。 如果是待处理日志,则为 `null`。 - - `blockHash`: `DATA`,32 字节 - 此日志所在区块的哈希。 如果是待处理区块,则为 `null`。 如果是待处理日志,则为 `null`。 - - `blockNumber`: `QUANTITY` - 此日志所在区块的区块编号。 如果是待处理区块,则为 `null`。 如果是待处理日志,则为 `null`。 - - `address`: `DATA`,20 字节 - 此日志的来源地址。 - - `data`: `DATA` - 包含日志的零个或多个 32 字节非索引参数。 - - `topics`: `Array of DATA` - 0 到 4 个 32 字节 `DATA` 类型的索引日志参数的数组。 (在 _Solidity_ 中:第一个主题是事件签名的_哈希_(例如 `Deposit(address,bytes32,uint256)`),除非你使用 `anonymous` 说明符声明了该事件。) + - `removed`:`TAG` - 如果日志因链重组而被删除,则为 `true`。 如果是有效日志,则为 `false`。 + - `logIndex`:`QUANTITY` - 区块中日志索引位置的整数。 如果是待处理日志,则为 `null`。 + - `transactionIndex`:`QUANTITY` - 创建日志的交易索引位置的整数。 如果是待处理日志,则为 `null`。 + - `transactionHash`:`DATA`,32 字节 - 创建此日志的交易的哈希。 如果是待处理日志,则为 `null`。 + - `blockHash`:`DATA`,32 字节 - 此日志所在区块的哈希。 如果交易待处理,则为 `null`。 如果是待处理日志,则为 `null`。 + - `blockNumber`:`QUANTITY` - 此日志所在区块的区块编号。 如果交易待处理,则为 `null`。 如果是待处理日志,则为 `null`。 + - `address`:`DATA`,20 字节 - 此日志的来源地址。 + - `data`:`DATA` - 可变长度的非索引日志数据。 (在 _solidity_ 中:零个或多个 32 字节的非索引日志参数。) + - `topics`:`DATA 数组` - 0 到 4 个 32 字节 `DATA` 类型的索引日志参数的数组。 (在 _solidity_ 中:第一个主题是事件签名的_哈希_(例如 `Deposit(address,bytes32,uint256)`),除非你使用 `anonymous` 说明符声明了该事件。) + - **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getFilterChanges","params":["0x16"],"id":73}' -// Result +// 结果 { "id":1, "jsonrpc":"2.0", @@ -1579,16 +1700,17 @@ params: [ ] ``` -**返回值** 参见 [eth_getFilterChanges](#eth_getfilterchanges) +**返回值** +请参阅 [eth_getFilterChanges](#eth_getfilterchanges) **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getFilterLogs","params":["0x16"],"id":74}' ``` -结果参见 [eth_getFilterChanges](#eth_getfilterchanges) +结果请参阅 [eth_getFilterChanges](#eth_getfilterchanges) ### eth_getLogs {#eth_getlogs} @@ -1596,13 +1718,13 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getFilterLogs","params":["0x **参数** -1. `Object` - 筛选器选项: +1. `对象` - 筛选器选项: -- `fromBlock`: `QUANTITY|TAG` -(可选,默认值:`"latest"`)整型区块编号,或者`"latest"`表示最近提议的区块,`"safe"`表示最新的安全区块,`"finalized"`表示最近最终化的区块,或者`"pending"`、`"earliest"`表示尚未在区块中的交易。 -- `toBlock`: `QUANTITY|TAG` - (可选,默认值:`"latest"`)整型区块编号,或者`"latest"`表示最近提议的区块,`"safe"`表示最新的安全区块,`"finalized"`表示最近最终化的区块,或者`"pending"`、`"earliest"`表示尚未在区块中的交易。 -- `address`: `DATA|Array`,20 字节 -(可选)日志起源的合约地址或地址列表。 -- `topics`: `Array of DATA` -(可选)32 字节 `DATA` 主题数组。 主题是顺序相关的。 每个主题也可以是带有“或”选项的 DATA 数组。 -- `blockhash`: `DATA`,32 字节 -(可选,**future**),添加 EIP-234 后,`blockHash` 将是一个新的过滤器选项,它会将返回的日志限制为具有 32 字节哈希 `blockHash` 的单一区块。 使用 `blockHash` 相当于 `fromBlock` = `toBlock` = 具有哈希 `blockHash` 的区块编号。 如果 `blockHash` 出现在筛选条件中,则 `fromBlock` 和 `toBlock` 都不允许。 +- `fromBlock`:`QUANTITY|TAG` - (可选,默认:`"latest"`)整数区块编号,或 `"latest"` 表示最新提议的区块,`"safe"` 表示最新的安全区块,`"finalized"` 表示最新最终确定的区块,或 `"pending"`、`"earliest"` 表示尚未进入区块的交易。 +- `toBlock`:`QUANTITY|TAG` - (可选,默认:`"latest"`)整数区块编号,或 `"latest"` 表示最新提议的区块,`"safe"` 表示最新的安全区块,`"finalized"` 表示最新最终确定的区块,或 `"pending"`、`"earliest"` 表示尚未进入区块的交易。 +- `address`:`DATA|数组`,20 字节 -(可选)日志起源的合约地址或地址列表。 +- `topics`:`DATA 数组`,-(可选)32 字节 `DATA` 主题数组。 主题是顺序相关的。 每个主题也可以是带有“or”选项的 DATA 数组。 +- `blockHash`:`DATA`,32 字节 -(可选,**未来**)添加 EIP-234 后,`blockHash` 将是一个新的过滤器选项,它会将返回的日志限制为具有 32 字节哈希 `blockHash` 的单一区块。 使用 `blockHash` 相当于 `fromBlock` = `toBlock` = 哈希为 `blockHash` 的区块编号。 如果 `blockHash` 出现在筛选条件中,则 `fromBlock` 和 `toBlock` 都不允许使用。 ```js params: [ @@ -1614,24 +1736,25 @@ params: [ ] ``` -**返回值** 参见 [eth_getFilterChanges](#eth_getfilterchanges) +**返回值** +请参阅 [eth_getFilterChanges](#eth_getfilterchanges) **示例** ```js -// Request +// 请求 curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"topics":["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]}],"id":74}' ``` -结果参见 [eth_getFilterChanges](#eth_getfilterchanges) +结果请参阅 [eth_getFilterChanges](#eth_getfilterchanges) -## 使用示例 {#usage-example} +## 用法示例 {#usage-example} ### 使用 JSON_RPC 部署合约 {#deploying-contract} -本节演示如何仅使用远程过程调用接口部署合约。 一些其他部署合约的途径可以消除这种复杂性 — 例如,使用在远程过程调用接口之上构建的库,如 [web3.js](https://web3js.readthedocs.io/) 和 [web3.py](https://github.com/ethereum/web3.py)。 这些简化通常更容易理解且不易出错,但了解幕后发生的操作仍然很有帮助。 +本节演示如何仅使用远程过程调用接口部署合约。 部署合约还有其他途径,可以省去这些复杂的步骤,例如使用构建在 RPC 接口之上的程序库,如 [web3.js](https://web3js.readthedocs.io/) 和 [web3.py](https://github.com/ethereum/web3.py)。 这些简化通常更容易理解且不易出错,但了解幕后发生的操作仍然很有帮助。 -以下是一个名为 `Multiply7` 的简单智能合约,将使用 JSON-RPC 接口将其部署到以太坊节点。 本教程假设读者已经在运行 Geth 节点。 [此处](/developers/docs/nodes-and-clients/run-a-node)提供了更多关于节点和客户端的信息。 请参阅单独的[客户端](/developers/docs/nodes-and-clients/)文档,了解如何为非 Geth 客户端启动超文本传输协议 JSON-RPC。 大多数客户端默认在 `localhost:8545` 上提供服务。 +以下是一个名为 `Multiply7` 的简单智能合约,将使用 JSON-RPC 接口将其部署到以太坊节点。 本教程假设读者已经在运行 Geth 节点。 更多关于节点和客户端的信息请见[此处](/developers/docs/nodes-and-clients/run-a-node)。 请参阅各个[客户端](/developers/docs/nodes-and-clients/)文档,了解如何为非 Geth 客户端启动 HTTP JSON-RPC。 大多数客户端默认在 `localhost:8545` 上提供服务。 ```javascript contract Multiply7 { @@ -1649,12 +1772,12 @@ contract Multiply7 { geth --http --dev console 2>>geth.log ``` -这将在 `http://localhost:8545` 上启动超文本传输协议远程过程调用接口。 +这将在 `http://localhost:8545` 上启动 HTTP RPC 接口。 -我们可以使用 [curl](https://curl.se) 检索 coinbase 地址(获取帐户数组的第一个地址)和余额来验证接口是否正常运行。 请注意,这些示例中的数据在你的本地节点上会有所不同。 如果你想尝试这些命令,请将第二个 curl 请求中的请求参数替换为第一个 curl 请求返回的结果。 +我们可以使用 [curl](https://curl.se) 检索 coinbase 地址(通过获取帐户数组的第一个地址)和余额来验证接口是否正在运行。 请注意,这些示例中的数据在你的本地节点上会有所不同。 如果你想尝试这些命令,请将第二个 curl 请求中的请求参数替换为第一个 curl 请求返回的结果。 ```bash -curl --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[]", "id":1}' -H "Content-Type: application/json" localhost:8545 +curl --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[], "id":1}' -H "Content-Type: application/json" localhost:8545 {"id":1,"jsonrpc":"2.0","result":["0x9b1d35635cc34752ca54713bb99d38614f63c955"]} curl --data '{"jsonrpc":"2.0","method":"eth_getBalance", "params": ["0x9b1d35635cc34752ca54713bb99d38614f63c955", "latest"], "id":2}' -H "Content-Type: application/json" localhost:8545 @@ -1668,9 +1791,9 @@ web3.fromWei("0x1639e49bba16280000", "ether") // "410" ``` -现在我们的私有开发链上有一些以太币,我们可以部署合约了。 第一步是将 Multiply7 合约编译为可以发送到以太坊虚拟机的字节码。 要安装 Solidity 编译器 solc,请遵循 [Solidity 文档](https://docs.soliditylang.org/en/latest/installing-solidity.html)。 (你可能希望使用较旧的 `solc` 版本来匹配[我们的示例中使用的编译器版本](https://github.com/ethereum/solidity/releases/tag/v0.4.20)。) +现在我们的私有开发链上有一些以太币,我们可以部署合约了。 第一步是将 Multiply7 合约编译为可以发送到以太坊虚拟机的字节码。 要安装 Solidity 编译器 solc,请遵照 [Solidity 文档](https://docs.soliditylang.org/en/latest/installing-solidity.html)。 (你可能希望使用较旧的 `solc` 版本来匹配[我们示例中使用的编译器版本](https://github.com/ethereum/solidity/releases/tag/v0.4.20)。) -下一步是将 Multiply7 合约编译为可以发送到以太坊虚拟机的字节码。 +下一步是将 Multiply7 合约编译成可以发送给以太坊虚拟机的字节码。 ```bash echo 'pragma solidity ^0.4.16; contract Multiply7 { event Print(uint); function multiply(uint input) public returns (uint) { Print(input * 7); return input * 7; } }' | solc --bin @@ -1680,7 +1803,7 @@ Binary: 6060604052341561000f57600080fd5b60eb8061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b60007f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da600783026040518082815260200191505060405180910390a16007820290509190505600a165627a7a7230582040383f19d9f65246752244189b02f56e8d0980ed44e7a56c0b200458caad20bb0029 ``` -现在我们有了编译后的代码,我们需要确定部署它需要花费多少燃料。 远程过程调用接口有一个 `eth_estimateGas` 方法,可以给我们一个估算值。 +现在我们有了编译后的代码,我们需要确定部署它需要花费多少燃料。 RPC 接口有一个 `eth_estimateGas` 方法,可以给我们一个估算值。 ```bash curl --data '{"jsonrpc":"2.0","method": "eth_estimateGas", "params": [{"from": "0x9b1d35635cc34752ca54713bb99d38614f63c955", "data": "0x6060604052341561000f57600080fd5b60eb8061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b60007f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da600783026040518082815260200191505060405180910390a16007820290509190505600a165627a7a7230582040383f19d9f65246752244189b02f56e8d0980ed44e7a56c0b200458caad20bb0029"}], "id": 5}' -H "Content-Type: application/json" localhost:8545 @@ -1694,7 +1817,8 @@ curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from {"id":6,"jsonrpc":"2.0","result":"0xe1f3095770633ab2b18081658bad475439f6a08c902d0915903bafff06e6febf"} ``` -交易被节点接受并返回交易哈希。 此哈希可用于跟踪交易。 下一步是确定我们的合约部署到的地址。 每个已执行的交易都将创建一个收据。 此收据包含有关交易的各种信息,例如交易包含在哪个区块中以及以太坊虚拟机使用了多少燃料。 如果交易 创建了合约,它还将包含合约地址。 我们可以使用远程过程调用方法 `eth_getTransactionReceipt` 检索收据。 +交易被节点接受并返回交易哈希。 此哈希可用于跟踪交易。 下一步是确定我们的合约部署到的地址。 每个已执行的交易都将创建一个收据。 此收据包含有关交易的各种信息,例如交易包含在哪个区块中以及以太坊虚拟机使用了多少燃料。 如果交易 +创建了合约,它还将包含合约地址。 我们可以使用 `eth_getTransactionReceipt` RPC 方法检索收据。 ```bash curl --data '{"jsonrpc":"2.0","method": "eth_getTransactionReceipt", "params": ["0xe1f3095770633ab2b18081658bad475439f6a08c902d0915903bafff06e6febf"], "id": 7}' -H "Content-Type: application/json" localhost:8545 @@ -1707,7 +1831,7 @@ curl --data '{"jsonrpc":"2.0","method": "eth_getTransactionReceipt", "params": [ 在本示例中,我们将使用 `eth_sendTransaction` 将交易发送到合约的 `multiply` 方法。 -`eth_sendTransaction` 需要几个参数,具体而言,`from`、`to` 和 `data`。 `From` 是我们帐户的公共地址,`to` 是合约地址。 `data` 参数包含有效载荷,它定义了必须调用哪个方法以及使用哪些参数。 这就是 [ABI(应用程序二进制接口)](https://docs.soliditylang.org/en/latest/abi-spec.html)的用武之地。 应用程序二进制接口是一个 JSON 文件,它定义了如何为以太坊虚拟机定义和编码数据。 +`eth_sendTransaction` 需要几个参数,具体而言,`from`、`to` 和 `data`。 `From` 是我们帐户的公共地址,`to` 是合约地址。 `data` 参数包含有效载荷,它定义了必须调用哪个方法以及使用哪些参数。 这就是 [ABI(应用程序二进制接口)](https://docs.soliditylang.org/en/latest/abi-spec.html)发挥作用的地方。 应用程序二进制接口是一个 JSON 文件,它定义了如何为以太坊虚拟机定义和编码数据。 有效载荷的字节定义了调用合约中的哪个方法。 这是函数名称及其参数类型的 Keccak 哈希的前 4 个字节(十六进制编码)。 Multiply 函数接受 uint,它是 uint256 的别名。 这为我们提供了: @@ -1718,7 +1842,7 @@ web3.sha3("multiply(uint256)").substring(0, 10) 下一步是对参数进行编码。 只有一个 uint256,比如值 6。 应用程序二进制接口有一个部分指定了如何编码 uint256 类型。 -`int: enc(X)` 是 X 的大端序二进制补码编码,对于负 X 在高位(左侧)填充 0xff,对于正 X 填充零 > 字节,使得长度为 32 字节的倍数。 +`int: enc(X)` 是 X 的大端序二进制补码编码,对于负 X 在高位(左侧)填充 0xff,对于正 X 填充零字节,使得长度为 32 字节的倍数。 此编码为 `0000000000000000000000000000000000000000000000000000000000000006`。 @@ -1755,7 +1879,7 @@ curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from } ``` -收据中包含一个日志。 此日志由以太坊虚拟机在交易执行时生成并包含在收据中。 `multiply` 函数显示 `Print` 事件在输入乘以 7 时触发。 由于 `Print` 事件的参数是 uint256,我们可以根据应用程序二进制接口规则对其进行解码,这将为我们提供预期的十进制数 42。 除了数据之外,值得注意的是,主题可用于确定哪个事件创建了日志: +收据中包含一个日志。 此日志由以太坊虚拟机在交易执行时生成并包含在收据中。 `multiply` 函数显示 `Print` 事件在输入乘以 7 时触发。 由于 `Print` 事件的参数是 uint256,我们可以根据 ABI 规则对其进行解码,这将为我们提供预期的十进制数 42。 除了数据之外,值得注意的是,主题可用于确定哪个事件创建了日志: ```javascript web3.sha3("Print(uint256)") @@ -1764,10 +1888,10 @@ web3.sha3("Print(uint256)") 以上只是对一些最常见任务的简要介绍,展示了 JSON-RPC 的直接用法。 -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [JSON-RPC 规范](http://www.jsonrpc.org/specification) - [节点和客户端](/developers/docs/nodes-and-clients/) - [JavaScript API](/developers/docs/apis/javascript/) -- [后端应用程序接口](/developers/docs/apis/backend/) +- [后端 API](/developers/docs/apis/backend/) - [执行客户端](/developers/docs/nodes-and-clients/#execution-clients) diff --git a/public/content/translations/zh/developers/docs/blocks/index.md b/public/content/translations/zh/developers/docs/blocks/index.md index cb59f2c7d6f..977d27be294 100644 --- a/public/content/translations/zh/developers/docs/blocks/index.md +++ b/public/content/translations/zh/developers/docs/blocks/index.md @@ -1,6 +1,6 @@ --- -title: 区块 -description: 以太坊区块链中区块的概述 – 其数据结构、存在的意义以及区块如何生成 +title: "区块" +description: "以太坊区块链中区块的概述 – 其数据结构、存在的意义以及区块如何生成" lang: zh --- @@ -8,55 +8,55 @@ lang: zh ## 前提条件 {#prerequisites} -区块是一个对初学者非常友好的主题。 为了帮助你更好地理解这个页面,我们建议你先阅读[帐户](/developers/docs/accounts/)、[交易](/developers/docs/transactions/)和我们的[以太坊简介](/developers/docs/intro-to-ethereum/)。 +区块是一个对初学者非常友好的主题。 为了更好地理解本页内容,我们建议您先阅读[帐户](/developers/docs/accounts/)、[交易](/developers/docs/transactions/)以及我们的[以太坊简介](/developers/docs/intro-to-ethereum/)。 ## 为什么要有区块? {#why-blocks} 为了确保以太坊网络上的所有参与者保持同步状态并就交易的确切历史达成共识,我们将交易分为多个区块。 这意味着同时有数十个(甚至数百个)交易被提交、达成一致并同步。 -![区块中的交易导致状态变化的图表](./tx-block.png) _示意图节选自[以太坊虚拟机图解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![显示区块中交易导致状态变化的示意图](./tx-block.png)\n_示意图改编自 [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ 通过间隔提交,所有网络参与者有足够时间达成共识:即使交易请求每秒发生数十次,但以太坊上的区块仅仅大约每十二秒创建并提交一次。 -## 区块如何工作 {#how-blocks-work} +## 区块如何运作 {#how-blocks-work} 为了保存交易历史,区块被严格排序(创建的每个新区块都包含一个其父块的引用),区块内的交易也严格排序。 除极少数情况外,在任何特定时间,网络上的所有参与者都同意区块的确切数目和历史, 并且正在努力将当前的活动交易请求分批到下一个区块。 随机选择的验证者在网络上构建完区块后,该区块将传播到整个网络;所有节点都将该区块添加至其区块链的末尾,然后挑选新的验证者来创建下一个区块。 目前,确切的区块构建过程和提交/共识过程由以太坊的“权益证明”协议规定。 -## 权益证明协议 {#proof-of-work-protocol} +## 权益证明协议 {#proof-of-stake-protocol} 权益证明是指: - 验证节点必须向存款合约中质押 32 个以太币,作为抵押品防止发生不良行为。 这有助于保护网络,因为如果发生不诚实活动且可以证实,部分甚至全部质押金额将被销毁。 - 在每个时隙(12 秒的时间间隔)中,会随机选择一个验证者作为区块提议者。 他们将交易打包并执行,然后确定一个新的“状态”。 他们将这些信息包装到一个区块中并传送给其他验证者。 -- 其他获悉新区块的验证者再次执行区块中包含的交易,确定他们同意对全局状态提出的修改。 假设该区块是有效的,验证者就将该区块添加进各自的数据库。 +- 其他获悉新区块的验证者会重新执行这些交易,以确保他们同意对全局状态的提议更改。 假设该区块有效,他们就会将其添加到自己的数据库中。 - 如果验证者获悉在同一时隙内有两个冲突区块,他们会使用自己的分叉选择算法选择获得最多质押以太币支持的那一个区块。 -[有关权益证明的更多信息](/developers/docs/consensus-mechanisms/pos) +[关于权益证明的更多信息](/developers/docs/consensus-mechanisms/pos) ## 区块包含什么? {#block-anatomy} 一个区块中包含很多信息。 区块的最高层包含以下字段: -| 字段 | 简介 | -|:---------------- |:-------------- | +| 字段 | 描述 | +| :--------------- | :------------- | | `时隙` | 区块所属的时隙 | | `proposer_index` | 提出区块的验证者的 ID | | `parent_root` | 上一个区块的哈希 | | `state_root` | 状态对象的根哈希 | | `正文` | 包含多个字段的对象,定义如下 | -区块的 `body` 包含一些自有字段: +区块 `body` 本身包含几个字段: -| 栏目 | 简介 | -|:-------------------- |:-------------- | +| 字段 | 描述 | +| :------------------- | :------------- | | `randao_reveal` | 用于选择下一个区块提议者的值 | | `eth1_data` | 关于存款合约的信息 | -| `涂鸦` | 用于标记区块的任意数据 | +| `graffiti` | 用于标记区块的任意数据 | | `proposer_slashings` | 将要惩罚的验证者列表 | | `attester_slashings` | 将要受到惩没的证明者列表 | -| `认证` | 支持当前区块的认证列表 | +| `认证` | 针对之前时隙所做认证的列表 | | `存款` | 存款合约新增存款的列表 | | `voluntary_exits` | 退出网络的验证者列表 | | `sync_aggregate` | 用于服务轻客户端的验证者子集 | @@ -64,29 +64,29 @@ lang: zh `attestations` 字段包含区块中所有认证的列表。 认证有自己的数据类型,其中包含多条数据。 每个认证包含: -| 栏目 | 简介 | -|:------------------ |:------------ | -| `aggregation_bits` | 参与此认证的验证者列表 | -| `数据` | 具有多个子字段的容器 | -| `签名` | 所有证明验证者的聚合签名 | +| 字段 | 描述 | +| :----------------- | :--------------------- | +| `aggregation_bits` | 参与此认证的验证者列表 | +| `数据` | 具有多个子字段的容器 | +| `签名` | 一组验证者针对 `data` 部分的聚合签名 | `attestation` 中的 `data` 字段包含以下内容: -| 栏目 | 简介 | -|:------------------- |:-------------- | +| 字段 | 描述 | +| :------------------ | :------------- | | `时隙` | 认证所涉及的时隙 | | `索引` | 证明验证者的索引 | -| `beacon_block_root` | 包含此对象的信标区块的根哈希 | +| `beacon_block_root` | 被视为链头的信标区块的根哈希 | | `来源` | 最后一个合理的检查点 | | `target` | 最新的时段边界区块 | -执行 `execution_payload` 中的交易会更新全局状态。 所有客户端重新执行 `execution_payload` 中的交易,以确保新状态与新区块 `state_root` 字段中的状态相符。 这就是客户端如何判断新区块是否有效且可以安全添加到其区块链的方式。 `execution payload` 本身是一个包含多个字段的对象。 还有一个 `execution_payload_header`,包含有关执行数据的重要摘要信息。 这些数据结构如下组织: +执行 `execution_payload` 中的交易会更新全局状态。 所有客户端都会重新执行 `execution_payload` 中的交易,以确保新状态与新区块 `state_root` 字段中的状态相符。 这就是客户端如何判断新区块是否有效且可以安全添加到其区块链的方式。 `execution payload` 本身是一个包含多个字段的对象。 还有一个 `execution_payload_header`,其中包含关于执行数据的重要摘要信息。 这些数据结构如下组织: `execution_payload_header` 包含以下字段: -| 领域 | 简介 | -|:------------------- |:------------------- | -| `父_哈希值` | 父块的哈希值 | +| 字段 | 描述 | +| :------------------ | :------------------ | +| `parent_hash` | 父块的哈希值 | | `fee_recipient` | 向其支付交易费的帐户地址 | | `state_root` | 应用此区块中的更改后,全局状态的根哈希 | | `receipts_root` | 交易收据树的哈希 | @@ -95,39 +95,39 @@ lang: zh | `block_number` | 当前区块的编号 | | `gas_limit` | 此区块允许的最大燃料量 | | `gas_used` | 此区块中使用的实际燃料量 | -| `时间戳` | 区块时间 | +| `timestamp` | 区块时间 | | `extra_data` | 作为原始字节的任意附加数据 | | `base_fee_per_gas` | 基础费值 | | `block_hash` | 执行区块的哈希 | | `transactions_root` | 有效载荷中交易的根哈希 | | `withdrawal_root` | 有效负载中提款的根哈希 | -`execution_payload` 本身包含以下字段(请注意这与 header 相同,只是它包含的不是交易的根哈希,而是实际的交易列表和提款信息列表): - -| 栏目 | 简介 | -|:------------------ |:------------------ | -| `父_哈希值` | 父块的哈希值 | -| `fee_recipient` | 支付交易费用的帐户地址 | -| `state_root` | 应用此区块中的更改后,全局的根哈希值 | -| `receipts_root` | 交易收据的哈希值 | -| `logs_bloom` | 包含事件日志的数据结构 | -| `prev_randao` | 在随机验证者选择中使用的值 | -| `block_number` | 当前区块的编号 | -| `gas_limit` | 此区块允许的最大的燃料量 | -| `gas_used` | 此区块中使用的燃料实际量 | -| `时间戳` | 区块时间 | -| `extra_data` | 作为原始字节任意附加数据 | -| `base_fee_per_gas` | 基本费用值 | -| `block_hash` | 执行区块的哈希值 | -| `交易` | 要执行交易的列表 | -| `提款` | 提款对象列表 | - -`Withdrawals` 列表包含了 `withdrawal` 对象,结构如下: +`execution_payload` 本身包含以下内容(请注意,这与标头相同,只是它不包含交易的根哈希,而是包含实际的交易列表和提款信息列表): + +| 字段 | 描述 | +| :----------------- | :------------------ | +| `parent_hash` | 父块的哈希值 | +| `fee_recipient` | 向其支付交易费的帐户地址 | +| `state_root` | 应用此区块中的更改后,全局状态的根哈希 | +| `receipts_root` | 交易收据树的哈希 | +| `logs_bloom` | 包含事件日志的数据结构 | +| `prev_randao` | 在随机选择验证者时使用的值 | +| `block_number` | 当前区块的编号 | +| `gas_limit` | 此区块允许的最大燃料量 | +| `gas_used` | 此区块中使用的实际燃料量 | +| `timestamp` | 区块时间 | +| `extra_data` | 作为原始字节的任意附加数据 | +| `base_fee_per_gas` | 基础费值 | +| `block_hash` | 执行区块的哈希 | +| `交易` | 要执行交易的列表 | +| `取款` | 提款对象列表 | + +`withdrawals` 列表包含按以下方式结构的 `withdrawal` 对象: | 字段 | 描述 | -|:---------------- |:------ | +| :--------------- | :----- | | `地址` | 提款帐户地址 | -| `amount` | 提款金额 | +| `金额` | 提款金额 | | `索引` | 提款索引值 | | `validatorIndex` | 验证者索引值 | @@ -135,17 +135,17 @@ lang: zh 区块时间是指两个区块之间的时间间隔。 在以太坊中,时间划分为每 12 秒一个单位,称为“时隙”。 在每个时隙内,选择一个单独的验证者提议区块。 假设所有验证者都在线且完全正常运行,则每个时隙内都会有一个区块产生,意味着区块时间是 12 秒。 但是,偶尔验证者在被要求提议区块时不在线,导致有时候一些时隙是空的。 -这种实现与基于工作量证明的系统不同。在工作量证明系统中,区块时间是带有概率性的,并由协议的目标挖矿难度调节。 以太坊的[平均区块时间](https://etherscan.io/chart/blocktime)是一个很好的例子,根据不变的新的 12 秒区块时间,可以清楚地推断出从工作量证明到权益证明的过渡。 +这种实现与基于工作量证明的系统不同。在工作量证明系统中,区块时间是带有概率性的,并由协议的目标挖矿难度调节。 以太坊的[平均区块时间](https://etherscan.io/chart/blocktime)就是一个很好的例子,基于新的 12 秒区块时间的一致性,可以清楚地推断出从工作量证明到权益证明的过渡。 ## 区块大小 {#block-size} -最后一条重要提示是,区块本身的大小是有界限的。 每个区块的目标大小为 3000 万单位燃料,但区块的大小将根据网络需求而增加或减少,直至达到 6000 万单位燃料的区块限制(目标区块大小的 2 倍)。 区块的燃料限制可以相对于上一个区块的燃料限制上调或下调 1/1024 的比例。 因此,验证者可以通过共识来改变区块的燃料限制。 区块中所有交易消耗的总燃料量必须低于区块的燃料限制。 这很重要,因为它可以确保区块不能任意扩大。 如果区块可以任意扩大,由于空间和速度方面的要求,性能较差的全节点将逐渐无法跟上网络。 区块越大,在下一个时隙中及时处理它们需要的算力就越强大。 这是一种集中化的因素,可以通过限制区块大小来抵制。 +最后一条重要提示是,区块本身的大小是有界限的。 每个区块的目标大小为 3000 万单位燃料,但区块的大小会根据网络需求增加或减少,直到达到 6000 万单位燃料的区块限制(目标区块大小的 2 倍)。 区块的燃料限制可以相对于上一个区块的燃料限制上调或下调 1/1024 的比例。 因此,验证者可以通过共识来改变区块的燃料限制。 区块中所有交易消耗的总燃料量必须低于区块的燃料限制。 这很重要,因为它可以确保区块不能任意扩大。 如果区块可以任意扩大,由于空间和速度方面的要求,性能较差的全节点将逐渐无法跟上网络。 区块越大,在下一个时隙中及时处理它们需要的算力就越强大。 这是一种集中化的因素,可以通过限制区块大小来抵制。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [交易](/developers/docs/transactions/) - [燃料](/developers/docs/gas/) diff --git a/public/content/translations/zh/developers/docs/bridges/index.md b/public/content/translations/zh/developers/docs/bridges/index.md index 2b94f0f5edc..150c59f9d2b 100644 --- a/public/content/translations/zh/developers/docs/bridges/index.md +++ b/public/content/translations/zh/developers/docs/bridges/index.md @@ -1,10 +1,10 @@ --- -title: 链桥 -description: 面向开发者的桥接概述 +title: "链桥" +description: "面向开发者的桥接概述" lang: zh --- -随着一层网络区块链和二层网络[扩容](/developers/docs/scaling/)解决方案的激增,以及越来越多的去中心化应用程序跨链,跨链通信和资产转移需求已成为网络基础设施的重要组成部分。 存在不同类型的链桥就是为了帮助解决这种需求。 +随着 L1 区块链和 L2 [扩容](/developers/docs/scaling/)解决方案的激增,以及越来越多的去中心化应用程序走向跨链,跨链通信和资产转移的需求已成为网络基础设施的重要组成部分。 存在不同类型的链桥就是为了帮助解决这种需求。 ## 对链桥的需求 {#need-for-bridges} @@ -12,9 +12,9 @@ lang: zh 区块链存在于孤立的环境中,这意味着区块链之间本来就无法进行交易和通信。 因此,虽然某个生态系统内可能存在大量的活动和创新,但它会由于缺乏与其他生态系统的连通性和互操作性而受到限制。 -链桥提供了一种让孤立的区块链环境相互连通的途径。 它们在区块链之间建立了一条传输路线,让代币、信息、任意数据甚至[智能合约](/developers/docs/smart-contracts/)调用都可以从一条区块链转移到另一条。 +链桥提供了一种让孤立的区块链环境相互连通的途径。 它们在区块链之间建立了一条传输路线,让代币、消息、任意数据,甚至[智能合约](/developers/docs/smart-contracts/)调用都可以从一条链转移到另一条链。 -## 链桥的优点 {#benefits-of-bridges} +## 链桥的优势 {#benefits-of-bridges} 简而言之,链桥解锁了大量应用场景,它允许区块链网络之间交换数据和转移资产。 @@ -30,63 +30,63 @@ lang: zh ## 链桥是如何工作的? {#how-do-bridges-work} -虽然[链桥设计](https://li.fi/knowledge-hub/blockchain-bridges-and-classification/)多种多样,但以下三种方便资产跨链转移的方法脱颖而出: +虽然有许多[链桥设计类型](https://li.fi/knowledge-hub/blockchain-bridges-and-classification/),但有三种促进资产跨链转移的方法脱颖而出: -- **锁定并铸币 – **锁定源链上的资产并在目标链上铸币。 -- **销毁并铸币 – **销毁源链上的资产并在目标链上铸币。 -- **原子交换 – **通过第三方将源链上的资产与目标链上的资产交换。 +- **锁定并铸币 –** 在源链上锁定资产,并在目标链上铸造资产。 +- **销毁并铸币 –** 在源链上销毁资产,并在目标链上铸造资产。 +- **原子交换 –** 与另一方将源链上的资产交换为目标链上的资产。 ## 链桥类型 {#bridge-types} 链桥通常可以分为以下几类之一: -- **原生链桥 –** 这些链桥通常用于加强特定区块链上的流动性,使用户更容易将资金转移到生态系统。 例如,[Arbitrum 链桥](https://bridge.arbitrum.io/)的目的就是为了方便用户从以太坊主网桥接到 Arbitrum。 其他此链类桥包括 Polygon PoS 链桥、[Optimism 网关](https://app.optimism.io/bridge)等。 -- **基于验证者或预言机的链桥 –** 这些链桥依赖于外部验证者组或预言机来验证跨链转移。 例如:Multichain 与 Across。 -- **通用信息传递链桥 – **这些链桥可以跨链传输资产、信息和任意数据。 例如:Axelar、LayerZero 与 Nomad。 -- **流动性网络 –** 这些链桥主要是通过原子交换将资产从一条链转移到另一条链。 一般来讲,它们不支持跨链信息传递。 例如:Connext 与 Hop。 +- **原生链桥 –** 此类链桥通常旨在引导特定区块链上的流动性,方便用户将资金转移到生态系统。 例如,[Arbitrum 链桥](https://bridge.arbitrum.io/)的构建就是为了方便用户从以太坊主网桥接到 Arbitrum。 其他类似的链桥包括 Polygon PoS 链桥、[Optimism Gateway](https://app.optimism.io/bridge) 等。 +- **基于验证者或预言机的链桥 –** 此类链桥依赖于外部验证者集或预言机来验证跨链转账。 例如:Multichain 与 Across。 +- **通用消息传递链桥 –** 此类链桥可以跨链转移资产、消息和任意数据。 例如:Axelar、LayerZero 与 Nomad。 +- **流动性网络 –** 此类链桥主要通过原子交换将资产从一条链转移到另一条链。 一般来讲,它们不支持跨链信息传递。 例如:Connext 与 Hop。 -## 权衡利弊 {#trade-offs} +## 需要考虑的权衡因素 {#trade-offs} 没有完美的链桥解决方案。 有的只是为了实现目的而进行的权衡利弊。 开发者和用户可以根据以下因素评估链桥: - **安全性 –** 谁来验证系统? 通常,由外部验证者保护的链桥不如由区块链验证者在本地保护的链桥安全。 -- **便利性 –** 完成一笔交易需要多长时间,用户需要签署多少笔交易? 对于开发者来说,集成一个链桥需要多长时间,这个过程有多复杂? -- **连通性 –** 一个链桥可以连接哪些不同的目标链(卷叠、侧链、其他一层网络区块链等),集成一条新区块链有多难? -- **传递更复杂数据的能力 –** 链桥能够跨链传输信息和更复杂的任意数据,还是只支持跨链资产转移? +- **便利性 –** 完成一笔交易需要多长时间?用户需要签署多少笔交易? 对于开发者来说,集成一个链桥需要多长时间,这个过程有多复杂? +- **连通性 –** 链桥可以连接哪些不同的目标链(即 Rollup、侧链、其他 L1 区块链等)?集成一条新的区块链有多难? +- **传递更复杂数据的能力 –** 链桥能够实现跨链传递消息和更复杂的任意数据,还是只支持跨链资产转移? - **成本效益 –** 通过链桥跨链转移资产的成本是多少? 通常情况下,链桥收取固定或变动的费用,具体取决于燃料成本和特定路线的流动性。 根据确保链桥安全所需的资本来评估链桥的成本效益也是至关重要的。 在较高层面上,链桥可以分为需信任链桥和去信任链桥。 -- **需信任链桥 –** 需信任链桥由外部验证。 它们使用一组外部验证者(具有多重签名的联盟、多方计算系统、预言机网络)跨链发送数据。 因此,它们可以提供出色的连通性,并完全支持跨链通用信息传递。 在速度和成本效益方面它们通常也表现良好。 但这些是以安全性为代价的,因为用户必须依赖链桥的安全性。 -- **去信任 –** 这类链桥依靠它们连接的区块链及其验证者来传输信息和代币。 它们是“去信任”的,因为它们没有增加新的信任假设(区块链除外)。 因此,我们认为去信任链桥比可信链桥更安全。 +- **需信任 –** 需信任链桥由外部验证。 它们使用一组外部验证者(具有多重签名的联盟、多方计算系统、预言机网络)跨链发送数据。 因此,它们可以提供出色的连通性,并完全支持跨链通用信息传递。 在速度和成本效益方面它们通常也表现良好。 但这些是以安全性为代价的,因为用户必须依赖链桥的安全性。 +- **无需信任 –** 此类链桥依赖其连接的区块链及其验证者来转移消息和代币。 它们是“去信任”的,因为它们没有增加新的信任假设(区块链除外)。 因此,我们认为去信任链桥比可信链桥更安全。 为了根据其他因素评估去信任链桥,我们须将其分为通用信息传递链桥和流动性网络。 -- **通用信息传递链桥 –** 这些链桥在安全性和跨链传输更复杂数据的能力方面表现卓越。 通常,它们还具有良好的成本效益。 然而,这些优点通常以轻客户端链桥(例如 IBC)的连通性以及使用欺诈证明的乐观链桥(例如 Nomad)的速度劣势作为代价。 -- **流动性网络 –** 这些链桥使用原子交换转移资产,并且是本地验证系统(即,它们使用底层区块链的验证者验证交易)。 因此,它们在安全性和速度方面表现出色。 此外,流动性网络具有不错的成本效益和良好的连通性。 然而,最大的折衷之处是它们无法传递更复杂的数据 — 因为它们不支持跨链信息传递。 +- **通用消息传递链桥 –** 此类链桥在安全性和跨链传递更复杂数据的能力方面表现出色。 通常,它们还具有良好的成本效益。 然而,这些优点通常以轻客户端链桥(例如 IBC)的连通性以及使用欺诈证明的乐观链桥(例如 Nomad)的速度劣势作为代价。 +- **流动性网络 –** 此类链桥使用原子交换来转移资产,是本地验证的系统(即它们使用底层区块链的验证者来验证交易)。 因此,它们在安全性和速度方面表现出色。 此外,流动性网络具有不错的成本效益和良好的连通性。 然而,最大的折衷之处是它们无法传递更复杂的数据 — 因为它们不支持跨链信息传递。 -## 链桥相关风险 {#risk-with-bridges} +## 链桥的风险 {#risk-with-bridges} -去中心化金融领域中[最大的三次黑客攻击](https://rekt.news/leaderboard/)都是链桥造成的,而且链桥目前仍处于开发阶段早期。 使用任何链桥都有以下风险: +在 [DeFi 领域最大的几起黑客攻击](https://rekt.news/leaderboard/)中,排名前三的都与链桥有关,而且链桥仍处于早期开发阶段。 使用任何链桥都有以下风险: -- **智能合约风险 –** 虽然许多链桥已经成功通过了审计,但只需智能合约中的一个缺陷就会使资产暴露在黑客攻击中(例如:[Solana 的 Wormhole 链桥](https://rekt.news/wormhole-rekt/))。 -- **系统性金融风险** – 许多链桥使用包装资产在新的链上铸造规范化的原始资产。 这使生态系统面临系统性风险,正如我们所看到的那样,包装代币遭到利用。 -- **交易对手风险 –** 一些链桥采用可信设计,这要求用户依靠一种假设,即验证者不会串通起来窃取用户的资金。 用户需要信任这些第三方参与者,这使他们面临一些风险,比如跑路、审查和其他恶意活动。 -- **未解决的问题 –** 考虑到链桥处于发展阶段初期,还有许多关于链桥在不同市场条件下如何表现的问题都尚未解决,如网络拥塞期和在发生网络级攻击或状态回滚等不可预见的事件时。 这种不确定性带来了一定的风险,且风险程度目前仍然未知。 +- **智能合约风险 –** 虽然许多链桥已成功通过审计,但智能合约中的一个漏洞就足以让资产面临被黑客攻击的风险(例如:[Solana 的 Wormhole 链桥](https://rekt.news/wormhole-rekt/))。 +- **系统性金融风险 –** 许多链桥使用封装资产在新的链上铸造原始资产的规范版本。 这使生态系统面临系统性风险,正如我们所看到的那样,包装代币遭到利用。 +- **交易对手风险 –** 一些链桥采用需信任的设计,要求用户依赖“验证者不会合谋窃取用户资金”这一假设。 用户需要信任这些第三方参与者,这使他们面临一些风险,比如跑路、审查和其他恶意活动。 +- **未决问题 –** 鉴于链桥仍处于起步阶段,关于它们在不同市场条件下的表现,仍有许多悬而未决的问题,例如在网络拥堵、网络级攻击或状态回滚等意外事件期间。 这种不确定性带来了一定的风险,且风险程度目前仍然未知。 ## 去中心化应用程序如何使用链桥? {#how-can-dapps-use-bridges} 下面介绍一些实际应用,在这些应用中,开发者可以考虑链桥并让他们的去中心化应用程序跨链: -### 集成桥接 {#integrating-bridges} +### 集成链桥 {#integrating-bridges} 对于开发者来说,有很多方法可以添加对链桥的支持: -1. **构建自己的链桥 –** 构建安全可靠的链桥并不容易,特别是在选择一种进一步将信任最小化的方式时。 此外,还需要与可伸缩性和互操作性研究相关的多年经验和技术专长。 另外,还需要一支亲力亲为的团队来维护链桥,并吸引足够的流动性使其可行。 +1. **构建自己的链桥 –** 构建安全可靠的链桥并非易事,尤其是在采用更加信任最小化的路线时。 此外,还需要与可伸缩性和互操作性研究相关的多年经验和技术专长。 另外,还需要一支亲力亲为的团队来维护链桥,并吸引足够的流动性使其可行。 -2. **向用户展示多种链桥选项 –** 很多[去中心化应用程序](/developers/docs/dapps/)要求用户拥有原生代币才可与它们交互。 为了使用户能够访问他们的代币,去中心化应用程序在其网站上提供了不同的链桥选项。 然而,这种方法是权宜之计,因为它使用户离开去中心化应用程序界面但仍需要用户与其他去中心化应用程序和链桥交互。 这是一种繁琐的上手体验,会增加出错的范围。 +2. **向用户显示多种链桥选项 –** 许多[去中心化应用程序](/developers/docs/dapps/)都要求用户持有其原生代币才能进行交互。 为了使用户能够访问他们的代币,去中心化应用程序在其网站上提供了不同的链桥选项。 然而,这种方法是权宜之计,因为它使用户离开去中心化应用程序界面但仍需要用户与其他去中心化应用程序和链桥交互。 这是一种繁琐的上手体验,会增加出错的范围。 -3. **集成一个链桥 –**该解决方案不需要去中心化应用程序将用户发送到外部链桥和去中心化交易所接口。 这让去中心化应用程序能够改善用户的上手体验。 然而,这种方法有其局限性: +3. **集成一个链桥 –** 此解决方案不需要去中心化应用程序将用户引导至外部链桥和 DEX 界面。 这让去中心化应用程序能够改善用户的上手体验。 然而,这种方法有其局限性: - 链桥的评估和维护既困难又耗时。 - 选用一个链桥将造成单点故障和依赖性。 @@ -95,41 +95,44 @@ lang: zh 4. **集成多个链桥 –** 该解决方案解决了许多与集成单个链桥相关的问题。 然而,它也有局限性,因为集成多个链桥会消耗资源,并给开发者带来技术和通信开销 — 这是加密货币领域最稀缺的资源。 -5. **集成链桥聚合器 –** 去中心化应用程序另一个选择是集成链桥聚合解决方案,使它们能够访问多个链桥。 链桥聚合器继承了所有链桥的优点,因此不受任何单一链桥能力的限制。 值得注意的是,链桥聚合器通常维护链桥集成,这使去中心化应用程序避免了管控链桥集成技术和操作方面的麻烦。 +5. **集成链桥聚合器 –** 去中心化应用程序的另一个选择是集成链桥聚合解决方案,从而访问多个链桥。 链桥聚合器继承了所有链桥的优点,因此不受任何单一链桥能力的限制。 值得注意的是,链桥聚合器通常维护链桥集成,这使去中心化应用程序避免了管控链桥集成技术和操作方面的麻烦。 尽管如此,链桥聚合器也有其局限性。 比如说,虽然它们可以提供较多的链桥选择,但除了聚合器平台上提供的链桥外,市场上通常还有更多的链桥。 此外,像链桥一样,链桥聚合器也面临智能合约和技术风险(更多的智能合约 = 更多的风险)。 如果去中心化应用程序计划集成链桥或聚合器,那么根据集成的深度会有不同的选择。 例如,如果只是进行前端集成以改善用户上手体验,去中心化应用程序将集成小组件。 然而,如果整合是为了探索更深层次的跨链策略,如质押、流动性矿池等,去中心化应用程序就集成软件开发工具包或应用程序接口。 -### 在多条链上部署去中心化应用程序 {#deploying-a-dapp-on-multiple-chains} +### 在多个链上部署去中心化应用程序 {#deploying-a-dapp-on-multiple-chains} -要在多条链上部署去中心化应用程序 (dapp),开发者可以使用 [Alchemy](https://www.alchemy.com/)、[安全帽](https://hardhat.org/)和 [Moralis](https://moralis.io/) 等开发平台。 这些平台通常提供可组合的插件,能够支持去中心化应用程序跨链。 例如,开发者可以使用[安全帽部署插件](https://github.com/wighawag/hardhat-deploy)提供的确定性部署代理。 +要在多个链上部署去中心化应用程序,开发者可以使用 [Alchemy](https://www.alchemy.com/)、[Hardhat](https://hardhat.org/)、[Moralis](https://moralis.io/) 等开发平台。 这些平台通常提供可组合的插件,能够支持去中心化应用程序跨链。 例如,开发者可以使用 [Hardhat部署插件](https://github.com/wighawag/hardhat-deploy) 提供的确定性部署代理。 #### 例子: - [如何构建跨链去中心化应用程序](https://moralis.io/how-to-build-cross-chain-dapps/) -- [构建跨链非同质化代币市场](https://youtu.be/WZWCzsB1xUE) -- [Moralis:构建跨链非同质化代币去中心化应用程序](https://www.youtube.com/watch?v=ehv70kE1QYo) +- [构建跨链 NFT 市场](https://youtu.be/WZWCzsB1xUE) +- [Moralis:构建跨链 NFT 去中心化应用程序](https://www.youtube.com/watch?v=ehv70kE1QYo) ### 监控跨链合约活动 {#monitoring-contract-activity-across-chains} -要监控跨链合约活动,开发者可以使用子图和 Tenderly 等开发者平台实时观察智能合约。 这类平台上还有一些工具,提供更强大的跨链活动数据监控功能,例如,检查有没有[合约触发的事件](https://docs.soliditylang.org/en/v0.8.14/contracts.html?highlight=events#events)等。 +要监控跨链合约活动,开发者可以使用子图和 Tenderly 等开发者平台实时观察智能合约。 此类平台也有工具可以为跨链活动提供更强大的数据监控功能,例如检查[合约发出的事件](https://docs.soliditylang.org/en/v0.8.14/contracts.html?highlight=events#events)等。 #### 工具 -- [图表](https://thegraph.com/en/) +- [The Graph](https://thegraph.com/en/) - [Tenderly](https://tenderly.co/) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [区块链链桥](/bridges/) — ethereum.org -- [区块链链桥:构建加密网络的网络](https://medium.com/1kxnetwork/blockchain-bridges-5db6afac44f8) 2021 年 9 月 8 日 - Dmitriy Berenzon -- [互操作性的三难困境](https://blog.connext.network/the-interoperability-trilemma-657c2cf69f17) 2021 年 10 月 1 日 – Arjun Bhuptani -- [群集:可信链桥和信任最小化链桥如何打造多链格局](https://blog.celestia.org/clusters/) 2021 年 10 月 4 日 – Mustafa Al-Bassam -- [LI.FI:有了链桥,信任就是一种范围](https://blog.li.fi/li-fi-with-bridges-trust-is-a-spectrum-354cd5a1a6d8) 2022 年 4 月 28 日 – Arjun Chand +- [区块链链桥](/bridges/) – ethereum.org +- [L2Beat 链桥风险框架](https://l2beat.com/bridges/summary) +- [区块链链桥:构建加密网络之网](https://medium.com/1kxnetwork/blockchain-bridges-5db6afac44f8) - 2021 年 9 月 8 日 – Dmitriy Berenzon +- [互操作性三难困境](https://blog.connext.network/the-interoperability-trilemma-657c2cf69f17) - 2021 年 10 月 1 日 – Arjun Bhuptani +- [集群:需信任链桥和信任最小化链桥如何塑造多链格局](https://blog.celestia.org/clusters/) - 2021 年 10 月 4 日 – Mustafa Al-Bassam +- [LI.FI:对于链桥,信任是一个谱系](https://blog.li.fi/li-fi-with-bridges-trust-is-a-spectrum-354cd5a1a6d8) - 2022 年 4 月 28 日 – Arjun Chand +- [Rollup 互操作性解决方案现状](https://web.archive.org/web/20250428015516/https://research.2077.xyz/the-state-of-rollup-interoperability) - 2024 年 6 月 20 日 – Alex Hook +- [利用共享安全实现安全的跨链互操作性:拉格朗日状态委员会及其他](https://web.archive.org/web/20250125035123/https://research.2077.xyz/harnessing-shared-security-for-secure-blockchain-interoperability) - 2024 年 6 月 12 日 – Emmanuel Awosika -此外,以下是 [James Prestwich](https://twitter.com/_prestwich) 的一些有颇有见解的讲解,可以帮助我们更深入地理解链桥: +此外,以下是 [James Prestwich](https://twitter.com/_prestwich) 的一些富有洞察力的演讲,可帮助您更深入地了解链桥: -- [构建链桥,而非构建有围墙的花园](https://youtu.be/ZQJWMiX4hT0) -- [破坏链桥](https://youtu.be/b0mC-ZqN8Oo) -- [为何链桥在销毁?](https://youtu.be/c7cm2kd20j8) +- [搭建桥梁,而非围墙花园](https://youtu.be/ZQJWMiX4hT0) +- [剖析链桥](https://youtu.be/b0mC-ZqN8Oo) +- [链桥为何在燃烧](https://youtu.be/c7cm2kd20j8) diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/index.md index 401a2d5fc06..9ccdddf6c10 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/index.md @@ -1,20 +1,20 @@ --- -title: 共识机制 -description: 解释分布式系统中的协商一致协议及其在以太坊中扮演的角色。 +title: "共识机制" +description: "解释分布式系统中的协商一致协议及其在以太坊中扮演的角色。" lang: zh --- -“共识机制”一词常常泛指“权益证明”、“工作量证明”或“权威证明”协议。 不过,这些协议只是共识机制的组成部分,用于防范[女巫攻击](/glossary/#sybil-attack)。 共识机制是由一整套想法、协议和激励构成的体系,使得一系列分布式节点能够就区块链状态达成一致。 +“共识机制”一词常常泛指“权益证明”、“工作量证明”或“权威证明”协议。 但是,它们只是共识机制中用于防御[女巫攻击](/glossary/#sybil-attack)的部分。 共识机制是由一整套想法、协议和激励构成的体系,使得一系列分布式节点能够就区块链状态达成一致。 ## 前提条件 {#prerequisites} -为了更好地理解此页面,我们建议你先阅读[以太坊简介](/developers/docs/intro-to-ethereum/)。 +为了更好地理解本页面,我们建议您先阅读我们的[以太坊简介](/developers/docs/intro-to-ethereum/)。 ## 什么是共识? {#what-is-consensus} 我们所说的共识,是指达成了广泛的一致。 比如,一群人去看电影, 如果他们对于提议“看某部电影”没有任何异议,那么就可以说共识达成了。 如果存在异议,那么他们就必须通过某种方法决定看哪一部电影。 在极端情况下,这群人就会分开。 -对于以太坊区块链来说,达成共识的过程是标准化的,达成共识意味着全网络中至少 66% 的节点就网络的全局状态达成一致。 +对于以太坊区块链来说,该过程是标准化的,达成共识意味着全网络中至少 66% 的节点就网络的全局状态达成一致。 ## 什么是共识机制? {#what-is-a-consensus-mechanism} @@ -28,21 +28,21 @@ lang: zh 这些部分共同组成了共识机制。 -## 共识机制类型 {#types-of-consensus-mechanisms} +## 共识机制的类型 {#types-of-consensus-mechanisms} ### 基于工作量证明 {#proof-of-work} -和比特币类似,以太坊也曾经使用基于**工作量证明 (PoW)** 的共识协议。 +与比特币类似,以太坊曾一度使用基于**工作量证明 (PoW)** 的共识协议。 #### 区块创建 {#pow-block-creation} 矿工相互竞争以创建新的包括已处理交易的区块。 优胜者将与网络中的其他矿工分享该新区块,以获得新铸造的以太币。 数学问题解决速度最快的计算机可以在比赛中获胜。 这将生成当前区块和之前的区块之间的加密链接。 解决此问题就是要在“工作量证明”中开展的工作了。 规范链随后由一条叉选择规则确定,该规则选择了一组区块,这些区块在挖矿方面做得最多。 -#### 安全性 {#pow-security} +#### 安全 {#pow-security} 因为用户需要拥有网络中 51% 的算力才能够欺骗整条链,因此网络的安全得以保证。 这将需要巨大的设备与能源投入,支出很有可能超过收益。 -关于[工作量证明](/developers/docs/consensus-mechanisms/pow/)的更多信息 +更多关于[工作量证明](/developers/docs/consensus-mechanisms/pow/) ### 基于权益证明 {#proof-of-stake} @@ -52,41 +52,41 @@ lang: zh 验证者创建区块。 每个时隙中都会随机选择一个验证者成为区块提议者。 区块提议者的共识客户端请求配对执行客户端对交易打包,作为“执行负载”。 然后它们将“执行负载”包装成共识数据并形成一个区块,再把这个区块发送给以太坊网络上的其他节点。 这样的区块生产会得到以太币奖励。 在极少数情况下,一个时隙中产生了多个可能的区块,或节点在不同时间收到区块,分叉选择算法就会选择使形成的链具有最大认证权重的那个区块(认证权重是指为该区块提供认证的验证者数量,并根据验证者质押的以太币余额调整)。 -#### 安全性 {#pos-security} +#### 安全 {#pos-security} 权益证明体系保障加密经济的安全,因为攻击者若试图控制整条链,就必须销毁大量以太币。 奖励机制会奖励诚实的质押人,而惩罚机制则阻止质押人作出恶意行为。 -有关[权益证明](/developers/docs/consensus-mechanisms/pos/)的更多信息 +更多关于[权益证明](/developers/docs/consensus-mechanisms/pos/) -### 直观指南 {#types-of-consensus-video} +### 视频指南 {#types-of-consensus-video} 观看视频,详细了解以太坊采用的不同类型共识机制: -### Sybil 抗性和链选择 {#sybil-chain} +### 抗女巫攻击与链选择 {#sybil-chain} 仅仅工作量证明和权益证明还不能成为共识协议,然而为了简便起见,通常将它们称为共识协议。 它们实际上是女巫攻击防御机制和区块作者选择器;它们是决定最新区块的作者的一种方式。 另一个重要组成部分是链选择(又称分叉选择)算法,它让节点可以在同一位置有多个区块的情况下在链头部选择一个正确区块。 -**女巫攻击防御**衡量一种协议如何抗衡女巫攻击。 防御这种攻击对去中心化区块链至关重要,并使矿工和验证者能够在资源投入的基础上获得平等奖励。 通过让用户消耗大量能源或提供大量抵押品,工作量证明和权益证明可以防止这种情况。 这些保护措施通过经济手段对女巫攻击形成威慑。 +**抗女巫攻击能力**衡量协议抵御女巫攻击的能力。 防御这种攻击对去中心化区块链至关重要,并使矿工和验证者能够在资源投入的基础上获得平等奖励。 通过让用户消耗大量能源或提供大量抵押品,工作量证明和权益证明可以防止这种情况。 这些保护措施通过经济手段对女巫攻击形成威慑。 -**链选择规则**用于决定哪条链才是“正确”的。 比特币使用“最长链”规则。这意味着,任何最长的区块链,都会被其他节点作为有效链接受并与之协作。 对于工作量证明链,最长链由链上累积的工作量证明总难度决定。 以太坊曾经也使用过最长链规则;然而权益证明机制下运行的以太坊采用了经过更新的分叉选择算法,衡量链的“权重”。 权重是验证者投票的累积总数,并以验证者质押的以太币余额加权。 +**链选择规则**用于决定哪条链是“正确”的链。 比特币使用“最长链”规则。这意味着,任何最长的区块链,都会被其他节点作为有效链接受并与之协作。 对于工作量证明链,最长链由链上累积的工作量证明总难度决定。 以太坊曾经也使用过最长链规则,但现在运行在权益证明机制下的以太坊采用了一种最新的分叉选择算法,以此衡量链的“权重”。 权重是验证者投票的累积总数,并以验证者质押的以太币余额加权。 -以太坊使用被称为 [Gasper](/developers/docs/consensus-mechanisms/pos/gasper/) 的共识机制,该机制结合了 [Casper 友好的最终确定性工具权益证明](https://arxiv.org/abs/1710.09437)和 [GHOST 分叉选择规则](https://arxiv.org/abs/2003.03052)。 +以太坊使用一种称为 [Gasper](/developers/docs/consensus-mechanisms/pos/gasper/) 的共识机制,它将 [Casper FFG 权益证明](https://arxiv.org/abs/1710.09437)与 [GHOST 分叉选择规则](https://arxiv.org/abs/2003.03052)相结合。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [什么是区块链共识算法?](https://academy.binance.com/en/articles/what-is-a-blockchain-consensus-algorithm) -- [什么是 Nakamoto 共识? 完整的初学者指南](https://blockonomi.com/nakamoto-consensus/) -- [Casper 的工作原理](https://medium.com/unitychain/intro-to-casper-ffg-9ed944d98b2d) +- [什么是中本聪共识? 完全初学者指南](https://blockonomi.com/nakamoto-consensus/) +- [Casper 如何工作?](https://medium.com/unitychain/intro-to-casper-ffg-9ed944d98b2d) - [关于工作量证明区块链的安全性和性能](https://eprint.iacr.org/2016/555.pdf) -- [拜占庭问题](https://en.wikipedia.org/wiki/Byzantine_fault) +- [拜占庭故障](https://en.wikipedia.org/wiki/Byzantine_fault) -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [工作量证明](/developers/docs/consensus-mechanisms/pow/) -- [矿工](/developers/docs/consensus-mechanisms/pow/mining/) +- [挖矿](/developers/docs/consensus-mechanisms/pow/mining/) - [权益证明](/developers/docs/consensus-mechanisms/pos/) - [权威证明](/developers/docs/consensus-mechanisms/poa/) diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/poa/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/poa/index.md index 6926bfe6def..d596538a99e 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/poa/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/poa/index.md @@ -1,6 +1,6 @@ --- -title: 权威证明 (PoA) -description: 权威证明共识协议的解释及其在区块链生态系统中的作用。 +title: "权威证明 (PoA)" +description: "权威证明共识协议的解释及其在区块链生态系统中的作用。" lang: zh --- @@ -77,3 +77,4 @@ lang: zh - [工作量证明](/developers/docs/consensus-mechanisms/pow/) - [权益证明](/developers/docs/consensus-mechanisms/pos/) + diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/attack-and-defense/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/attack-and-defense/index.md index 69a5a4bf0b9..a1b2d6b796c 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/attack-and-defense/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/attack-and-defense/index.md @@ -1,6 +1,6 @@ --- -title: 以太坊权益证明攻击与防御 -description: 了解针对权益证明以太坊的已知攻击途径以及如何防御这些攻击。 +title: "以太坊权益证明攻击与防御" +description: "了解针对权益证明以太坊的已知攻击途径以及如何防御这些攻击。" lang: zh --- @@ -74,7 +74,7 @@ lang: zh 这些措施结合在一起形成了这样一种场景:诚实的区块提议者在时隙开始时快速发送他们的区块,然后有一个约 1/3 时隙(4 秒)的时间段,在这个时间段内,新区块可能导致分叉选择算法切换到另一条链。 在同一截止时间后,与较早到达的认证相比,来自较慢验证者的认证会被降低权重。 这极大地有利于快速提议者和验证者决定链的头部,同时大大减少了平衡或弹跳攻击成功的可能性。 -值得注意的是,被单独提升权重的提议者只能防御“廉价重组”攻击,即那些有少量质押权益的攻击者实施的攻击。 实际上,提议者权重提升本身可以被较大质押者所利用。 [这篇帖子](https://ethresear.ch/t/change-fork-choice-rule-to-mitigate-balancing-and-reorging-attacks/11127)的作者描述了具有 7% 质押权益的攻击者如何策略性地部署他们的投票,欺骗诚实验证者在他们的分叉上进行构建,从而重组出一个诚实的区块。 这种攻击的设计要求非常理想的延迟条件,但这不太可能。 攻击者的胜算仍然很低,更多的质押权益意味着冒更多的资本风险和更强力的经济抑制因素。 +值得注意的是,仅靠提议者提升机制只能防御“廉价重组”,即由持有少量质押的攻击者所尝试的重组。 实际上,提议者权重提升本身可以被较大质押者所利用。 [这篇帖子](https://ethresear.ch/t/change-fork-choice-rule-to-mitigate-balancing-and-reorging-attacks/11127)的作者描述了具有 7% 质押权益的攻击者如何策略性地部署他们的投票,欺骗诚实验证者在他们的分叉上进行构建,从而重组出一个诚实的区块。 这种攻击的设计要求非常理想的延迟条件,但这不太可能。 攻击者的胜算仍然很低,更多的质押权益意味着冒更多的资本风险和更强力的经济抑制因素。 还有人提出了一种[专门针对最新消息驱动 (LMD) 规则的平衡攻击](https://ethresear.ch/t/balancing-attack-lmd-edition/11853),尽管有了提议者权重提升,这种攻击仍被认为可行。 攻击者通过模棱两可地提出区块提议,并把每个区块传播到大约一半的网络,来建立两个相互竞争的链,从而在分叉之间建立近似的平衡。 然后串通验证者会模棱两可地投票并掌握好时机,让一半的网络先接收他们对分叉 `A` 的投票,而另一半的网络先接收他们对分叉 `B` 的投票。 由于最新消息驱动 (LMD) 规则会丢弃第二个认证,只为每个验证者保留第一个认证,一半的网络看到给 `A` 的投票,看不到给 `B` 的投票,另一半网络看到给 `B` 的投票,看不到给 `A` 的投票。 作者描述了最新消息驱动 (LMD) 规则赋予攻击者“非凡的力量”来发动平衡攻击。 @@ -130,7 +130,7 @@ LMD-GHOST 分叉选择算法的最新消息驱动 (LMD) 部分减轻了雪崩攻 不管攻击者受到什么惩罚,社区都必须共同决定不诚实链(哪怕以太坊客户端中编码的分叉选择算法支持这条链)是否实际上无效,而社区应该在诚实的链上构建。 诚实的验证者可以集体同意在被社区认可的以太坊区块链分叉上进行构建,例如,该分叉可能在攻击开始之前就已经从规范链上分叉出来,或者攻击者的验证者被强行移除。 诚实的验证者受到激励来构建这条链,因为他们可以避免因未能证明(或无法正确地证明)攻击者的链而受到惩罚。 建立在以太坊上的交易所、入口和应用可能更愿意位于诚实链上,并且跟随诚实验证者进入诚实区块链。 -但是,这是一个重大的治理挑战。 有些用户和验证者会在切换回诚实链时无可避免地产生损失,因为攻击后被验证的区块中的交易可能会回滚,从而扰乱应用层。这很容易破坏倾向于相信“代码就是法律”的用户的观念。 交易所和应用很可能已经把脱链行为和现在可能要回滚的链上交易关联起来,并开始一连串的撤回和修订,很难公平地进行取舍,特别是如果不义之财混杂在其中,存入了去中心化金融或其他衍生品,会对诚实用户产生二次影响。 毫无疑问,那些因为精明手段或机缘巧合已经从不诚实链获利的一些用户甚至机构,可能会反对分叉以此保护他们的利益。 目前已经有呼吁要求演练对超过 51% 攻击的社区响应,以便可以快速执行合理的协调缓解措施。 Vitalik 在 ethresear.ch 上([此处](https://ethresear.ch/t/timeliness-detectors-and-51-attack-recovery-in-blockchains/6925)、[此处](https://ethresear.ch/t/responding-to-51-attacks-in-casper-ffg/6363))发起了一些有用的讨论,并在推特上(此处)也有所讨论。 协调的社交响应的目的应该是非常有针对性和具体地惩罚攻击者并尽量减少对其他用户的影响。 +但是,这是一个重大的治理挑战。 有些用户和验证者会在切换回诚实链时无可避免地产生损失,因为攻击后被验证的区块中的交易可能会回滚,从而扰乱应用层。这很容易破坏倾向于相信“代码就是法律”的用户的观念。 交易所和应用很可能已经把脱链行为和现在可能要回滚的链上交易关联起来,并开始一连串的撤回和修订,很难公平地进行取舍,特别是如果不义之财混杂在其中,存入了去中心化金融或其他衍生品,会对诚实用户产生二次影响。 毫无疑问,那些因为精明手段或机缘巧合已经从不诚实链获利的一些用户甚至机构,可能会反对分叉以此保护他们的利益。 目前已经有呼吁要求演练对超过 51% 攻击的社区响应,以便可以快速执行合理的协调缓解措施。 Vitalik 在 ethresear.ch 上([此处](https://ethresear.ch/t/timeliness-detectors-and-51-attack-recovery-in-blockchains/6925)、[此处](https://ethresear.ch/t/responding-to-51-attacks-in-casper-ffg/6363))发起了一些有用的讨论,并在推特上([此处](https://twitter.com/skylar_eth/status/1551798684727508992?s=20&t=oHZ1xv8QZdOgAXhxZKtHEw))也有所讨论。 协调的社交响应的目的应该是非常有针对性和具体地惩罚攻击者并尽量减少对其他用户的影响。 治理已经是一个复杂的话题。 对于以太坊社区来说,管理对不诚实的最终确定的链进行 0 层网络紧急响应无疑会是一个挑战,但这在以太坊历史上[已经发生过](/ethereum-forks/#dao-fork-summary) [2 次](/ethereum-forks/#tangerine-whistle)。 diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/attestations/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/attestations/index.md index ec900c1c007..5adffeefe86 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/attestations/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/attestations/index.md @@ -1,6 +1,6 @@ --- -title: 认证 -description: 关于在权益证明以太坊上进行认证的描述。 +title: "认证" +description: "关于在权益证明以太坊上进行认证的描述。" lang: zh --- @@ -8,31 +8,31 @@ lang: zh ## 什么是认证? {#what-is-an-attestation} -每个[时段](/glossary/#epoch)(6.4 分钟)验证者都会向网络提议一个认证。 这个认证是针对时段中的一个特定时隙。 认证的目的是投票赞成验证者对于链的看法,特别是最近的合理区块和当前时段的第一个区块(被称为`来源`和`目标`检查点)。 所有参与的验证者的信息都会合并,使得网络可以达成关于区块链状态的共识。 +每个[时段](/glossary/#epoch)(6.4 分钟)验证者都会向网络提议一个认证。 这个认证是针对时段中的一个特定时隙。 认证的目的是投票赞成验证者对于链的看法,特别是最近的合理区块和当前时段的第一个区块(被称为 `source` 和 `target` 检查点)。 所有参与的验证者的信息都会合并,使得网络可以达成关于区块链状态的共识。 认证包含以下组成部分: -- `aggregation_bits`:验证者的位列表,其位置映射到委员会中的验证者索引;(0/1) 数值表示验证者是否签名了`数据`(即,他们是否活跃和同意区块提议者) -- `data`:与认证相关的细节,如下方的定义 -- `signature`:聚合了个人验证者签名的 BLS 签名 +- `aggregation_bits`:验证者的位列表,其位置映射到验证者在其委员会中的索引;值 (0/1) 表示验证者是否签署了 `data`(即验证者是否处于活跃状态并同意区块提议者)。 +- `data`:与认证相关的细节,如下文所定义。 +- `signature`:聚合了各个验证者签名的 BLS 签名。 -证明验证者的第一项任务是创建 `data`。 `data` 包含以下信息: +进行认证的验证者的首要任务是构建 `data`。 `data` 包含以下信息: -- `slot`:认证指向的时隙号 -- `index`:一个数字,用来识别在给定的时隙中,验证者所属的委员会 -- `beacon_block_root`:验证者在链头看到的区块的根哈希(应用分叉选择算法的结果) -- `source`:最终确定性投票的一部分,表示验证者认为的最新的合理区块 -- `target`:最终确定性投票的一部分,表示验证者认为的当前时段的第一个区块 +- `slot`:认证引用的时隙编号。 +- `index`:一个数字,用于识别在给定的时隙中,验证者所属的委员会。 +- `beacon_block_root`:验证者在链的头部所见区块(应用分叉选择算法的结果)的根哈希。 +- `source`:最终确定性投票的一部分,表示验证者所见的最近合理区块。 +- `target`:最终确定性投票的一部分,表示验证者所见的当前时段的第一个区块。 -一旦 `data` 构造完成,验证者就可以将 `aggregation_bits` 中对应于他们自己的验证者索引的位从 0 翻转到 1,以表明他们已经参与。 +一旦构建好 `data`,验证者就可以将 `aggregation_bits` 中与其验证者索引对应的位从 0 翻转为 1,表示其已参与。 最终,验证者签名认证并且在网络进行广播。 ### 聚合的认证 {#aggregated-attestation} -对于验证者来说,在网络传递此数据需要大量的开销。 因此,在更加广泛地广播前,个人验证者的认证会在子网内进行聚合。 这包括聚合签名,以便广播的认证包含共识 `data` 和一个签名,后者结合了所有同意 `data` 的验证者的签名。 这可以使用 `aggregation_bits` 来检查,因为它提供了委员会中每个验证者的索引(其 ID 在 `data` 中提供),可用于查询个人签名。 +对于验证者来说,在网络传递此数据需要大量的开销。 因此,在更加广泛地广播前,个人验证者的认证会在子网内进行聚合。 这包括将签名聚合在一起,以便广播的认证包含共识 `data` 和一个由所有同意该 `data` 的验证者的签名组合而成的单一签名。 这可以使用 `aggregation_bits` 进行检查,因为它提供了委员会中每个验证者的索引(其 ID 在 `data` 中提供),可用于查询单个签名。 -在每个时段,每个子网中会有 16 个验证者被选为`聚合者`。 聚合者收集所有在广播网络听到的,与他们自己的 `data` 相同的所有认证。 每一个匹配认证的发送者被记录在 `aggregation_bits` 中。 然后聚合者将聚合的认证广播到更广泛的网络上。 +在每个时段,每个子网中会有 16 个验证者被选为聚合者。 聚合者会收集他们在 gossip 网络上听到的、与他们自己的 `data` 等效的所有认证。 每个匹配认证的发送者都记录在 `aggregation_bits` 中。 然后聚合者将聚合的认证广播到更广泛的网络上。 当一个验证者被选为区块提议者时,他们打包从子网到新区块最新时隙的聚合认证。 @@ -64,11 +64,11 @@ lang: zh 基础奖励根据证明验证者的数量及其有效质押以太币余额来计算: -`base reward = validator effective balance x 2^6 / SQRT(Effective balance of all active validators)` +`基础奖励 = 验证者有效余额 x 2^6 / SQRT(所有活跃验证者的有效余额)` #### 纳入延迟 {#inclusion-delay} -在验证者对链头 (`block n`) 进行投票,并且 `block n+1` 还没有被提出的时候。 认证自然会在**一个区块后**被包含,因此,投票给 `block n` 称为链头的所有认证被包含在 `block n+1` 中,其**纳入延迟**为 1。 如果纳入延迟加倍到两个时隙,那么认证奖励将减半,因为认证奖励等于基础奖励乘以纳入延迟的倒数。 +在验证者对链的头部(`区块 n`)投票时,`区块 n+1` 尚未被提议。 因此,认证自然会在**一个区块之后**被纳入,所以所有投票支持 `区块 n` 成为链头的认证都会被纳入 `区块 n+1`,**纳入延迟**为 1。 如果纳入延迟加倍到两个时隙,那么认证奖励将减半,因为认证奖励等于基础奖励乘以纳入延迟的倒数。 ### 认证场景 {#attestation-scenarios} @@ -76,17 +76,17 @@ lang: zh 验证者最多有 1 个时段来提交他们的认证。 如果在时段 0 缺失了认证,那就可以在时段 1 中提交并且附带纳入延迟。 -#### 缺失聚合者 {#missing-aggregator} +#### 缺失聚合器 {#missing-aggregator} -每个时段总共有 16 个聚合者。 此外,随机验证者订阅了**两个子网的 256 个时段**,在聚合者缺失的情况下作为备份。 +每个时段总共有 16 个聚合者。 此外,随机验证者会订阅**两个子网,为期 256 个时段**,在聚合器缺失时充当备份。 #### 缺失区块提议者 {#missing-block-proposer} -请注意,在某些情况下,幸运的聚合者可能也会成为区块提议者。 如果因为区块提议者缺失导致认证没有被包含,下一个区块提议者会捡起聚合的认证并将其包含到下一个区块中。 但是,**纳入延迟**将会增加 1。 +请注意,在某些情况下,幸运的聚合者可能也会成为区块提议者。 如果因为区块提议者缺失导致认证没有被包含,下一个区块提议者会捡起聚合的认证并将其包含到下一个区块中。 但是,**纳入延迟**会增加 1。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [Vitalik 的注释共识规范中的认证](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#attestationdata) +- [Vitalik 注释版共识规范中的认证](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#attestationdata) - [eth2book.info 中的认证](https://eth2book.info/capella/part3/containers/dependencies/#attestationdata) -_还有哪些社区资源对你有所帮助? 编辑并添加本页面!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/block-proposal/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/block-proposal/index.md index 9899a21041b..9a6b9ba2064 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/block-proposal/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/block-proposal/index.md @@ -1,6 +1,6 @@ --- -title: 提出区块 -description: 解释在权益证明以太坊中如何提议区块。 +title: "提出区块" +description: "解释在权益证明以太坊中如何提议区块。" lang: zh --- @@ -8,7 +8,7 @@ lang: zh ## 前提条件 {#prerequisites} -区块提议是权益证明协议的一部分。 为了帮助理解本页面,我们建议你阅读有关[权益证明](/developers/docs/consensus-mechanisms/pos/)和[区块架构](/developers/docs/blocks/)的内容。 +区块提议是权益证明协议的一部分。 为帮助您理解此页面,我们建议您阅读有关[权益证明](/developers/docs/consensus-mechanisms/pos/)和[区块架构](/developers/docs/blocks/)的内容。 ## 谁产生区块? {#who-produces-blocks} @@ -18,7 +18,7 @@ lang: zh 在每个时隙以伪随机的方式选择一个验证者来提议区块。 在区块链中没有真正的随机性,因为如果每个节点生成真正的随机数,它们就无法达成共识。 相反,目的是使验证者的选择过程不可预测。 以太坊使用一种叫做 RANDAO 的算法来实现随机性,它将来自区块提议者的一个哈希与一个随每个区块更新的种子混合起来。 这个值用于在所有验证者中选择一个特定的验证者。 验证者的选择提前两个时段固定,这是为了防范某些类型的种子操纵。 -虽然验证者在每个时隙中都会向 RANDAO 添加内容,但全局 RANDAO 值仅在每个时段更新一次。 为了计算下一个区块提议者的索引,RANDAO 值在每个时隙与时隙号混合,以给出唯一的值。 单独验证者被选中的概率并不是简单的 `1/N`(其中 `N` = 活跃验证者的总数)。 相反,它是按照每个验证者的有效以太币余额进行加权的。 最大有效余额为 32 个以太币(这意味着 `balance < 32 ETH` 会产生低于 `balance == 32 ETH` 的权重,而 `balance > 32 ETH` 不会产生高于 `balance == 32 ETH` 的权重)。 +虽然验证者在每个时隙中都会向 RANDAO 添加内容,但全局 RANDAO 值仅在每个时段更新一次。 为了计算下一个区块提议者的索引,RANDAO 值在每个时隙与时隙号混合,以给出唯一的值。 单个验证者被选中的概率并非简单的 `1/N`(其中 `N` = 活跃验证者总数)。 相反,它是按照每个验证者的有效以太币余额进行加权的。 最大有效余额为 32 ETH(这意味着 `balance < 32 ETH` 导致的权重低于 `balance == 32 ETH`,但 `balance > 32 ETH` 导致的权重不会高于 `balance == 32 ETH`)。 每个时隙中只选择一个区块提议者。 在正常情况下,单个区块生产者会在他们专属的时隙中创建并发布单个区块。 为同一个时隙创建两个区块是一种可罚没的行为,通常被称为“模棱两可”。 @@ -44,26 +44,26 @@ class BeaconBlockBody(Container): `randao_reveal` 字段取一个可验证的随机值,该值是区块提议者通过签署当前的时段编号创建的。 `eth1_data` 是就区块提议者对存款合约的看法进行的投票,包括存款默克尔树的根和使新存款能够被验证的总存款数。 `graffiti` 是一个可选字段,可以用来在区块中添加一条消息。 `proposer_slashings` 和 `attester_slashings` 字段包含了某些验证者根据区块提议者对链的看法已经犯下可罚没行为的证据。 `deposits` 是区块提议者所知道的新验证者存款的列表,`voluntary_exits` 是区块提议者从共识层广播网络上监听到的希望退出的验证者的列表。 `sync_aggregate` 是一个向量,显示哪些验证者之前被分配到一个同步委员会(服务于轻量客户端数据的验证者子集)并参与了数据签名。 -`execution_payload` 使得关于交易的信息可以在执行和共识客户端之间传递。 `execution_payload` 是一个被嵌套在信标链区块内部的执行数据区块。 `execution_payload` 中的字段反映了以太坊黄皮书中概述的区块结构,只不过其中没有叔块,并且 `prev_randao` 取代了 `difficulty`。 执行客户端可以访问它在自己的广播网络上监听到的本地交易池。 这些交易在本地执行,以生成一个被称为“后状态”的更新的状态树。 这些交易被包括在 `execution_payload` 中名为 `transactions` 的列表中,后状态则在 `state-root` 字段中提供。 +`execution_payload` 使得关于交易的信息可以在执行客户端和共识客户端之间传递。 `execution_payload` 是一个被嵌套在信标链区块内部的执行数据区块。 `execution_payload` 中的字段反映了以太坊黄皮书中概述的区块结构,只是其中没有叔块,并且 `prev_randao` 取代了 `difficulty`。 执行客户端可以访问它在自己的广播网络上监听到的本地交易池。 这些交易在本地执行,以生成一个被称为“后状态”的更新的状态树。 这些交易被包括在 `execution_payload` 中名为 `transactions` 的列表中,后状态则在 `state-root` 字段中提供。 所有这些数据都被收集在一个信标链区块中,经过签名并广播给区块提议者的对等者,再由他们传播给他们的对等者,以此类推。 -阅读更多关于[区块剖析](/developers/docs/blocks)的内容。 +阅读更多关于[区块剖析](/developers/docs/blocks)的信息。 -## 区块发生了什么? {#what-happens-to-blocks} +## 区块发生了什么? 区块的后续处理 {#what-happens-to-blocks} 区块被添加到区块提议者的本地数据库,并通过共识层广播网络广播给对等者。 当一个验证者接收到区块时,它会验证其中的数据,包括检查区块是否有正确的父区块、是否对应正确的时隙、提议者索引是否符合预期、RANDAO 揭示是否有效以及提议者是否被罚没。 `execution_payload` 被解包,验证者的执行客户端重新执行列表中的交易,以检查所提议的状态变化。 假设区块通过了所有这些检查,每个验证者将区块添加到自己的规范链中。 然后,在下一个时隙中重新开始这个过程。 ## 区块奖励 {#block-rewards} -区块提议者会收到他们工作的报酬。 有一个 `base_reward`,它是根据活跃验证者的数量和他们的有效余额来计算的。 然后,区块提议者会收到区块中包含的每个有效认证的 `base_reward` 的一部分;认证区块的验证者越多,区块提议者获得的奖励就越高。 还有一个奖励是报告应该被罚没的验证者,数额等于每个被罚没的验证者的 `1/512 * effective balance`。 +区块提议者会收到他们工作的报酬。 有一个 `base_reward`,它是根据活跃验证者的数量和他们的有效余额来计算的。 然后,区块提议者会收到区块中包含的每个有效认证的 `base_reward` 的一部分;认证该区块的验证者越多,区块提议者的奖励就越多。 还有一个奖励是报告应该被罚没的验证者,数额等于每个被罚没的验证者的 `1/512 * effective balance`。 [关于奖励和惩罚的更多信息](/developers/docs/consensus-mechanisms/pos/rewards-and-penalties) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [区块简介](/developers/docs/blocks/) - [权益证明简介](/developers/docs/consensus-mechanisms/pos/) - [以太坊共识规范](https://github.com/ethereum/consensus-specs) -- [Gasper 简介](/developers/docs/consensus-mechanisms/pos/) +- [Gasper 简介](/developers/docs/consensus-mechanisms/pos/gasper/) - [升级以太坊](https://eth2book.info/) diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/faqs/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/faqs/index.md index 86050a1e3c6..6b2d77c00e8 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/faqs/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/faqs/index.md @@ -1,14 +1,14 @@ --- -title: 常见问题 -description: 常见问题:权益证明以太坊 +title: "常见问题" +description: "常见问题:权益证明以太坊" lang: zh --- -## 权益证明是什么? {#what-is-proof-of-stake} +## 什么是权益证明 {#what-is-proof-of-stake} 权益证明是一种算法类别,通过确保攻击者因欺诈行为而损失有价值的资产,可以为区块链提供安全性。 权益证明系统需要一组验证者提供一些资产,如果验证者从事某些被证明为欺诈的行为,则可以销毁这些资产。 以太坊使用权益证明机制来保护区块链的安全性。 -## 权益证明与工作量证明相比有何不同? {#comparison-to-proof-of-work} +## 权益证明与工作量证明相比有何不同? 与工作量证明的比较 {#comparison-to-proof-of-work} 权益证明和工作量证明都是从经济上抑制恶意行为者的机制,以防止其向网络发送垃圾或进行欺诈行为。 在两种情况下,积极参与共识的节点都会“向网络中”投入某些资产,如果他们行为不当,便会失去这些资产。 @@ -18,7 +18,7 @@ lang: zh 工作量证明需要在挖矿过程中消耗大量的电力,因此能耗要高得多。 而权益证明只需要非常少量的能量 - 以太坊验证者甚至可以在树莓派等低功耗设备上运行。 以太坊的权益证明机制被认为比工作量证明机制更安全,因为攻击的代价更高,并且给攻击者造成的后果更严重。 -工作量证明与权益证明是一个有争议的话题。 [Vitalik Buterin 的博客](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-are-the-benefits-of-proof-of-stake-as-opposed-to-proof-of-work)以及 Justin Drake 和 Lyn Alden 间的辩论很好地总结了各方论点。 +工作量证明与权益证明是一个有争议的话题。 [Vitalik Buterin 的博客](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-are-the-benefits-of-proof-of-stake-as-opposed-to-proof-of-work)以及 Justin Drake 和 Lyn Alden 之间的辩论很好地总结了这些论点。 @@ -26,31 +26,31 @@ lang: zh 由此可见, 权益证明网络上的节点能耗很低。 一项第三方研究得出的结论是,整个基于权益证明的以太坊网络每年消耗约 0.0026 亿千瓦时的电量,仅相当于美国博彩行业电力消耗量的 1/13000 左右。 -[关于以太坊能源消耗的更多信息](/energy-consumption/)。 +[更多关于以太坊能源消耗的信息](/energy-consumption/) ## 权益证明安全吗? {#is-pos-secure} 以太坊的权益证明是非常安全的。 这种机制经过了八年的研究、开发和严格测试,才得以投入使用。 安全保证有别于使用工作量证明的区块链。 在权益证明机制中,可以主动惩罚(“罚没”)恶意验证者并将其从验证者组中驱逐出去,这将导致其损失大量的以太币。 而在工作量证明中,攻击者在拥有足够哈希能力的情况下可以不断重复攻击。 与工作量证明以太坊相比,对权益证明以太坊发起同等攻击的成本也更高。 要影响链的活性,至少需要网络上已质押以太币总数的 33%(除非进行极为复杂、成功概率极低的攻击)。 要控制未来区块的内容,至少需要已质押以太币总量的 51%,而要重写历史记录,则需要超过质押总量的 66%。 以太坊协议将在 33% 或 51% 攻击场景中销毁这些资产,并通过社会共识来应对 66% 攻击场景。 -- [关于保护以太坊权益证明机制免受攻击的更多信息](/developers/docs/consensus-mechanisms/pos/attack-and-defense) -- [关于权益证明设计的更多信息](https://medium.com/@VitalikButerin/a-proof-of-stake-design-philosophy-506585978d51) +- [更多关于保护以太坊权益证明免受攻击者攻击的信息](/developers/docs/consensus-mechanisms/pos/attack-and-defense) +- [更多关于权益证明设计的信息](https://medium.com/@VitalikButerin/a-proof-of-stake-design-philosophy-506585978d51) ## 权益证明机制降低了以太坊的费用吗? {#does-pos-make-ethereum-cheaper} 否。 发送交易的成本(燃料费)由动态费用市场决定,随着网络需求的增加而增加。 共识机制对此没有直接影响。 -[关于燃料的更多信息](/developers/docs/gas)。 +[更多关于燃料的信息](/developers/docs/gas)。 ## 什么是节点、客户端和验证者? {#what-are-nodes-clients-and-validators} 节点是连接到以太坊网络的计算机。 客户端是在计算机上运行,将其转化为节点的软件。 有两种类型的客户端:执行客户端和共识客户端。 两种客户端都是创建节点所需的。 验证者是共识客户端一个可选的附加功能,使节点能够参与权益证明共识。 这意味着当被选中时创建和提议区块,以及认证其在网络上监听到的区块。 要运行验证者,节点运营商必须在存款合约中存入 32 个以太币。 -- [关于节点和客户端的更多信息](/developers/docs/nodes-and-clients) -- [关于质押的更多信息](/staking) +- [更多关于节点和客户端的信息](/developers/docs/nodes-and-clients) +- [更多关于质押的信息](/staking) ## “权益证明”是一个新的概念吗? {#is-pos-new} -否。 早在 2011 年,BitcoinTalkk 论坛上有一位用户就[提出了将权益证明作为比特币的升级形态的想法](https://bitcointalk.org/index.php?topic=27787.0)。 11 年后,才准备好在以太坊主网上实施。 一些其他的区块链比以太坊更早实施了权益证明,但不是以太坊的特定机制(称为 Gasper)。 +否。 2011 年,BitcoinTalk 上的一位用户[提出了权益证明的基本思想](https://bitcointalk.org/index.php?topic=27787.0),作为比特币的一项升级。 11 年后,才准备好在以太坊主网上实施。 一些其他的区块链比以太坊更早实施了权益证明,但不是以太坊的特定机制(称为 Gasper)。 ## 以太坊的权益证明有什么特别之处? {#why-is-ethereum-pos-special} @@ -60,13 +60,13 @@ lang: zh Casper 和 LMD_GHOST 的组合被称为 Gasper。 -[关于 Gasper 的更多信息](/developers/docs/consensus-mechanisms/pos/gasper/) +[更多关于 Gasper 的信息](/developers/docs/consensus-mechanisms/pos/gasper/) ## 什么是罚没? {#what-is-slashing} 罚没是指销毁验证者的部分质押额并将验证者从网络中逐出的行为。 罚没中损失的以太币数量随着被罚没的验证者数量而变化 - 这意味着串通的验证者会受到比个人更严厉的惩罚。 -[关于罚没的更多信息](/developers/docs/consensus-mechanisms/pos/rewards-and-penalties#slashing) +[更多关于惩罚的信息](/developers/docs/consensus-mechanisms/pos/rewards-and-penalties#slashing) ## 为什么成为验证者需要质押 32 个以太币? {#why-32-eth} @@ -76,32 +76,31 @@ Casper 和 LMD_GHOST 的组合被称为 Gasper。 每个时隙都会以伪随机的方式选择一个验证者来提议区块,使用的算法被称为 RANDAO,它将区块提议者的哈希与一个随每个区块更新的种子混合在一起。 这个值用于在所有验证者中选择一个特定的验证者。 验证者的选择会提前两个时段固定。 -[关于如何选择验证者的更多信息](/developers/docs/consensus-mechanisms/pos/block-proposal) +[更多关于验证者选择的信息](/developers/docs/consensus-mechanisms/pos/block-proposal) ## 什么是权益粉碎攻击? {#what-is-stake-grinding} - 权益粉碎攻击是针对权益证明网络的攻击类别,这种情况下,攻击者试图将验证者选择算法偏向于选择他们自己的验证者。 对 RANDAO 发起权益粉碎攻击需要已质押的以太币总数的约一半。 -[关于权益粉碎攻击的更多信息](https://eth2book.info/altair/part2/building_blocks/randomness/#randao-biasability) +[更多关于权益粉碎攻击的信息](https://eth2book.info/altair/part2/building_blocks/randomness/#randao-biasability) ## 什么是社交罚没? {#what-is-social-slashing} 社交罚没是指社区协调区块链的分叉以应对攻击的能力。 它使社区能够从攻击者最终化不诚实的链中恢复过来。 它也可以用于对抗审查攻击。 -- [关于社交罚没的更多信息](https://ercwl.medium.com/the-case-for-social-slashing-59277ff4d9c7) -- [Vitalik Buterin 关于社交罚没的观点](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-is-proof-of-stake) +- [更多关于社会性惩罚的信息](https://ercwl.medium.com/the-case-for-social-slashing-59277ff4d9c7) +- [Vitalik Buterin 谈社会性惩罚](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-is-proof-of-stake) ## 我会受到罚没吗? {#will-i-get-slashed} 作为验证者,除非你故意从事恶意行为,否则不会受到罚没。 罚没机制只会在极其特定的情况下实施,比如验证者在同一时隙提议多个区块或者在其认证中出现自相矛盾等行为,这类情况很少会在正常操作中意外发生。 -[关于罚没条件的更多信息](https://eth2book.info/altair/part2/incentives/slashing) +[更多关于惩罚条件的信息](https://eth2book.info/altair/part2/incentives/slashing) -## 什么是无利害关系问题? {#what-is-nothing-at-stake-problem} +## 什么是无利害关系问题? 什么是“无利害关系”问题?{#what-is-nothing-at-stake-problem} 无利害关系问题是一些权益证明机制中的一个概念性问题,其中只有奖励而没有惩罚。 如果没有任何利害关系,那么一个务实的验证者同样愿意验证任何甚至多个区块链分叉,因为这将增加他们的奖励。 以太坊通过使用最终确定性条件和罚没机制来确保只有一个规范链,以解决此问题。 -[关于无利害关系问题的更多信息](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-is-the-nothing-at-stake-problem-and-how-can-it-be-fixed) +[更多关于“无利害关系”问题的信息](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-is-the-nothing-at-stake-problem-and-how-can-it-be-fixed) ## 什么是分叉选择算法? {#what-is-a-fork-choice-algorithm} @@ -109,37 +108,37 @@ Casper 和 LMD_GHOST 的组合被称为 Gasper。 以太坊的分叉选择算法被称为 LMD-GHOST。 它会选择具有最大认证权重的分叉,也就是得到了最多质押以太币投票的分叉。 -[关于 LMD-GHOST 的更多信息](/developers/docs/consensus-mechanisms/pos/gasper/#fork-choice) +[更多关于 LMD-GHOST 的信息](/developers/docs/consensus-mechanisms/pos/gasper/#fork-choice) ## 什么是权益证明中的最终确定性? {#what-is-finality} 权益证明中的最终确定性是指保证给定的区块是规范链的永久部分,并且只有在出现共识失败的情况下才会被回滚,这时攻击者将会销毁已质押以太币总数的 33%。 这是“加密经济”的最终确定性,而不是与工作量证明区块链相关的“概率最终确定性”。 在概率最终确定性中,区块没有明确的确定/非确定状态——只不过随着时间的推移,区块从链上被删除的可能性越来越小,用户将自行决定他们什么时候有足够的信心认为区块是“安全的”。 而在加密经济的最终确定性下,成对的检查点区块必须获得已质押以太币 66% 以上的选票。 如果满足这个条件,这两个检查点之间的区块将被明确“最终确定”。 -[关于最终确定性的更多信息](/developers/docs/consensus-mechanisms/pos/#finality) +[更多关于确定性的信息](/developers/docs/consensus-mechanisms/pos/#finality) ## 什么是“弱主观性”? {#what-is-weak-subjectivity} 弱主观性是权益证明网络的一个特点,其中社交信息用于确认区块链的当前状态。 新节点或长时间离线后重新加入网络的节点可以获得最新的状态,以便节点能够立即查看它们是否位于正确的链上。 这些状态被称为“弱主观性检查点”,它们可以从其他带外节点运营者处获取,也可以从区块链浏览器或多个公共端点获取。 -[关于弱主观性的更多信息](/developers/docs/consensus-mechanisms/pos/weak-subjectivity) +[更多关于弱主观性的信息](/developers/docs/consensus-mechanisms/pos/weak-subjectivity) ## 权益证明能抗审查吗? {#is-pos-censorship-resistant} 抗审查性当前很难证明。 然而,与工作量证明不同,权益证明提供了协调罚没以处罚审查验证者的选择。 该协议即将修改为将区块构建者与区块提议者分开,并实施构建者必须在每个区块中包括的交易列表。 此提案被称为“提议者-构建者分离”,有助于防止验证者审查交易。 -[关于“提议者-构建者分离”的更多信息](https://notes.ethereum.org/@fradamt/H1TsYRfJc#Original-basic-scheme) +[更多关于提议者-构建者分离的信息](https://notes.ethereum.org/@fradamt/H1TsYRfJc#Original-basic-scheme) ## 以太坊的权益证明系统会受到 51% 攻击吗? {#pos-51-attack} 由此可见, 权益证明和工作量证明一样,容易受到 51% 攻击。 攻击者不需要掌控 51% 的网络算力,而是需要掌控已质押以太币总数的 51%。 如果攻击者累积了总质押量的 51%,则能够控制分叉选择算法。 这使得攻击者能够审查某些交易,进行短程重组,以及通过以有利于他们的方式重新排序区块来提取矿工可提取价值。 -[关于权益证明攻击的更多信息](/developers/docs/consensus-mechanisms/pos/attack-and-defense) +[更多关于权益证明攻击的信息](/developers/docs/consensus-mechanisms/pos/attack-and-defense) ## 什么是社交协调,为什么需要它? {#what-is-social-coordination} 社交协调是以太坊的最后一道防线,它可以使一个由于遭到攻击而最终化了不诚实区块的区块链恢复到诚实状态。 在这种情况下,以太坊社区将不得不进行“带外”社交协调并同意使用诚实的少数分支,同时罚没攻击者的验证者。 这需要应用程序和交易所也认可诚实的分叉。 -[了解关于社交协调的更多信息](/developers/docs/consensus-mechanisms/pos/attack-and-defense#people-the-last-line-of-defense) +[阅读更多关于社会协调的信息](/developers/docs/consensus-mechanisms/pos/attack-and-defense#people-the-last-line-of-defense) ## 在权益证明中,富人会变得更富有吗? {#do-rich-get-richer} @@ -147,15 +146,15 @@ Casper 和 LMD_GHOST 的组合被称为 Gasper。 ## 权益证明是否比工作量证明更中心化? {#is-pos-decentralized} -不,由于采矿成本增加、价格高昂迫使个人和小公司退出等原因,工作量证明更倾向于集中化。 目前权益证明存在的问题是流动性质押衍生品的影响。 这些是代表某些提供者所质押的以太币的代币,任何人都可以在二级市场上交换,而无需实际解除以太币的质押。 流动性质押衍生品允许用户质押的以太币数量少于 32 个,但也会产生中心化风险,即少数几个大型组织最终可能控制大部分的质押份额。 这就是为什么[单独质押](/staking/solo)成为以太坊的最佳选择。 +不,由于采矿成本增加、价格高昂迫使个人和小公司退出等原因,工作量证明更倾向于集中化。 目前权益证明存在的问题是流动性质押衍生品的影响。 这些是代表某些提供者所质押的以太币的代币,任何人都可以在二级市场上交换,而无需实际解除以太币的质押。 流动性质押衍生品允许用户质押的以太币数量少于 32 个,但也会产生中心化风险,即少数几个大型组织最终可能控制大部分的质押份额。 这就是为什么[单独质押](/staking/solo)是以太坊的最佳选择。 -[关于流动性质押衍生品中的权益中心化的更多信息](https://notes.ethereum.org/@djrtwo/risks-of-lsd) +[更多关于流动性质押衍生品 (LSD) 中质押中心化的信息](https://notes.ethereum.org/@djrtwo/risks-of-lsd) ## 为什么我只能质押以太币? {#why-can-i-only-stake-eth} ETH 是以太坊的原生货币。 为计算有效余额以用于加权投票和确保安全性,必须有一种单一的货币来计量所有权益。 以太币本身是以太坊的一个基本组成部分,而不是一个智能合约。 如果加入其他货币,将会显著增加质押的复杂性并降低其安全性。 -## 以太坊是唯一使用权益证明的区块链吗? {#is-ethereum-the-only-pos-blockchain} +## 以太坊是唯一使用权益证明的区块链吗? 以太坊是唯一的权益证明区块链吗?{#is-ethereum-the-only-pos-blockchain} 不,现在有多种使用权益证明的区块链。 但是没有一个和以太坊完全相同;以太坊的权益证明机制是独一无二的。 @@ -163,10 +162,10 @@ ETH 是以太坊的原生货币。 为计算有效余额以用于加权投票和 合并是指以太坊关闭其基于工作量证明的共识机制并开启其基于权益证明的共识机制的时刻。 合并发生在 2022 年 9 月 15 日。 -[关于合并的更多信息](/roadmap/merge) +[更多关于合并的信息](/roadmap/merge) ## 什么是活性和安全性? {#what-are-liveness-and-safety} -活性和安全性是区块链的两个基本安全问题。 活性是指最终链的可用性。 如果链停止最终化或用户无法轻松访问它,这些都是活性失败。 极高的访问成本也可能被认为是一种活性失败。 安全性是指攻击链,即最终化彼此冲突的检查点的难度有多大。 +活性和安全性是区块链的两个基本安全问题。 活性是指最终链的可用性。 如果链停止最终化或用户无法轻松访问它,这些都是活性失败。 极高的访问成本也可能被认为是一种活性失败。 安全性是指攻击区块链的难度,即最终确定相互冲突的检查点。 -[阅读关于 Casper 论文的更多信息](https://arxiv.org/pdf/1710.09437.pdf) +[在 Casper 论文中阅读更多信息](https://arxiv.org/pdf/1710.09437.pdf) diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/gasper/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/gasper/index.md index e4fcd08375a..9ac4c80324f 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/gasper/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/gasper/index.md @@ -1,6 +1,6 @@ --- title: Gasper -description: 关于信标链协议权益证明机制的说明。 +description: "关于信标链协议权益证明机制的说明。" lang: zh --- @@ -8,9 +8,9 @@ Gasper 是友好的最终确定性工具 Gasper (Casper-FFG) 和 LMD-GHOST 分 **请注意**,Casper-FFG 的初始定义已稍作更新,以纳入 Gasper。 撰写此页面时,我们考量的是更新后的版本。 -## 前提条件 +## 前言 -为理解此材料,需要阅读[权益证明](/developers/docs/consensus-mechanisms/pos/)的介绍页面。 +要理解此材料,必须阅读关于[权益证明](/developers/docs/consensus-mechanisms/pos/)的介绍页面。 ## Gasper 的作用 {#role-of-gasper} @@ -23,20 +23,20 @@ Gasper 在权益证明区块链中具有最重要的地位——节点提供以 1. 区块必须获得总质押以太币 2/3 的投票,才能纳入规范链。 此条件可将区块升级至“合理”状态。 合理的区块不大可能回滚,但满足某些条件时也可以回滚。 2. 当一个合理区块上有另一个区块被合理化,那前者就被升级为“最终确定”状态。 确定一个区块就是承诺将该区块纳入规范链。 除非攻击者销毁数百万以太币(几十亿美元),否则该区块不会回滚。 -并非每个时隙都会发生这种区块升级。 相反,只有时段边界的区块才能是“合理”和“最终确定”状态。 这些区块一般被称为“检查点”。 升级涉及成对的检查点。 两个连续的检查点之间必须存在"绝对多数链接🔗"(即:总质押以太币中有 2/3 投票认为检查点 B 是检查点 A 的正确衍生物),才能将存在时间更长的检查点升级为“最终确定”,而较新的区块则升级为“合理”。 +并非每个时隙都会发生这种区块升级。 相反,只有时段边界的区块才能是“合理”和“最终确定”状态。 这些区块一般被称为“检查点”。 升级涉及成对的检查点。 两个连续的检查点之间必须存在“绝对多数链接”(即,三分之二的总质押以太币投票认为检查点 B 是检查点 A 的正确后代),才能将较旧的检查点升级为“已最终确定”,并将较新的区块升级为“已合理化”。 由于最终确定需要三分之二同意某个区块是规范的,因此除非能满足以下条件,否则攻击者不可能另外创建一条最终确定链: 1. 拥有或控制总质押以太币的 2/3。 2. 至少销毁总质押以太币的 1/3。 -之所以要满足第一个条件,是因为要最终确定一条链,需要质押以太币 2/3 的投票。 而第二个条件是因为,如果总质押的 2/3 对两个分叉表示支持,那么必然有 1/3 对两个分叉均进行了投票。 双重投票是会触发最大惩罚的罚没条件,总质押的 1/3 会被销毁。 截至 2022 年 5 月,此条件需要攻击者销毁价值约 100 亿美元的以太币。 Gasper 中用来合理化和最终确定区块的算法是[友好的最终确定性工具 Casper (Casper-FFG)](https://arxiv.org/pdf/1710.09437.pdf) 的微调版。 +之所以要满足第一个条件,是因为要最终确定一条链,需要质押以太币 2/3 的投票。 而第二个条件是因为,如果总质押的 2/3 对两个分叉表示支持,那么必然有 1/3 对两个分叉均进行了投票。 双重投票是会触发最大惩罚的罚没条件,总质押的 1/3 会被销毁。 截至 2022 年 5 月,此条件需要攻击者销毁价值约 100 亿美元的以太币。 Gasper 中用于合理化和最终确定区块的算法是[友好的最终确定性工具 Casper (Casper-FFG)](https://arxiv.org/pdf/1710.09437.pdf) 的微调版。 -### 激励和罚没 {#incentives-and-slashing} +### 激励和惩罚 {#incentives-and-slashing} 验证者将因诚实地提议和验证区块而获得奖励。 奖励将以发放以太币的形式提供,这些以太币将加入他们的质押额。 另一方面,缺席和调用时未能响应的验证者将会错过这些奖励,有时还会损失一小部分现有质押额。 然而,离线的处罚较小,在大多数情况下,仅仅是错失奖励的机会成本。 但是,有些验证者的操作很难无意为之,并且常为恶意行为,例如,为同一时隙提议多个区块、为同一时隙验证多个区块或者与以前的检查点投票背道而驰。 这些都是要接受更严厉惩罚的“可罚没”行为,罚没结果是验证者的部分质押额遭到销毁,以及验证者被移出验证者网络。 整个过程需要 36 天。 第一天,进行最高 1 个以太币的初次惩罚。 随后,被罚没验证者的以太币将在退出期一点点耗尽,但到第 18 天,他们会收到一个“相关性惩罚”,即当更多的验证者都在大致相同的时间受罚时,惩罚将更重。 最大的惩罚是全部质押。 这些奖励和惩罚为激励诚实的验证者和挫伤网络攻击而立。 -### 怠惰惩罚 {#inactivity-leak} +### 非活跃泄漏 {#inactivity-leak} 除了安全性,Gasper 还提供“合理的活性”。 条件是只要有三分之二的质押以太币遵守协议地诚实投票,不论是否发生其他任何活动(比如攻击、延迟问题或罚没),区块链都将被最终确定。 换言之,要阻止区块链被最终确定,必须以某种方式破坏总质押以太币的 1/3。 在 Gasper 中,有另一条防线防止活性失败,即“怠惰惩罚”。 如果链未能在四个时段内最终确定,便会激活此机制。 对于未能积极证明主链的验证者,其质押货币将逐渐耗尽,直到主链重新获得总质押 2/3 的投票,以确保活性失败只是暂时的。 @@ -46,7 +46,7 @@ Casper-FFG 的原始定义包含一个分叉选择算法,该算法规定:`fo LMD-GHOST 代表“最新消息驱动的最贪婪、最重的观测子树(Latest Message-Driven Greedy Heaviest Observed Sub-Tree)”。 该术语充满行话,用来定义一种算法:选择具有最大证明累积权重的分叉作为规范分叉(最贪婪、最重的子树);如果从验证者那里收到多条消息,则只考虑最新的那个(最新消息驱动)。 在将最重的区块添加到规范链之前,每位验证者都会使用这个规则来评估每个区块。 -## 延伸阅读 {#further-reading} +## 扩展阅读 {#further-reading} -- [Gasper:GHOST 和 Casper 的结合](https://arxiv.org/pdf/2003.03052.pdf) -- [友好的最终确定性小工具 Capser](https://arxiv.org/pdf/1710.09437.pdf) +- [Gasper:GHOST 与 Casper 的结合](https://arxiv.org/pdf/2003.03052.pdf) +- [友好的最终确定性工具 Casper](https://arxiv.org/pdf/1710.09437.pdf) diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/index.md index 41867968933..df54a5dd4cc 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/index.md @@ -1,14 +1,14 @@ --- -title: 权益证明(PoS) -description: 权益证明共识算法以及其在以太坊中作用的解释。 +title: "权益证明(PoS)" +description: "权益证明共识算法以及其在以太坊中作用的解释。" lang: zh --- -权益证明 (PoS) 是支撑以太坊[共识机制](/developers/docs/consensus-mechanisms/)的基础。 以太坊于 2022 年启动了权益证明机制,这是因为和原先的[工作量证明](/developers/docs/consensus-mechanisms/pow)架构相比,以太坊更安全、能耗更低并且更利于实现新的扩容解决方案。 +权益证明 (PoS) 是[以太坊共识机制](/developers/docs/consensus-mechanisms/)的基础。 以太坊于 2022 年启动了权益证明机制,这是因为和原先的[工作量证明](/developers/docs/consensus-mechanisms/pow)架构相比,以太坊更安全、能耗更低并且更利于实现新的扩容解决方案。 ## 前提条件 {#prerequisites} -为了更好地理解本文,我们建议你首先阅读以下内容 [共识机制](/developers/docs/consensus-mechanisms/)。 +为更好地理解本页面,我们建议您先阅读[共识机制](/developers/docs/consensus-mechanisms/)。 ## 什么是权益证明? {#what-is-pos} @@ -20,38 +20,38 @@ lang: zh 在工作量证明中,生成区块的时间是由挖矿难度决定的,而在权益证明中,节奏是固定的。 权益证明以太坊中的时间分为时隙(12 秒)和时段(32 个时隙)。 在每个时隙中随机选择一位验证者作为区块提议者。 该验证者负责创建新区块并发送给网络上的其他节点。 另外在每个时隙中,都会随机选择一个验证者委员会,通过他们的投票确定所提出区块的有效性。 将验证者集合划分为若干个委员会对于保持网络负荷易于管理非常重要。 委员会将验证者集合分成不同部分,以便每个活跃的验证者在每个时段都会出示证明,但并不在每个时隙都这样做。 -## 如何在以太坊权益证明中执行交易 {#transaction-execution-ethereum-pos} +## 交易在以太坊 PoS 中如何执行 {#transaction-execution-ethereum-pos} 下面提供了关于如何在以太坊权益证明中执行交易的全面解释。 -1. 用户使用他们的私钥创建并签署[交易](/developers/docs/transactions/)。 这通常由钱包或库处理,例如 [ethers.js](https://docs.ethers.org/v6/)、[web3js](https://docs.web3js.org/)、[web3py](https://web3py.readthedocs.io/en/v5/) 等,但本质上是用户在使用以太坊 [JSON-RPC 应用程序接口](/developers/docs/apis/json-rpc/)向节点发出请求。 用户定义他们准备支付一定量的燃料作为给验证者的小费,以鼓励他们将交易纳入在一个区块中。 [小费](/developers/docs/gas/#priority-fee)支付给验证者,而[基础费](/developers/docs/gas/#base-fee)被销毁。 -2. 交易被提交给以太坊[执行客户端](/developers/docs/nodes-and-clients/#execution-client)验证有效性。 这意味着确保发送人有足够的以太币来完成交易,并且他们已经使用正确的密钥来签名交易。 -3. 如果交易有效,执行客户端将其添加到其本地内存池(待处理交易列表),并通过执行层广播网络将其广播到其他节点。 当其他节点听到关于交易的消息时,它们也将其添加到本地内存池中。 高级用户可能会避免广播他们的交易,而是将其转发给专门的区块构建器,例如 [Flashbots Auction](https://docs.flashbots.net/flashbots-auction/overview)。 这使他们能够在即将到来的区块中组织交易以获得最大利润([最大可提取价值](/developers/docs/mev/#mev-extraction))。 -4. 网络上的验证节点之一是当前时隙的区块提议者(之前已使用 RANDAO 以伪随机方式选择)。 该节点负责构建和广播下一个要添加到以太坊区块链的区块并更新全局状态。 该节点由三部分组成:执行客户端、共识客户端和验证者客户端。 执行客户端将来自本地内存池的交易捆绑到“执行负载”中,并在本地执行它们以生成状态更改。 此信息被传递到共识客户端。在该客户端,执行有效载荷被包装为“信标区块”的一部分。该信标区块还包含有关奖励、惩罚、罚没、认证等的信息,从而使网络能够就链头的区块顺序达成一致。 [连接共识客户端和执行客户端](/developers/docs/networking-layer/#connecting-clients)中更详细地描述了执行客户端和共识客户端之间的通信。 -5. 其他节点在共识层广播网络上接收新的信标区块, 并将其传递给它们的执行客户端。在执行客户端上,交易在本地重新执行以确保提议的状态更改有效。 然后,验证者客户端证明该区块是有效的,并且根据他们对链的看法,这是逻辑上的下一个区块(这意味着它建立在具有最大认证权重的链上,如[分叉选择规则](/developers/docs/consensus-mechanisms/pos/#fork-choice)所定义)。 该块被添加到证明它的每个节点的本地数据库中。 +1. 用户使用其私钥创建并签署[交易](/developers/docs/transactions/)。 这通常由钱包或程序库(例如 [ethers.js](https://docs.ethers.org/v6/)、[web3js](https://docs.web3js.org/)、[web3py](https://web3py.readthedocs.io/en/v5/) 等)处理,但在底层,用户是使用以太坊 [JSON-RPC API](/developers/docs/apis/json-rpc/) 向节点发出请求。 用户定义他们准备支付一定量的燃料作为给验证者的小费,以鼓励他们将交易纳入在一个区块中。 [小费](/developers/docs/gas/#priority-fee)会支付给验证者,而[基本费用](/developers/docs/gas/#base-fee)则被销毁。 +2. 交易被提交给以太坊[执行客户端](/developers/docs/nodes-and-clients/#execution-client),后者会验证其有效性。 这意味着确保发送人有足够的以太币来完成交易,并且他们已经使用正确的密钥来签名交易。 +3. 如果交易有效,执行客户端将其添加到其本地内存池(待处理交易列表),并通过执行层广播网络将其广播到其他节点。 当其他节点听到关于交易的消息时,它们也将其添加到本地内存池中。 高级用户可能会避免广播他们的交易,而是将其转发给专门的区块构建者,例如 [Flashbots Auction](https://docs.flashbots.net/flashbots-auction/overview)。 这让他们能在即将生成的区块中组织交易,以实现利润最大化 ([MEV](/developers/docs/mev/#mev-extraction))。 +4. 网络上的验证节点之一是当前时隙的区块提议者(之前已使用 RANDAO 以伪随机方式选择)。 该节点负责构建和广播下一个要添加到以太坊区块链的区块并更新全局状态。 该节点由三部分组成:执行客户端、共识客户端和验证者客户端。 执行客户端将来自本地内存池的交易捆绑到“执行负载”中,并在本地执行它们以生成状态更改。 此信息被传递到共识客户端。在该客户端,执行有效载荷被包装为“信标区块”的一部分。该信标区块还包含有关奖励、惩罚、罚没、认证等的信息,从而使网络能够就链头的区块顺序达成一致。 执行客户端和共识客户端之间的通信在[连接共识和执行客户端](/developers/docs/networking-layer/#connecting-clients)中有更详细的描述。 +5. 其他节点在共识层广播网络上接收新的信标区块, 并将其传递给它们的执行客户端。在执行客户端上,交易在本地重新执行以确保提议的状态更改有效。 然后,验证者客户端会证明该区块有效,并且在他们所见的链中是逻辑上的下一个区块(意即该区块建立在[分叉选择规则](/developers/docs/consensus-mechanisms/pos/#fork-choice)所定义的、拥有最大证明权重的链上)。 该块被添加到证明它的每个节点的本地数据库中。 6. 如果一笔交易已经成为两个检查点之间具有“绝对多数链接”的链的一部分,那么可以认为该交易已经“最终确定”。 检查点发生在每个时段的开始,并且它们的存在是为了考虑到只有活跃验证者的子集在每个时隙中提供证明,但所有活跃验证者在每个时段内都会提供证明。 因此,只有在时段之间才能证明“超过半数链接”(这是指网络上总质押以太币的 66% 同意两个检查点的情况)。 有关最终确定性的更多详细信息,请参见下文。 ## 最终确定性 {#finality} -交易在分布式网络中具有“最终确定性”是指,该交易是区块的一部分,而且除非销毁大量以太币,否则便无法改变。 在权益证明以太坊上,通过“检查点”区块来管理最终确定性。 每个时段中的第一个区块是检查点。 验证者为其认为有效的“检查点对”投票。 如果一对检查点获得了质押以太币总数中三分之二以上的投票,那么这对检查点将被升级。 这两个(目标)中较新的一个会变成“合理”状态。 较旧的一个检查点已经是合理状态,因为它是上一个时段中的“目标”。 现在,这个检查点会升级为“最终确定”状态。 +交易在分布式网络中具有“最终确定性”是指,该交易是区块的一部分,而且除非销毁大量以太币,否则便无法改变。 在权益证明以太坊上,通过“检查点”区块来管理最终确定性。 每个时段中的第一个区块是检查点。 验证者为其认为有效的“检查点对”投票。 如果一对检查点获得了质押以太币总数中三分之二以上的投票,那么这对检查点将被升级。 这两个(目标)中较新的一个会变成“合理”状态。 较旧的一个检查点已经是合理状态,因为它是上一个时段中的“目标”。 现在,这个检查点会升级为“最终确定”状态。 升级检查点的过程由 **[Casper the Friendly Finality Gadget (Casper-FFG)](https://arxiv.org/pdf/1710.09437)** 处理。 Casper-FFG 是用于共识的区块最终性工具。 一旦区块被最终敲定,若没有对大多数质押者进行罚没,该区块就无法回滚或更改,这使得攻击在经济上不可行。 -要回滚最终确定的区块,攻击者将承担至少相当于质押以太币总数三分之一的损失。 这篇[以太坊基金会博文](https://blog.ethereum.org/2016/05/09/on-settlement-finality/)解释了其确切原因。 因为最终确定性需要获得三分之二多数投票,攻击者可以用质押以太币总数的三分之一投票来阻止网络实现最终确定性。 有一种可以防御这种攻击行为的机制:[怠惰惩罚](https://eth2book.info/bellatrix/part2/incentives/inactivity)。 当链超过四个时段无法最终确定时,这项机制会触发。 怠惰惩罚逐渐消耗与其投票与大多数投票相反的验证者的质押以太币,使得大多数验证者重新获得三分之二多数投票并最终确定链。 +要回滚最终确定的区块,攻击者将承担至少相当于质押以太币总数三分之一的损失。 [以太坊基金会的这篇博文](https://blog.ethereum.org/2016/05/09/on-settlement-finality/)中解释了具体原因。 因为最终确定性需要获得三分之二多数投票,攻击者可以用质押以太币总数的三分之一投票来阻止网络实现最终确定性。 有一种机制可以防御这种情况:[怠速泄露 (inactivity leak)](https://eth2book.info/bellatrix/part2/incentives/inactivity)。 当链超过四个时段无法最终确定时,这项机制会触发。 怠惰惩罚逐渐消耗与其投票与大多数投票相反的验证者的质押以太币,使得大多数验证者重新获得三分之二多数投票并最终确定链。 -## 加密经济的安全性 {#crypto-economic-security} +## 加密经济安全 {#crypto-economic-security} 运行验证者是一种承诺。 验证者应当保持足够的硬件和连接,来参与区块的验证和提出。 作为回报,验证者将获得以太币(他们的质押余额增加)。 另一方面,作为验证者参与,也为用户为了个人利益或破坏而攻击网络开辟了新的渠道。 为了防止这种情况,如果验证者在被调用时未能参与,他们就会错过以太币奖励;如果他们有不诚实行为,他们现有的质押可能会被销毁。 主要有两种行为被视为不诚实:在一个时隙中提出多个区块(模棱两可)和提交相互矛盾的认证。 -被罚没以太币的金额取决于大致同一时间受到罚没的验证者数量。 这称为[“相关性惩罚”](https://eth2book.info/bellatrix/part2/incentives/slashing#the-correlation-penalty),相关性惩罚可以是轻微的(单个验证者被罚没质押以太币的 1%),也可以是导致验证者质押的以太币全部被销毁(大额罚没事件)。 这种惩罚在强制退出期执行,首先是第 1 天的立即惩罚(最多 1 个以太币),接着是第 18 天的相关性惩罚,最后是第 36 天的逐出网络。 如果验证者在网络上但不提交投票,他们每天都会受到轻微的认证惩罚。 对于攻击者来说,这些措施都意味着协同攻击的代价将极其高昂。 +被罚没以太币的金额取决于大致同一时间受到罚没的验证者数量。 这被称为[“相关性惩罚”](https://eth2book.info/bellatrix/part2/incentives/slashing#the-correlation-penalty),这种惩罚可能很轻(单个验证者被罚没约 1% 的质押金),也可能导致验证者的质押金被 100% 销毁(大规模罚没事件)。 这种惩罚在强制退出期执行,首先是第 1 天的立即惩罚(最多 1 个以太币),接着是第 18 天的相关性惩罚,最后是第 36 天的逐出网络。 如果验证者在网络上但不提交投票,他们每天都会受到轻微的认证惩罚。 对于攻击者来说,这些措施都意味着协同攻击的代价将极其高昂。 ## 分叉选择 {#fork-choice} -当网络以最佳状态诚信运行时,链头始终只会有一个新区块并且所有验证者都会证明它。 然而,由于网络延迟或因为区块提议者提出多个区块(模棱两可),验证者可能看到不同的链头视图。 因此,共识客户端需要一种算法来确定支持哪一个区块。 权益证明以太坊中使用的算法称为 [LMD-GHOST](https://arxiv.org/pdf/2003.03052.pdf)。它的工作原理是确定其历史记录中具有最大证明权重的分叉。 +当网络以最佳状态诚信运行时,链头始终只会有一个新区块并且所有验证者都会证明它。 然而,由于网络延迟或因为区块提议者提出多个区块(模棱两可),验证者可能看到不同的链头视图。 因此,共识客户端需要一种算法来确定支持哪一个区块。 权益证明以太坊中使用的算法称为 [LMD-GHOST](https://arxiv.org/pdf/2003.03052.pdf),其工作原理是,识别出其历史记录中拥有最大证明权重的分叉。 ## 权益证明和安全性 {#pos-and-security} -正如在工作量证明中一样,权益证明中仍然存在 [51% 攻击](https://www.investopedia.com/terms/1/51-attack.asp)的威胁,但对于攻击者来说风险却更大。 攻击者需要获得 51% 的质押以太币。 然后他们可以通过自己的认证确保他们首选的分叉拥有最多累积认证。 共识客户端使用累积认证的“权重”确定正确的链,所以攻击者能够使他们的分叉成为规范区块。 然而与工作量证明相比,权益证明的优势在于,社区能够灵活地发动反击。 例如,诚实的验证者可以决定继续在非主流链上构建并忽略攻击者的分叉,同时鼓励应用程序、交易所和池也这样做。 他们还可以决定强行将攻击者从网络中移除并销毁攻击者质押的以太币。 这些都是对 51% 攻击的强有力的经济防御措施。 +与工作量证明一样,权益证明也仍然存在 [51% 攻击](https://www.investopedia.com/terms/1/51-attack.asp)的威胁,但对于攻击者来说,这种攻击的风险甚至更高。 攻击者需要获得 51% 的质押以太币。 然后他们可以通过自己的认证确保他们首选的分叉拥有最多累积认证。 共识客户端使用累积认证的“权重”确定正确的链,所以攻击者能够使他们的分叉成为规范区块。 然而与工作量证明相比,权益证明的优势在于,社区能够灵活地发动反击。 例如,诚实的验证者可以决定继续在非主流链上构建并忽略攻击者的分叉,同时鼓励应用程序、交易所和池也这样做。 他们还可以决定强行将攻击者从网络中移除并销毁攻击者质押的以太币。 这些都是对 51% 攻击的强有力的经济防御措施。 除了 51% 攻击,不良行为者也可能尝试其他形式的恶意活动,例如: @@ -71,7 +71,7 @@ lang: zh | 权益证明的加密经济安全性高于工作量证明 | 用户需要运行三种软件才能参与以太坊的权益证明。 | | 需要发行较少的新以太币就可以激励网络参与者 | | -### 与工作量证明相比 {#comparison-to-proof-of-work} +### 与工作量证明的比较 {#comparison-to-proof-of-work} 以太坊原来使用的是工作量证明,但在 2022 年 9 月转换为使用权益证明。 权益证明相较于工作量证明有如下一些优点: @@ -82,18 +82,18 @@ lang: zh - 与工作量证明相比,对不当行为的经济处罚让 51% 攻击的代价变得更高。 - 如果 51% 攻击是为了攻破加密经济的防御,那么社区可以求助于诚实链的社交恢复。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [权益证明机制常见问题](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html) _Vitalik Buterin_ -- [What is Proof of Stake](https://consensys.net/blog/blockchain-explained/what-is-proof-of-stake/) _ConsenSys_ -- [What Proof of Stake Is And Why It Matters](https://bitcoinmagazine.com/culture/what-proof-of-stake-is-and-why-it-matters-1377531463) _Vitalik Buterin_ -- [为什么采用权益证明机制(2020 年 11 月)](https://vitalik.eth.limo/general/2020/11/06/pos2020.html) _Vitalik Buterin_ -- [权益证明:我如何爱上弱主观性](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/) _Vitalik Buterin_ -- [权益证明以太坊的攻击和防御](https://mirror.xyz/jmcook.eth/YqHargbVWVNRQqQpVpzrqEQ8IqwNUJDIpwRP7SS5FXs) -- [权益证明设计原则](https://medium.com/@VitalikButerin/a-proof-of-stake-design-philosophy-506585978d51) _Vitalik Buterin_ -- [视频:Vitalik buterin 向 Lex Fridman 解释权益证明](https://www.youtube.com/watch?v=3yrqBG-7EVE) +- [权益证明常见问题解答](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html) _Vitalik Buterin_ +- [什么是权益证明](https://consensys.net/blog/blockchain-explained/what-is-proof-of-stake/) _ConsenSys_ +- [什么是权益证明及其重要性](https://bitcoinmagazine.com/culture/what-proof-of-stake-is-and-why-it-matters-1377531463) _Vitalik Buterin_ +- [为何选择权益证明 (2020 年 11 月)](https://vitalik.eth.limo/general/2020/11/06/pos2020.html) _Vitalik Buterin_ +- [权益证明:我如何学会爱上弱主观性](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/) _Vitalik Buterin_ +- [权益证明以太坊的攻击与防御](https://mirror.xyz/jmcook.eth/YqHargbVWVNRQqQpVpzrqEQ8IqwNUJDIpwRP7SS5FXs) +- [权益证明设计理念](https://medium.com/@VitalikButerin/a-proof-of-stake-design-philosophy-506585978d51) _Vitalik Buterin_ +- [视频:Vitalik Buterin 向 Lex Fridman 解释权益证明](https://www.youtube.com/watch?v=3yrqBG-7EVE) -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [工作量证明](/developers/docs/consensus-mechanisms/pow/) - [权威证明](/developers/docs/consensus-mechanisms/poa/) diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/keys/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/keys/index.md index 9e3f3d50076..39a7c06b3bf 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/keys/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/keys/index.md @@ -1,20 +1,20 @@ --- -title: 权益证明以太坊中的密钥 -description: 对以太坊权益证明共识机制中使用的密钥的说明 +title: "权益证明以太坊中的密钥" +description: "对以太坊权益证明共识机制中使用的密钥的说明" lang: zh --- 以太坊使用公钥-私钥加密法来保护用户资产的安全。 公钥被用作以太坊地址的基础 — 即,它对公众是可见的,并被用来当作唯一标识符。 私钥(或密钥)只能被帐户拥有者获取。 私钥用于‘签名’交易和数据,以便密码学能证明拥有者批准一个特定私钥的某些行为。 -以太坊的密钥使用 [椭圆曲线加密法](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography) 生成。 +以太坊的密钥是使用[椭圆曲线加密](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography)生成的。 -然而,在以太坊从[工作量证明](/developers/docs/consensus-mechanisms/pow)转换到[权益证明](/developers/docs/consensus-mechanisms/pos)的时候,一种新类型的密钥被加入到以太坊。 原来的密钥仍然像之前那样工作—基于椭圆曲线的密钥确保帐户安全没有变化。 然而,通过质押以太币和运行验证者来参与权益证明时,用户需要一种新类型的密钥。 这一需求是由于扩容挑战带来的,信息需要在大量验证者之间传递,这些信息需要一种密码学方法来方便汇总,以减少网络达成共识所需的沟通数量。 +然而,当以太坊从[工作量证明](/developers/docs/consensus-mechanisms/pow)切换到[权益证明](/developers/docs/consensus-mechanisms/pos)时,以太坊中增加了一种新型密钥。 原来的密钥仍然像之前那样工作—基于椭圆曲线的密钥确保帐户安全没有变化。 然而,通过质押以太币和运行验证者来参与权益证明时,用户需要一种新类型的密钥。 这一需求是由于扩容挑战带来的,信息需要在大量验证者之间传递,这些信息需要一种密码学方法来方便汇总,以减少网络达成共识所需的沟通数量。 -这种新型密钥采用[** Boneh-Lynn-Shacham (BLS) **签名方案](https://wikipedia.org/wiki/BLS_digital_signature)。 BLS 能够对签名进行高效聚合,同时允许对聚合的单个验证者密钥进行逆向工程,它对于管理验证者之间的行动非常理想。 +这种新型密钥使用 [**Boneh-Lynn-Shacham (BLS)** 签名方案](https://wikipedia.org/wiki/BLS_digital_signature)。 BLS 能够对签名进行高效聚合,同时允许对聚合的单个验证者密钥进行逆向工程,它对于管理验证者之间的行动非常理想。 ## 两种类型的验证者密钥 {#two-types-of-keys} -在转换到权益证明之前,以太坊用户只有一个基于椭圆曲线的私钥来访问他们的资金。 随着权益证明的引入,那些希望成为单独质押人的用户也需要一个**验证者密钥**和一个**提款密钥**。 +在转换到权益证明之前,以太坊用户只有一个基于椭圆曲线的私钥来访问他们的资金。 随着权益证明的引入,希望成为独立质押者的用户也需要一个**验证者密钥**和一个**提款密钥**。 ### 验证者密钥 {#validator-key} @@ -25,7 +25,7 @@ lang: zh 验证者私钥的目的是签名链上操作,如区块提议和认证。 因此,这些密钥必须存放在热钱包中。 -这种灵活性的优势是可以快速地把验证者的签名密钥从一台设备转移到另一台,然而,如果密钥丢失或者被盗,盗窃者可以通过这些方式**恶意地行动**: +这种灵活性便于将验证者签名密钥从一台设备快速转移到另一台设备,但如果密钥丢失或被盗,盗窃者就可以通过以下几种方式**恶意行事**: - 通过以下方式罚没验证者: - 作为一个提议者,在同一时隙签名两个不同的信标区块 @@ -33,13 +33,13 @@ lang: zh - 作为一个证明人,签名两个具有相同目标的不同证明 - 促使自愿退出,从而停止验证者质押,并授权提款密钥拥有者获取以太币余额。 -当用户把以太币存入到质押存款合约时,**验证者公钥**会被包含在交易数据中。 这被称为_存款数据_,它让以太坊可以识别验证者。 +当用户将 ETH 存入质押存款合约时,**验证者公钥**会包含在交易数据中。 这被称为_存款数据_,它让以太坊可以识别验证者。 ### 提款凭证 {#withdrawal-credentials} -每个验证者都有一个被称为_提款凭证_的属性。 此 32 字节字段的开头要么是 `0x00`,表示 BLS 提款凭证,要么是 `0x01`,表示指向执行地址的凭证。 +每个验证者都有一个称为_提款凭证_的属性。 此 32 字节字段以 `0x00`(代表 BLS 提款凭证)或 `0x01`(代表指向某个执行地址的凭证)开头。 -具有 `0x00` BLS 密钥的验证者必须更新这些凭证,使其指向执行地址,以便激活从质押进行超额余额支付或全额提款。 这可以通过在初始密钥生成期间在存款数据中提供执行地址,_或者_通过稍后使用提款密钥签署并广播 `BLSToExecutionChange` 信息来实现。 +持有 `0x00` BLS 密钥的验证者必须更新这些凭证,使其指向一个执行地址,才能激活超额余额支付或从质押中全额提款。 这可以通过在初始密钥生成期间在存款数据中提供一个执行地址来实现,_或者_也可以在之后使用提款密钥来签署并广播一条 `BLSToExecutionChange` 消息。 ### 提款密钥 {#withdrawal-key} @@ -50,17 +50,19 @@ lang: zh - 提款**私**钥 - 提款**公**钥 -在将提款凭证更新为 `0x01` 类型之前丢失此密钥,意味着失去对验证者余额的访问权限。 验证者仍然可以对认证和区块进行签名,因为这些操作只需要验证者的私钥,但如果提款密钥丢失,那就几乎没有任何奖励。 +在将提款凭证更新为 `0x01` 类型之前丢失此密钥,意味着将失去对验证者余额的访问权限。 验证者仍然可以对认证和区块进行签名,因为这些操作只需要验证者的私钥,但如果提款密钥丢失,那就几乎没有任何奖励。 把验证者密钥和以太坊帐户密钥分开,可以让一个用户运行多个验证者。 ![验证者密钥示意图](validator-key-schematic.png) +**注意**:目前,要退出质押职责并提取验证者余额,需要使用验证者密钥签署一条[自愿退出消息 (VEM)](https://mirror.xyz/ladislaus.eth/wmoBbUBes2Wp1_6DvP6slPabkyujSU7MZOFOC3QpErs&1)。 然而,[EIP-7002](https://eips.ethereum.org/EIPS/eip-7002) 是一项提案,未来将允许用户通过提款密钥签署退出消息,从而触发验证者退出并提取其余额。 这将减少信任假设,使那些将 ETH 委托给[质押即服务提供商](/staking/saas/#what-is-staking-as-a-service)的质押者能够继续控制自己的资金。 + ## 从助记词派生密钥 {#deriving-keys-from-seed} 如果每次质押 32 个以太币都需要一套新的 2 个完全独立的密钥,那么密钥管理将很快变得难以操作,特别是对于运行多个验证者的用户来说。 相反,多个验证者密钥可以从一个共同的密钥进行派生,并且存储这个密钥就能允许访问多个验证者密钥。 -当[用户访问](https://ethereum.stackexchange.com/questions/19055/what-is-the-difference-between-m-44-60-0-0-and-m-44-60-0)自己的钱包时,[助记符](https://en.bitcoinwiki.org/wiki/Mnemonic_phrase)和路径是用户经常遇到的突出特征。 助记符是一连串的词语,作为私钥的初始种子。 当与其他数据结合时,助记符生成一个被称为‘主密钥’的哈希。 这可以被视为一棵树的根部。 根部的分支可以使用层次路径来派生,从而子节点可以作为其父节点的哈希和它们在树中的索引的组合而存在。 阅读 [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) 和 [BIP-19](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) 基于助记词的密钥生成标准。 +[助记词](https://en.bitcoinwiki.org/wiki/Mnemonic_phrase)和路径是用户在[访问](https://ethereum.stackexchange.com/questions/19055/what-is-the-difference-between-m-44-60-0-0-and-m-44-60-0)自己的钱包时经常遇到的突出功能。 助记符是一连串的词语,作为私钥的初始种子。 当与其他数据结合时,助记符生成一个被称为‘主密钥’的哈希。 这可以被视为一棵树的根部。 根部的分支可以使用层次路径来派生,从而子节点可以作为其父节点的哈希和它们在树中的索引的组合而存在。 阅读关于基于助记词生成密钥的 [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) 和 [BIP-19](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) 标准。 这些路径有以下结构,对于和硬件钱包打过交道的用户来说应该比较熟悉: @@ -74,7 +76,7 @@ m/44'/60'/0'/0` master_key / purpose / coin_type / account / change / address_index ``` -这个逻辑可以使用户把尽可能多的验证者绑定到一个**助记词**,因为虽然树的根部是共同的,但在分支上却可以产生差异化。 用户可以从助记词**派生任意数量的密钥**。 +这个逻辑可以使用户将尽可能多的验证者绑定到单个**助记词**,因为树根可以是共同的,而差异化可以发生在分支上。 用户可以从助记词**派生任意数量的密钥**。 ``` [m / 0] @@ -86,11 +88,13 @@ master_key / purpose / coin_type / account / change / address_index [m / 2] ``` -每个分支都用一个 `/` 来分割,因此 `m/2` 意味着由主密钥开始,接着是分支 2。 在下面的示意图中,一个助记词用来存储三个提款密钥,每个密钥都有两个相关的验证者。 +每个分支由 `/` 分隔,所以 `m/2` 意味着从主密钥开始,然后跟随分支 2。 在下面的示意图中,一个助记词用来存储三个提款密钥,每个密钥都有两个相关的验证者。 ![验证者密钥逻辑](multiple-keys.png) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [由 Carl Beekhuizen 发表的以太坊基金会博客](https://blog.ethereum.org/2020/05/21/keys/) +- [Carl Beekhuizen 撰写的以太坊基金会博客文章](https://blog.ethereum.org/2020/05/21/keys/) - [EIP-2333 BLS12-381 密钥生成](https://eips.ethereum.org/EIPS/eip-2333) +- [EIP-7002:执行层触发的退出](https://web.archive.org/web/20250125035123/https://research.2077.xyz/eip-7002-unpacking-improvements-to-staking-ux-post-merge) +- [大规模密钥管理](https://docs.ethstaker.cc/ethstaker-knowledge-base/scaled-node-operators/key-management-at-scale) diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/pos-vs-pow/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/pos-vs-pow/index.md index 5bcad99bdc1..e8e1f4c7a39 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/pos-vs-pow/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/pos-vs-pow/index.md @@ -1,6 +1,6 @@ --- -title: 权益证明与工作量证明 -description: 以太坊权益证明共识机制与工作量证明共识机制的比较 +title: "权益证明与工作量证明" +description: "以太坊权益证明共识机制与工作量证明共识机制的比较" lang: zh --- @@ -8,23 +8,23 @@ lang: zh 本页解释了以太坊从工作量证明向权益证明过渡的依据以及相关权衡考虑。 -## 安全性 {#security} +## 安全 {#security} 以太坊的研究人员认为权益证明机制比工作量证明机制更安全。 然而,权益证明机制直到最近才在真正的以太坊主网上实现,并且不如工作量证明机制那样久经考验。 以下部分将讨论权益证明的安全模型相对于工作量证明的优缺点。 ### 攻击成本 {#cost-to-attack} -在权益证明机制中,验证者需要在智能合约中托管(质押)至少 32 个以太币。 以太坊可以通过销毁质押的以太币来惩罚不当行为的验证者。 为了达成共识,至少要有总质押数 66%的以太币投票支持一组特定的区块。 被至少 66% 的质押以太币投票支持的区块成为“最终确定”区块,这意味着它们不能被移除或重组。 +在权益证明机制中,验证者需要在智能合约中托管(质押)至少 32 个以太币。 以太坊可以通过销毁质押的以太币来惩罚不当行为的验证者。 为了达成共识,至少要有总质押数 66%的以太币投票支持一组特定的区块。 获得 >=66% 质押投票的区块将成为“最终确定”区块,这意味着它们不能被移除或重组。 攻击网络可能意味着阻止区块链最终确定,或者确保规范链中出现特定的区块组织结构,从而以某种方式使攻击者受益。 这需要攻击者改变达成诚信共识的途径,要么通过积累大量以太币并直接进行投票,要么诱使诚实的验证者按特定方式投票。 除了欺骗诚实验证者的复杂低概率攻击之外,攻击以太坊的成本是攻击者必须积累足够的质押以对他们有利的方式影响共识的成本。 -攻击的最低成本至少为总质押数的 33%。 持有至少达到总质押数 33% 的攻击者可以通过离线来导致最终确定延迟。 这对网络来说是一个相对较小的问题,因为有一种称为“怠惰惩罚”的机制,可以罚没离线验证者的质押,直到多数在线验证者的质押达到总质押数的 66% 并且能够再次确定区块链。 理论上,攻击者可以通过在被要求成为区块生产者时创建两个区块而不是一个,并利用其所有的验证者进行双重投票,从而使用略微超过 33% 的总质押数来形成双重最终确定性。 每个分叉只需要剩余诚实验证者中的 50% 先查看每个区块,因此如果攻击者能够恰到好处地控制消息的时机,他们可能能够最终确定这两条分叉。 这种攻击成功的可能性很低,但如果攻击者能够导致双重最终确定性,以太坊社区将不得不决定跟随其中一条分叉,这种情况下,攻击者的验证者将必然在另一个分叉上遭到罚没。 +最低攻击成本超过总质押量的 33%。 持有超过 33% 总质押的攻击者仅需下线即可造成最终确定性延迟。 这对网络来说是一个相对较小的问题,因为有一种称为“怠惰惩罚”的机制,可以罚没离线验证者的质押,直到多数在线验证者的质押达到总质押数的 66% 并且能够再次确定区块链。 理论上,攻击者可以通过在被要求成为区块生产者时创建两个区块而不是一个,并利用其所有的验证者进行双重投票,从而使用略微超过 33% 的总质押数来形成双重最终确定性。 每个分叉只需要剩余诚实验证者中的 50% 先查看每个区块,因此如果攻击者能够恰到好处地控制消息的时机,他们可能能够最终确定这两条分叉。 这种攻击成功的可能性很低,但如果攻击者能够导致双重最终确定性,以太坊社区将不得不决定跟随其中一条分叉,这种情况下,攻击者的验证者将必然在另一个分叉上遭到罚没。 -如果拥有总质押数的 33%以上,攻击者有机会对以太坊网络产生轻微(最终确定性延迟)或更严重(双重最终确定性)的影响。 网络上质押了超过 14,000,000 个以太币,而且代表性的价格为每个以太币 1000 美元,那么进行这些攻击的最低成本为 `1000 x 14,000,000 x 0.33 = $4,620,000,000`。 攻击者会由于受到罚没而损失这一大笔钱,并且可能被网络驱逐。 要再次发起攻击,攻击者必须(再次)积累超过 33% 的质押数并(再次)销毁。 每次尝试攻击网络将耗费超过 46 亿美元(每个以太币的价格为 1000 美元,总共质押了 1400 万个以太币)。 在攻击者受到罚没时,他们也会被从网络中驱逐,而且他们必须加入激活队列才能重新加入网络。 这意味着重复攻击的频次不仅受到攻击者积攒超过 33% 的总质押数快慢的限制,还受到将其所有验证者加入网络所需的时间的限制。 每次进行攻击时,攻击者将变得更穷,而其他社区成员则由于产生的供应冲击变得更富。 +拥有超过 33% 的总质押,攻击者就有可能对以太坊网络产生轻微(最终确定性延迟)或更严重(双重最终确定性)的影响。 网络上质押了超过 14,000,000 ETH,以每个 ETH 1000 美元的代表性价格计算,发起这些攻击的最低成本为 `1000 x 14,000,000 x 0.33 = $4,620,000,000`。 攻击者会由于受到罚没而损失这一大笔钱,并且可能被网络驱逐。 要再次发起攻击,他们必须(再次)积累超过 33% 的质押并(再次)销毁它。 每次攻击网络的尝试都将花费超过 46 亿美元(按 1000 美元/ETH 和 1400 万 ETH 质押计算)。 在攻击者受到罚没时,他们也会被从网络中驱逐,而且他们必须加入激活队列才能重新加入网络。 这意味着重复攻击的频次不仅受到攻击者积攒超过 33% 的总质押数快慢的限制,还受到将其所有验证者加入网络所需的时间的限制。 每次进行攻击时,攻击者将变得更穷,而其他社区成员则由于产生的供应冲击变得更富。 其他攻击需要的以太币要多得多,如 51% 攻击或使用超过 66% 的总质押数进行的最终确定性逆转,它们对攻击者来说代价更高。 -对比工作量证明。 在工作量证明以太坊上,发起攻击的成本是持续拥有超过 50% 的总网络算力的成本。 这相当于硬件和足够算力的运行成本,以持续地超越其他矿工来计算工作量证明解决方案。 以太坊主要是使用图形处理器 (GPU) 进行挖矿,而不是应用型专用集成电路 (ASIC),这降低了成本(尽管如果以太坊继续采用工作量证明机制,ASIC 挖矿可能会变得更受欢迎)。 要攻击工作量证明以太坊网络,攻击者必须购买大量硬件设备,并支付电费来运行这些设备。然而,总成本仍然比累积足够以太币以发起攻击的成本低。 工作量证明机制下,51% 攻击的成本比权益证明机制下大约低 [20 倍](https://youtu.be/1m12zgJ42dI?t=1562)。 如果检测到攻击,并且区块链进行硬分叉以消除攻击者的更改,那么攻击者可以反复使用相同的硬件攻击新的分叉。 +对比工作量证明。 在工作量证明以太坊上,发起攻击的成本是持续拥有超过 50% 的总网络算力的成本。 这相当于硬件和足够算力的运行成本,以持续地超越其他矿工来计算工作量证明解决方案。 以太坊主要是使用图形处理器 (GPU) 进行挖矿,而不是应用型专用集成电路 (ASIC),这降低了成本(尽管如果以太坊继续采用工作量证明机制,ASIC 挖矿可能会变得更受欢迎)。 要攻击工作量证明以太坊网络,攻击者必须购买大量硬件设备,并支付电费来运行这些设备。然而,总成本仍然比累积足够以太币以发起攻击的成本低。 在工作量证明中,51% 攻击的成本比在权益证明中~[低约 20 倍](https://youtu.be/1m12zgJ42dI?t=1562)。 如果检测到攻击,并且区块链进行硬分叉以消除攻击者的更改,那么攻击者可以反复使用相同的硬件攻击新的分叉。 ### 复杂性 {#complexity} @@ -36,7 +36,7 @@ lang: zh 权益证明比工作量证明复杂,这意味着需要处理更多潜在的攻击途径。 与单个对等网络连接客户端不同,权益证明中存在两个对等网络,分别实现不同的协议。 在每个时隙内预先选择一个特定的验证者提议一个区块,可能会导致拒绝服务攻击,其中大量的网络流量会使该特定验证者下线。 -还有一些方法可以让攻击者精心安排他们的区块或认证的发布时间,以便诚实网络中有一定部分接收到这些信息,影响他们以特定方式投票。 最后一点,攻击者可以简单地积攒足够多的以太币进行质押,并主导共识机制。 所有这些[攻击途径都有相应的防御措施](/developers/docs/consensus-mechanisms/pos/attack-and-defense),但在工作量证明机制中并不存在这些需要防御的攻击途径。 +还有一些方法可以让攻击者精心安排他们的区块或认证的发布时间,以便诚实网络中有一定部分接收到这些信息,影响他们以特定方式投票。 最后一点,攻击者可以简单地积攒足够多的以太币进行质押,并主导共识机制。 每一种[攻击途径都有相应的防御措施](/developers/docs/consensus-mechanisms/pos/attack-and-defense),但在工作量证明机制下,这些攻击途径并不存在,也就无需防御。 ## 去中心化 {#decentralization} @@ -62,8 +62,8 @@ lang: zh -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [Vitalik 的权益证明设计理念](https://medium.com/@VitalikButerin/a-proof-of-stake-design-philosophy-506585978d51) -- [Vitalik 的权证明常见问题](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-is-proof-of-stake) -- [权益证明与工作量证明的“简介”视频](https://www.youtube.com/watch?v=M3EFi_POhps) +- [Vitalik 的权益证明常见问题解答](https://vitalik.eth.limo/general/2017/12/31/pos_faq.html#what-is-proof-of-stake) +- [关于 PoS 与 PoW 的“Simply Explained”视频](https://www.youtube.com/watch?v=M3EFi_POhps) diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/index.md index 9a334def4f6..cbbc3bef775 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/index.md @@ -1,10 +1,10 @@ --- -title: 权益证明机制下的奖励和惩罚 -description: 了解关于权益证明以太坊的协议内激励。 +title: "权益证明机制下的奖励和惩罚" +description: "了解关于权益证明以太坊的协议内激励。" lang: zh --- -以太坊使用其原生加密货币以太币 (ETH) 来保证其安全。 希望参与验证区块和识别链头的节点运营商,在以太坊上的[存款合约](/staking/deposit-contract/)中存入以太币。 他们运行验证者软件检查从点对点网络接收到的新区块的有效性,以及应用分叉选择算法来识别链头,然后收到用以太币支付的报酬。 +以太坊使用其原生加密货币以太币 (ETH) 来保证其安全。 希望参与验证区块和识别链头的节点运营商,将以太币存入以太坊上的[存款合约](/staking/deposit-contract/)。 他们运行验证者软件检查从点对点网络接收到的新区块的有效性,以及应用分叉选择算法来识别链头,然后收到用以太币支付的报酬。 对于验证者来说有两个主要角色:1) 检查新区块并且“证明”它们是否有效,2) 当从整个验证者池子被随机选中时,提议新的区块。 如果验证者无法完成其中任何一项的任务,将错过以太币的支付。 验证者有时也需要负责签名聚合以及参与同步委员会。 @@ -18,49 +18,49 @@ lang: zh ### 奖励 {#rewards} -当验证者作出与大多数其他验证者一致的投票时,当验证者提议区块时,以及当验证者参与同步委员会时,他们会受到奖励。 每个时段奖励的数额是从 `base_reward` 计算的。 这是计算其他奖励的基本单位。 `base_reward` 代表了在每个时段的最佳条件下每个验证者的平均奖励。 这是根据验证者的有效余额以及活跃验证者的总数计算的,如下所示: +当验证者作出与大多数其他验证者一致的投票时,当验证者提议区块时,以及当验证者参与同步委员会时,他们会受到奖励。 每个时段奖励的数额是从 `base_reward` 计算的。 这是计算其他奖励的基本单位。 `base_reward` 代表了验证者在每个时段的最佳条件下获得的平均奖励。 这是根据验证者的有效余额以及活跃验证者的总数计算的,如下所示: ``` base_reward = effective_balance * (base_reward_factor / (base_rewards_per_epoch * sqrt(sum(active_balance)))) ``` -其中,`base_reward_factor` 是 64,`base_rewards_per_epoch` 是 4,`sum(active balance)` 是所有活跃验证者的质押以太币总数。 +其中 `base_reward_factor` 是 64,`base_rewards_per_epoch` 是 4,`sum(active balance)` 是所有活跃验证者质押的以太币总额。 -这意味着基础奖励与验证者的有效余额成正比,与网络中的验证者数量成反比。 验证者越多,整体发行量越大(如 `sqrt(N)`),但每个验证者的 `base_reward` 越小(如`1/sqrt(N)`)。 这些因素影响质押节点的年化利率。 在 [Vitalik 的笔记](https://notes.ethereum.org/@vbuterin/rkhCgQteN?type=view#Base-rewards)阅读这方面的原理。 +这意味着基础奖励与验证者的有效余额成正比,与网络中的验证者数量成反比。 验证者越多,总发行量越大(如 `sqrt(N)`),但每个验证者的 `base_reward` 越小(如 `1/sqrt(N)`)。 这些因素影响质押节点的年化利率。 请在 [Vitalik 的笔记](https://notes.ethereum.org/@vbuterin/rkhCgQteN?type=view#Base-rewards)中阅读相关基本原理。 总奖励由五个部分之和组成,每个部分都有一个权重,决定每个部分在总奖励中的比重。 这些部分是: ``` -1. 来源投票:验证者给正确的来源检查点进行了及时投票 -2. 目标投票:验证者给正确的目标检查点进行了及时投票 -3. 头部投票:验证者给正确的头部区块进行了及时投票 +1. 来源投票:验证者及时对正确的来源检查点进行投票 +2. 目标投票:验证者及时对正确的目标检查点进行投票 +3. 头部投票:验证者及时对正确的头部区块进行投票 4. 同步委员会奖励:验证者参与了同步委员会 -5. 提议者奖励:验证者在正确的时隙提议了区块 +5. 提议者奖励:验证者在正确的时隙中提议了区块 ``` 每个部分的权重如下所示: ``` -TIMELY_SOURCE_WEIGHT uint64(14) -TIMELY_TARGET_WEIGHT uint64(26) -TIMELY_HEAD_WEIGHT uint64(14) -SYNC_REWARD_WEIGHT uint64(2) -PROPOSER_WEIGHT uint64(8) +TIMELY_SOURCE_WEIGHT uint64(14) +TIMELY_TARGET_WEIGHT uint64(26) +TIMELY_HEAD_WEIGHT uint64(14) +SYNC_REWARD_WEIGHT uint64(2) +PROPOSER_WEIGHT uint64(8) ``` -这些权重加起来等于 64。 奖励的计算方法是适用权重的总和除以 64。 如果验证者及时给来源、目标和头部投票,提议一个区块以及参与同步委员会,他们就能获取 `64/64 * base_reward == base_reward`。 然而,验证者通常不是区块提议者,所以它们的最大奖励是 `64-8 /64 * base_reward == 7/8 * base_reward`。 既不是区块提议者,也不参与同步委员会的验证者能收到 `64-8-2 / 64 * base_reward == 6.75/8 * base_reward`。 +这些权重加起来等于 64。 奖励的计算方法是适用权重的总和除以 64。 及时为来源、目标和头部投票、提议了一个区块并参与同步委员会的验证者可以收到 `64/64 * base_reward == base_reward`。 然而,验证者通常不是区块提议者,所以他们的最大奖励是 `64-8 /64 * base_reward == 7/8 * base_reward`。 既不是区块提议者,也不在同步委员会中的验证者可以收到 `64-8-2 / 64 * base_reward == 6.75/8 * base_reward`。 -还增加一个额外奖励来激励快速认证。 这就是 `inclusion_delay_reward`。 这个值等于 `base_reward` 乘以 `1/delay`,其中 `delay` 是分隔区块提议和认证的时隙数。 例如,如果在区块提议的一个时隙内提交认证,那么认证者将获得 `base_reward * 1/1 == base_reward`。 如果认证在下一个时隙到达,认证者将收到 `base_reward * 1/2`,以此类推。 +还增加一个额外奖励来激励快速认证。 这就是 `inclusion_delay_reward`。 这个值等于 `base_reward` 乘以 `1/delay`,其中 `delay` 是区块提议和证明之间的时隙数。 例如,如果证明在区块提议后的一个时隙内提交,证明者将收到 `base_reward * 1/1 == base_reward`。 如果证明在下一个时隙到达,证明者将收到 `base_reward * 1/2`,以此类推。 -包含在区块中的**每一个有效认证**都能让区块提议者获得 `8 / 64 * base_reward`,所以奖励的实际值与证明验证者的数量成比例。 通过在所提议区块中包含其他验证者的不良行为证据,区块提议者也能增加奖励。 这些奖励是鼓励验证者诚实的“胡萝卜”。 一个包含罚没的区块提议者将被奖励 `slashed_validators_effective_balance / 512`。 +区块提议者因其区块中包含的**每个有效证明**而收到 `8 / 64 * base_reward`,因此奖励的实际价值与进行证明的验证者数量成正比。 通过在所提议区块中包含其他验证者的不良行为证据,区块提议者也能增加奖励。 这些奖励是鼓励验证者诚实的“胡萝卜”。 包含罚没信息的区块提议者将获得 `slashed_validators_effective_balance / 512` 的奖励。 ### 惩罚 {#penalties} 到目前为止,我们已经考虑了行为良好的验证者,但对于那些没有及时作出头部、来源和目标投票或者投票非常慢的验证者呢? -错失目标和来源投票的惩罚等于认证者提交这些投票时获取到的奖励。 这意味着没有奖励会添加到他们的余额中,反而会从余额中移除同等价值。 错失头部投票没有惩罚(即,头部投票只有奖励,没有惩罚)。 也没有与 `inclusion_delay` 值相关的惩罚 - 只是不会把奖励添加到验证者余额。 区块提议失败也没有惩罚。 +错失目标和来源投票的惩罚等于认证者提交这些投票时获取到的奖励。 这意味着没有奖励会添加到他们的余额中,反而会从余额中移除同等价值。 错失头部投票没有惩罚(即头部投票只奖励,不惩罚)。 没有与 `inclusion_delay` 相关的惩罚 — 奖励只是不会被添加到验证者的余额中。 区块提议失败也没有惩罚。 -在[共识规范](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md)中阅读更多关于奖励和惩罚的内容。 Bellatrix 升级调整了奖励和惩罚 - 观看 Danny Ryan 和 Vitalik 在[“以太坊改进提案解读”视频](https://www.youtube.com/watch?v=iaAEGs1DMgQ)中对此的讨论。 +请在[共识规范](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md)中阅读更多关于奖励和惩罚的信息。 奖励和惩罚在 Bellatrix 升级中进行了调整——观看 Danny Ryan 和 Vitalik 在这个 [Peep an EIP 视频](https://www.youtube.com/watch?v=iaAEGs1DMgQ)中对此的讨论。 ## 罚没 {#slashing} @@ -70,7 +70,7 @@ PROPOSER_WEIGHT uint64(8) - 认证一个“包围”另一个区块的区块(有效地更改历史) - 通过证明同一个区块的两名候选人进行“双重投票” -如果这些行为被检测到,验证者就会被罚没。 这意味着 1/32 的质押以太币(最多是 1 个以太币)将被立即销毁,然后一个为期36天的移除期开始。 在移除期内,验证者的质押将逐渐流失。 在中间点(第 18 天),会有一个额外的惩罚,其幅度与罚没事件之前 36 天内所有被罚没验证者的质押以太币总数成比例。 这意味着被罚没的验证者越多,罚没的幅度就会增加。 最大的罚没幅度是所有罚没验证者的全部有效余额(即,如果有很多的验证者被罚没,那么他们将失去全部的质押)。 另一方面,一次单独的罚没事件只会销毁一小部分的验证者质押。 这个与罚没验证者的数量成比例的中间点惩罚被称为“相关性惩罚”。 +如果这些行为被检测到,验证者就会被罚没。 这意味着,对于一个质押 32 个ETH 的验证者,如果准备撤出质押节点(36 天的等待周期), 0.0078125 ETH 会立即被销毁(按活跃余额线性缩放)。 在移除期内,验证者的质押将逐渐流失。 在中间点(第 18 天),会有一个额外的惩罚,其幅度与罚没事件之前 36 天内所有被罚没验证者的质押以太币总数成比例。 这意味着被罚没的验证者越多,罚没的幅度就会增加。 最大罚没额是所有被罚没验证者的全部有效余额(即,如果有很多验证者被罚没,他们可能会失去全部质押)。 另一方面,一次单独的罚没事件只会销毁一小部分的验证者质押。 这个与罚没验证者的数量成比例的中间点惩罚被称为“相关性惩罚”。 ## 怠惰惩罚 {#inactivity-leak} @@ -78,12 +78,13 @@ PROPOSER_WEIGHT uint64(8) 共识机制的奖励、惩罚和罚没的设计,可鼓励个人验证者做出正确行为。 然而,从这些设计选择中催生了一个这样一个系统:它强烈激励在多个客户端平均分配验证者,并应强烈抑制单一客户端的主导地位。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [升级以太坊:激励层](https://eth2book.info/altair/part2/incentives) -- [以太坊混合型 Casper 协议中的激励措施](https://arxiv.org/pdf/1903.04205.pdf) -- [Vitalik 的注释规范](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#rewards-and-penalties-1) -- [防止以太坊 2 罚没的技巧](https://medium.com/prysmatic-labs/eth2-slashing-prevention-tips-f6faa5025f50) +- [以太坊混合 Casper 协议中的激励机制](https://arxiv.org/pdf/1903.04205.pdf) +- [Vitalik 的注释版规范](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#rewards-and-penalties-1) +- [Eth2 罚没预防技巧](https://medium.com/prysmatic-labs/eth2-slashing-prevention-tips-f6faa5025f50) +- [EIP-7251 下的罚没惩罚分析](https://ethresear.ch/t/slashing-penalty-analysis-eip-7251/16509) _来源_ diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/weak-subjectivity/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/weak-subjectivity/index.md index fbc3b77473c..5426496a6e9 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/weak-subjectivity/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pos/weak-subjectivity/index.md @@ -1,6 +1,6 @@ --- -title: 弱主观性 -description: 关于弱主观性及其在权益证明版以太坊中的作用。 +title: "弱主观性" +description: "关于弱主观性及其在权益证明版以太坊中的作用。" lang: zh --- @@ -8,15 +8,15 @@ lang: zh ## 前提条件 {#prerequisites} -理解此页必须首先理解[权益证明](/developers/docs/consensus-mechanisms/pos/)的基础知识。 +要理解本页内容,首先需要了解[权益证明](/developers/docs/consensus-mechanisms/pos/)的基础知识。 -## 弱主观性解决了哪些问题? {#problems-ws-solves} +## 弱主观性解决了哪些问题? 弱主观性解决的问题 {#problems-ws-solves} 主观性是权益证明区块链所固有的,因为从多个分叉中选择正确的链是通过计算历史投票来完成的。 这使区块链暴露在多个攻击途径下,包括以下类型的长期攻击:很早就参与了区块链的节点维护一个替代分叉,并会在稍后因自己的利益释放此分叉。 另外,如果 33% 的验证者取出他们的质押物,但仍继续证明和生产区块,他们可能会生成一个与规范链相冲突的替代分叉。 新的节点或已经离线很长时间的节点可能不知道这些攻击验证者已经取出了他们的资金,所以攻击者可能会诱骗他们跟随不正确的链。 以太坊可以通过施加限制来解决这些攻击途径,因为这些限制可将机制的主观方面(也就是信任假设)降至最低。 ## 弱主观性检查点 {#ws-checkpoints} -在权益证明版以太坊中,弱主观性的实现要用到“弱主观性检查点”, 即网络上所有节点都同意加入规范链的状态根。 它们的作用与创世区块的"普遍事实"相同,只是它们不在区块链的创世块位置上。 分叉选择算法相信该检查点中确定的区块链状态是正确的,并且独立和客观地验证了从该点开始的区块链。 检查点起到了"回滚限制"的作用,因为位于弱主观性检查点之前的区块不能改变。 如此,只需将远程分叉作为机制设计的一部分界定为无效,就能破坏远程攻击。 确保弱主观性检查点之间相隔的距离小于验证者提款期,这样便可保证分叉链的验证者在提取质押前至少被罚没一些阈值量,且新验证者不能被已经提取质押的验证者骗到错误的分叉上。 +在权益证明版以太坊中,弱主观性的实现要用到“弱主观性检查点”, 即网络上所有节点都同意加入规范链的状态根。 与创世区块一样,它们起到相同的“普遍真理”作用,只是它们并不位于区块链的创世位置。 分叉选择算法相信该检查点中确定的区块链状态是正确的,并且独立和客观地验证了从该点开始的区块链。 检查点起到了"回滚限制"的作用,因为位于弱主观性检查点之前的区块不能改变。 如此,只需将远程分叉作为机制设计的一部分界定为无效,就能破坏远程攻击。 确保弱主观性检查点之间相隔的距离小于验证者提款期,这样便可保证分叉链的验证者在提取质押前至少被罚没一些阈值量,且新验证者不能被已经提取质押的验证者骗到错误的分叉上。 ## 弱主观性检查点和最终确定区块的区别 {#difference-between-ws-and-finalized-blocks} @@ -30,10 +30,10 @@ lang: zh 最终,可以从其他节点请求检查点;也许另一个运行完整节点的以太坊用户可以提供一个检查点,然后验证者可以根据区块浏览器的数据进行验证。 总的来说,信任弱主观性检查点的提供者和信任客户端开发人员可视为同样的问题, 即所需的整体信任度很低。 需要注意的是,这些考虑只有在大多数验证者密谋生成另一个区块链分叉这种不太可能的情况下才变得重要。 在任何其他情况下,只有一条以太坊链可以选择。 -## 延伸阅读 {#further-reading} +## 扩展阅读 {#further-reading} -- [以太坊 2 中的弱主观性](https://notes.ethereum.org/@adiasg/weak-subjectvity-eth2) -- [Vitalik:我如何爱上弱主观性](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/) -- [弱主观性(Teku 文档)](https://docs.teku.consensys.net/en/latest/Concepts/Weak-Subjectivity/) -- [阶段 0 的弱主观性指南](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/weak-subjectivity.md) -- [以太坊 2.0 的弱主观性分析](https://github.com/runtimeverification/beacon-chain-verification/blob/master/weak-subjectivity/weak-subjectivity-analysis.pdf) +- [Eth2 中的弱主观性](https://notes.ethereum.org/@adiasg/weak-subjectvity-eth2) +- [Vitalik:我是如何爱上弱主观性的](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/) +- [弱主观性 (Teku 文档)](https://docs.teku.consensys.io/concepts/weak-subjectivity) +- [Phase-0 弱主观性指南](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/weak-subjectivity.md) +- [以太坊 2.0 弱主观性分析](https://github.com/runtimeverification/beacon-chain-verification/blob/master/weak-subjectivity/weak-subjectivity-analysis.pdf) diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/index.md index 0799938120d..c0a73bf13ae 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/index.md @@ -1,55 +1,55 @@ --- -title: 工作量证明 (PoW) -description: 工作量证明共识协议的解释及其在以太坊中的作用。 +title: "工作量证明 (PoW)" +description: "工作量证明共识协议的解释及其在以太坊中的作用。" lang: zh --- -以太坊网络最初采用一种称为**[工作量证明 (PoW)](/developers/docs/consensus-mechanisms/pow)** 的共识机制。 这种机制允许以太坊网络的节点就以太坊区块链上记录的所有信息的状态达成共识,并防止某些产生经济影响的攻击。 然而,以太坊在 2022 年终结了工作量证明并开始采用[权益证明](/developers/docs/consensus-mechanisms/pos)。 +以太坊网络最初采用一种涉及\*\*[工作量证明 (PoW)](/developers/docs/consensus-mechanisms/pow)\*\*的共识机制。 这种机制允许以太坊网络的节点就以太坊区块链上记录的所有信息的状态达成共识,并防止某些产生经济影响的攻击。 然而,以太坊于 2022 年弃用工作量证明,并转而开始使用[权益证明](/developers/docs/consensus-mechanisms/pos)。 - 工作量证明现已弃用。 以太坊不再使用工作量证明作为其部分共识机制。 它改用权益证明。 阅读有关[权益证明](/developers/docs/consensus-mechanisms/pos/)和[质押](/staking/)的更多信息。 + 工作量证明现已弃用。 以太坊不再使用工作量证明作为其部分共识机制。 它改用权益证明。 阅读更多关于[权益证明](/developers/docs/consensus-mechanisms/pos/)和[质押](/staking/)的信息。 ## 前提条件 {#prerequisites} -为了更好地理解此页面,建议提前阅读[交易](/developers/docs/transactions/)、[区块](/developers/docs/blocks/)和[共识机制](/developers/docs/consensus-mechanisms/)。 +为了更好地理解本页内容,建议您先阅读有关[交易](/developers/docs/transactions/)、[区块](/developers/docs/blocks/)和[共识机制](/developers/docs/consensus-mechanisms/)的相关信息。 -## 什么是工作量证明 (POW) {#what-is-pow} +## 什么是工作量证明 (PoW)? {#what-is-pow} -中本聪共识采用工作量证明,一度允许去中心化的以太坊网络对帐户余额和交易顺序等达成共识(即所有节点都同意)。 这种机制防止用户“重复支付”他们的货币,同时确保极难攻击或操作以太坊区块链。 这些安全特性现在由权益证明提供,后者采用称为 [Gasper](/developers/docs/consensus-mechanisms/pos/gasper/) 的共识机制。 +采用工作量证明的中本聪共识,是曾允许去中心化以太坊网络就帐户余额和交易顺序等达成共识(即所有节点都同意)的机制。 这种机制防止用户“重复支付”他们的货币,同时确保极难攻击或操作以太坊区块链。 这些安全特性现在由权益证明提供,后者采用称为 [Gasper](/developers/docs/consensus-mechanisms/pos/gasper/) 的共识机制。 -## 工作量证明和挖矿 {#pow-and-mining} +## 工作量证明与挖矿 {#pow-and-mining} 工作量证明是一种基础性算法,它为矿工在工作量证明区块链上进行的工作设置难度和规则。 挖矿就是“工作”本身。 挖矿是向区块链中添加有效区块。 这很重要,因为链的长度有助于网络跟随区块链的正确分叉。 “工作”完成得越多,链越长,区块编号就越大,就更能确定网络达到最新状态。 -[有关挖矿的更多信息](/developers/docs/consensus-mechanisms/pow/mining/) +[深入了解挖矿](/developers/docs/consensus-mechanisms/pow/mining/) ## 以太坊的工作量证明机制如何运作? {#how-it-works} 以太坊交易处理到区块中。 在现已弃用的工作量证明以太坊中,每个区块包含: - 区块的难度,例如:3,324,092,183,262,715 -- 混合哈希(mixHash),例如:`0x44bca881b07a6a09f83b130798072441705d9a665c5ac8bdf2f39a3cdf3bee29` -- nonce--例如:`0xd3ee432b4fb3d26b` +- 混合哈希 (mixHash)——例如:`0x44bca881b07a6a09f83b130798072441705d9a665c5ac8bdf2f39a3cdf3bee29` +- 随机数 (nonce)——例如:`0xd3ee432b4fb3d26b` 这些区块数据与工作量证明直接相关。 -### 工作量证明机制 {#the-work} +### 工作量证明中的“工作” {#the-work} 工作量证明协议 Ethash 要求矿工经过激烈的试错竞赛,找到一个区块的随机数。 只有具备有效随机数的区块才能加入区块链中。 -当矿工们争相创建区块时,他们会反复通过一个数学函数放置一个数据集,此数据集只能通过下载和运行整条区块链获得(矿工们都是这样做的)。 该数据集用来产生一个低于目标随机数的混合哈希,而此目标随机数由区块难度决定。 做到这些最好的方式是试错。 +当矿工们争相创建区块时,他们会反复通过一个数学函数放置一个数据集,此数据集只能通过下载和运行整条区块链获得(矿工们都是这样做的)。 该数据集用来产生一个低于目标随机数的混合哈希,而此目标随机数由区块难度决定。 找到这个满足条件的哈希值的最好的方式是试错。 难度决定了哈希的目标值。 目标值越小,有效哈希的集合就越小。 一旦生成哈希,其他矿工和客户端就很容易验证哈希。 即使一条交易记录出现改变,整个哈希就会变得完全不同,表示出现欺诈。 哈希使得欺诈更容易被发现。 此外,工作量证明作为一个流程,同样有效威慑了对区块链的攻击。 -### 工作量证明和安全性 {#security} +### 工作量证明与安全性 {#security} 激励矿工在以太坊主链上挖矿。 对于一小部分矿工而言,没有任何激励措施让他们去开辟一条自己的新链 - 因为这破坏了体系。 区块链依赖于唯一状态来判断真实性。 @@ -57,11 +57,11 @@ lang: zh 要持续创建恶意但有效的区块,恶意矿工将需要超过 51% 的网络挖矿算力才能击败其他人。 这种海量的“工作”需要大量昂贵的算力,而且消耗的能源甚至可能超过攻击所得的收益。 -### 工作量证明的经济模型 {#economics} +### 工作量证明的经济学 {#economics} 工作量证明还负责向系统中发行新货币并激励矿工完成工作。 -自[君士坦丁堡升级](/ethereum-forks/#constantinople)以来,成功创建区块的矿工将获得两个新铸造的以太币及部分交易费作为奖励。 叔块也会获得 1.75 个以太币的补偿。 叔块是由一个矿工创建的有效区块,几乎与此同时另一个矿工创建了规范区块。要确定规范区块,最终取决于哪条链构建于第一个区块之上。 叔块通常是由于网络延迟而出现。 +自 [君士坦丁堡升级](/ethereum-forks/#constantinople) 以来,成功创建区块的矿工会获得两个新铸造的 ETH 和部分交易费作为奖励。 叔块也会获得 1.75 个以太币的补偿。 叔块是由一个矿工创建的有效区块,几乎与此同时另一个矿工创建了规范区块。要确定规范区块,最终取决于哪条链构建于第一个区块之上。 叔块通常是由于网络延迟而出现。 ## 最终确定性 {#finality} @@ -69,21 +69,21 @@ lang: zh 由于矿工以去中心化的方式工作,有可能同时开采出两个有效区块。 这就产生了一个临时分叉。 最后,在后续区块被开采出并添加到其中一条链使其更长时,这条链就会成为被接受的链。 -但更复杂的是,在临时分叉上被拒绝的交易可能没有包含在被接受的主链上。 这意味着区块是可逆的。 因此,最终确定性是指你在认为交易不可逆之前需要等待的一段时间。 在以前的工作量证明以太坊中,一个特定区块 `N` 之后开采出的区块越多,就更加确信区块 `N` 内的交易是成功的且不可回滚。 现在,基于权益证明机制,最终确定是区块的明确属性,而不再是概率性的。 +但更复杂的是,在临时分叉上被拒绝的交易可能没有包含在被接受的主链上。 这意味着区块可逆。 因此,最终确定性是指你在认为交易不可逆之前需要等待的一段时间。 在以前采用工作量证明的以太坊中,在特定区块 `N` 之上挖出的区块越多,`N` 区块中的交易成功且不会被回滚的确定性就越高。 现在,基于权益证明机制,最终确定是区块的明确属性,而不再是概率性的。 -## 工作量证明能源消耗 {#energy} +## 工作量证明的能源消耗 {#energy} -对工作量证明提出的一项主要批评是保证网络安全所需的能源消耗。 为了维持安全和去中心化,采用工作量证明的以太坊每年消耗大量能源。 在即将过渡到权益证明之际,以太坊矿工的总能源消耗大约为 70 亿千瓦时/年(大约与捷克共和国相当 - 数据来自 2022 年 7 月 18 日 [digiconomist](https://digiconomist.net/))。 +对工作量证明提出的一项主要批评是保证网络安全所需的能源消耗。 为了维持安全和去中心化,采用工作量证明的以太坊每年消耗大量能源。 在切换到权益证明前不久,以太坊矿工每年总共消耗约 70 TWh/年(与捷克共和国大致相同——根据 [digiconomist](https://digiconomist.net/) 于 2022 年 7 月 18 日发布的数据)。 ## 优点和缺点 {#pros-and-cons} -| 优点 | 缺点 | -| -------------------------------------------------------------------------------------------------------------------- | --------------------------------- | -| 工作量证明并无对错。 你不需要以太币来启动,出块奖励允许你从 0 ETH 获得正的收益。 而在[权益证明](/developers/docs/consensus-mechanisms/pos/)中,你需要以太币来启动获取收益的过程。 | 工作量证明消耗了大量能源,对环境不利。 | -| 工作量证明是一个经过考验和测试的共识机制,多年来一直保持了比特币和以太坊的安全性和去中心化。 | 如果你想要挖矿,需要花大量的启动资金去购买专业设备。 | -| 与权益证明方式相比,工作量证明是比较容易实施的。 | 因为算力的不断增加,矿池可能会主导挖矿过程,导致中心化和安全风险。 | +| 优点 | 缺点 | +| ------------------------------------------------------------------------------------------------------------- | --------------------------------- | +| 工作量证明并无对错。 你不需要以太币来启动,出块奖励允许你从 0 ETH 获得正的收益。 使用[权益证明](/developers/docs/consensus-mechanisms/pos/),你需要先拥有 ETH。 | 工作量证明消耗了大量能源,对环境不利。 | +| 工作量证明是一个经过考验和测试的共识机制,多年来一直保持了比特币和以太坊的安全性和去中心化。 | 如果你想要挖矿,需要花大量的启动资金去购买专业设备。 | +| 与权益证明方式相比,工作量证明是比较容易实施的。 | 因为算力的不断增加,矿池可能会主导挖矿过程,导致中心化和安全风险。 | -## 与权益证明对比 {#compared-to-pos} +## 与权益证明的比较 {#compared-to-pos} 从更高层面上看,权益证明和工作量证明的最终目标相同,即帮助去中心化网络安全地达成共识。 但它们在实现方式和人员上有些不同: @@ -92,23 +92,23 @@ lang: zh - 验证者不会竞争创建区块,而是由算法随机选择。 - 终局性是很清晰的:在特定的检查节点,如果 2/3 验证者确定了区块,这个区块将被视为最终状态。 验证者必须在区块压上自己全部质押,因此如果他们试图串通更改区块链,他们就会失去他们的全部质押。 -[有关权益证明的更多信息](/developers/docs/consensus-mechanisms/pos/) +[深入了解权益证明](/developers/docs/consensus-mechanisms/pos/) ## 更愿意通过视频学习? {#visual-learner} -## 延伸阅读 {#further-reading} +## 扩展阅读 {#further-reading} - [多数攻击](https://en.bitcoin.it/wiki/Majority_attack) -- [关于结算终局性](https://blog.ethereum.org/2016/05/09/on-settlement-finality/) +- [关于结算确定性](https://blog.ethereum.org/2016/05/09/on-settlement-finality/) ### 视频 {#videos} -- [对工作量证明协议的技术说明](https://youtu.be/9V1bipPkCTU) +- [工作量证明协议的技术说明](https://youtu.be/9V1bipPkCTU) ## 相关主题 {#related-topics} -- [矿工](/developers/docs/consensus-mechanisms/pow/mining/) +- [挖矿](/developers/docs/consensus-mechanisms/pow/mining/) - [权益证明](/developers/docs/consensus-mechanisms/pos/) - [权威证明](/developers/docs/consensus-mechanisms/poa/) diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/index.md index 51659c387eb..783b3447877 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/index.md @@ -1,6 +1,6 @@ --- -title: 挖矿 -description: 解释以太坊上挖矿的工作原理。 +title: "挖矿" +description: "解释以太坊上挖矿的工作原理。" lang: zh --- @@ -8,14 +8,14 @@ lang: zh -工作量证明不再是以太坊共识机制的基础,这意味着挖矿已终结。 取而代之的是,以太坊将由质押了以太币的验证者保护。 你可以立即开始质押以太币。 阅读更多关于合并权益证明质押的信息。 此页面仅展示历史内容。 +工作量证明不再是以太坊共识机制的基础,这意味着挖矿已被关闭。 取而代之的是,以太坊由质押以太币的验证者来保证安全。 你可以立即开始质押以太币。 阅读更多关于合并权益证明质押的信息。 此页面仅展示历史内容。
## 前提条件 {#prerequisites} -为了更好地了解此页面,推荐先阅读[交易](/developers/docs/transactions/)、[区块](/developers/docs/blocks/)和[工作量证明](/developers/docs/consensus-mechanisms/pow/)。 +为了更好地理解本页内容,建议您先阅读有关[交易](/developers/docs/transactions/)、[区块](/developers/docs/blocks/)和[工作量证明](/developers/docs/consensus-mechanisms/pow/)的内容。 ## 以太坊挖矿是什么? {#what-is-ethereum-mining} @@ -31,7 +31,7 @@ lang: zh 在以太坊这样的去中心化系统中,需要确保每个人都同意交易的顺序。 矿工通过解决计算难题来产生区块并保护网络免受攻击,从而帮助实现这一目标。 -[关于工作量证明的更多信息](/developers/docs/consensus-mechanisms/pow/) +[更多关于工作量证明](/developers/docs/consensus-mechanisms/pow/) 以前任何人都能使用他们的计算机在以太坊网络上挖矿。 然而,并非每个人都可以通过挖矿实现以太币 (ETH) 获利。 在大多数情况下,矿工必须购买专用计算机硬件,并且能够获得廉价能源。 普通计算机不太可能获得足够的区块奖励来支付相关的挖矿成本。 @@ -42,32 +42,32 @@ lang: zh - 如果你在矿池中挖矿,这些矿池通常对矿池生成的每个区块收取固定百分比的费用 - 支持矿机的潜在成本(通风、能源监测、电线等) -要进一步探索挖矿收益,请使用挖矿收益计算器,例如 [Etherscan](https://etherscan.io/ether-mining-calculator) 提供的挖矿收益计算器。 +要进一步探索挖矿收益,请使用挖矿计算器,例如 [Etherscan](https://etherscan.io/ether-mining-calculator) 提供的计算器。 -## 如何挖掘以太坊交易 {#how-ethereum-transactions-were-mined} +## 以太坊交易是如何被挖出的 {#how-ethereum-transactions-were-mined} -以下内容将简要介绍如何在以太坊工作量证明中挖掘交易。 在[这里](/developers/docs/consensus-mechanisms/pos/#transaction-execution-ethereum-pos)可以找到对以太坊权益证明中该过程的类比介绍。 +以下内容将简要介绍如何在以太坊工作量证明中挖掘交易。 以太坊权益证明流程的类似描述可以在[这里](/developers/docs/consensus-mechanisms/pos/#transaction-execution-ethereum-pos)找到。 -1. 用户编写和通过一些[帐户](/developers/docs/accounts/)私钥来签署[交易](/developers/docs/transactions/)请求。 -2. 用户通过一些[节点](/developers/docs/nodes-and-clients/)将自己的交易请求广播到整个以太坊网络。 +1. 用户用某个[帐户](/developers/docs/accounts/)的私钥编写并签署一项[交易](/developers/docs/transactions/)请求。 +2. 用户通过某个[节点](/developers/docs/nodes-and-clients/)将交易请求广播到整个以太坊网络。 3. 在听到新的转账请求时,每个以太坊网络节点会添加这笔交易到本地的内存池,这些内存池包括他们收到的没有被添加到区块链以承认的所有转账请求。 -4. 在这个时候,一个挖矿节点将几十或上百个交易请求汇总到潜在[区块](/developers/docs/blocks/)中,从而尽量多收取[交易](/developers/docs/gas/)手续费,同时保证不超出区块燃料限制。 采矿节点将: - 1. 验证每个交易请求的有效性(例如没有人试图将以太币从他们没有签名的帐户中转移出来,请求是否有格式错误等),然后执行请求的本地代码,改变本地副本 EVM 的状态。 矿工获得每个交易请求的转账的手续费到他们的帐户。 - 2. 一旦在本地 EVM 副本上验证并执行了块中的所有转账请求,就开始为潜在块生成工作证明“合法性证书”。 +4. 在某个时间点,一个挖矿节点会将数十或数百个交易请求聚合成一个潜在的[区块](/developers/docs/blocks/),以便在不超过区块燃料限制的情况下,最大化其赚取的[交易费](/developers/docs/gas/)。 采矿节点将: + 1. 验证每个交易请求的有效性(即,没有人试图从自己没有签名的帐户转出以太币,请求格式无误等),然后执行请求中的代码,更改其本地 EVM 副本的状态。 矿工获得每个交易请求的转账的手续费到他们的帐户。 + 2. 一旦在本地 EVM 副本上验证并执行了区块中的所有交易请求,就开始为该潜在区块生成工作量证明“合法性证书”。 5. 最终,矿工将完成为包含我们特定交易请求的区块生成的证书。 然后,矿工广播完成的区块,其中包括证书和校验新 EVM 状态。 6. 其他节点将收到新的区块。 他们将验证证书,执行区块上所有的转账(包括最初由用户广播的交易),然后校验新 EVM 状态,之后执行所有满足 EVM 校验和的转账。 只有这样,这些节点才会将该块附加到区块链的尾部,并接受新的 EVM 状态作为新的规范状态。 7. 每个节点将从其未完成的本地内存池的转账请求中删除新区块中已经存在的转账请求。 8. 加入网络的新节点将按顺序下载所有块,包括未被打包的交易块。 初始化本地 EVM 副本(作为空白状态的 EVM 开始),在本地 EVM 副本上执行每个块中的每个转账,校验各块的校验和。 -每个交易都只会被挖掘(首次包含在新区块中并传播)一次,但在推进规范以太坊虚拟机状态的过程中,每个参与者都会执行和验证交易。 这凸显出区块链的核心准则之一:**不信任,就验证**。 +每个交易都只会被挖掘(首次包含在新区块中并传播)一次,但在推进规范以太坊虚拟机状态的过程中,每个参与者都会执行和验证交易。 这凸显了区块链的核心准则之一:**不信任,就验证**。 -## 叔块 {#ommer-blocks} +## 叔块 (Ommer) {#ommer-blocks} -基于工作量证明的区块挖掘是概率性的,这意味着有时由于网络延迟而同时公布了两个有效的区块。 在这种情况下,协议必须确定最长链(因此大多数即是最“有效的”),同时针对已提交但未被包含的有效区块,给予矿工部分奖励以确保公平。 这促使网络进一步去中心化,因为小矿工群体可能面临更大的延迟,但仍然可以通过[叔块](/glossary/#ommer)奖励获得收益。 +基于工作量证明的区块挖掘是概率性的,这意味着有时由于网络延迟而同时公布了两个有效的区块。 在这种情况下,协议必须确定最长链(因此大多数即是最“有效的”),同时针对已提交但未被包含的有效区块,给予矿工部分奖励以确保公平。 这促进了网络的进一步去中心化,因为规模较小的矿工(他们可能面临更大的延迟)仍然可以通过[叔块](/glossary/#ommer)区块奖励来获得回报。 -对于父区块的同级区块来说,“ommer”一词不分性别,因而为首选,但有时也被称为“uncle”(叔)。 **因为以太坊切换到权益证明机制后,叔块就不会被挖掘了**,因为每个时隙中只选择了一名提议者。 通过查看被挖掘叔块的[历史图表](https://ycharts.com/indicators/ethereum_uncle_rate),你可以看到这种变化。 +对于父块的同级区块来说,“叔块”一词不分性别,因而为首选,但有时也被称为“uncle”(叔块)。 **自从以太坊转向权益证明后,便不再挖出叔块了**,因为每个时隙只会选出一位提议者。 你可以通过查看已挖出叔块的[历史图表](https://ycharts.com/indicators/ethereum_uncle_rate)来了解这一变化。 -## 直观演示 {#a-visual-demo} +## 可视化演示 {#a-visual-demo} 跟随 Austin 了解挖矿和工作量证明区块链。 @@ -75,12 +75,12 @@ lang: zh ## 挖矿算法 {#mining-algorithm} -以太坊主网只使用过一种挖矿算法:[“Ethash”](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/)。 Ethash 是一种初始研发算法[“Dagger-Hashimoto”](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/)的后续版本。 +以太坊主网只使用过一种挖矿算法——['Ethash'](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/)。 Ethash 是最初研发算法 ['Dagger-Hashimoto'](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/) 的后继算法。 -[有关挖矿算法的更多信息](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/)。 +[更多关于挖矿算法](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/)。 -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [燃料](/developers/docs/gas/) -- [以太坊虚拟机](/developers/docs/evm/) +- [以太坊虚拟机 (EVM)](/developers/docs/evm/) - [工作量证明](/developers/docs/consensus-mechanisms/pow/) diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/index.md index faa0ed58c54..bc07e2aea13 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto/index.md @@ -1,35 +1,35 @@ --- title: Dagger-Hashimoto -description: 详细了解 Dagger-Hashimoto 算法。 +description: "详细了解 Dagger-Hashimoto 算法。" lang: zh --- -Dagger-Hashimoto 是以太坊挖矿算法的原始研究实现和规范。 但是,Dagger-Hashimoto 已被 [Ethash](#ethash) 取代。 在 2022 年 9 月 15 日实施[合并](/roadmap/merge/)后,挖矿完全关闭。 此后,以太坊采用[权益证明](/developers/docs/consensus-mechanisms/pos)机制保护安全。 本页面展示与历史有关的内容,其中的信息不再与合并后的以太坊相关。 +Dagger-Hashimoto 是以太坊挖矿算法的原始研究实现和规范。 Dagger-Hashimoto 已被 [Ethash](#ethash) 取代。 2022 年 9 月 15 日[合并](/roadmap/merge/)后,挖矿已完全停止。 此后,以太坊转而使用[权益证明](/developers/docs/consensus-mechanisms/pos)机制来保障安全。 本页面展示与历史有关的内容,其中的信息不再与合并后的以太坊相关。 ## 前提条件 {#prerequisites} -为了更好地了解此页面,建议提前阅读[工作量证明共识](/developers/docs/consensus-mechanisms/pow)、[挖矿](/developers/docs/consensus-mechanisms/pow/mining)和[挖矿算法](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms)。 +为了更好地理解本页内容,我们建议您首先阅读有关[工作量证明共识](/developers/docs/consensus-mechanisms/pow)、[挖矿](/developers/docs/consensus-mechanisms/pow/mining)和[挖矿算法](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms)的资料。 -## Dagger-Hashimoto 算法 {#dagger-hashimoto} +## Dagger-Hashimoto {#dagger-hashimoto} Dagger-Hashimoto 旨在实现两个目标: -1. **ASIC 抗性**:为算法打造专用硬件的益处应尽可能小。 -2. **轻量级客户端可验证性**:区块应能被轻量级客户端高效验证。 +1. **抗 ASIC 性**:为该算法创建专用硬件的好处应尽可能小 +2. **轻客户端可验证性**:区块应能由轻客户端高效验证。 在作出进一步修改后,我们还要具体说明如何在必要时实现第三个目标,但要以增加复杂性为代价: -**完整链存储**:挖矿需要存储完整的区块链状态(因为以太坊状态子树的不规则结构,我们预计将有可能进行一些修改,特别是一些经常用到的合约,但我们希望尽量减少这种情况)。 +**全链存储**:挖矿应要求存储完整的区块链状态(由于以太坊状态树的结构不规则,我们预计可以进行一些修剪,特别是一些常用合约,但我们希望将其最小化)。 -## 有向无环图世代 {#dag-generation} +## DAG 生成 {#dag-generation} -以下算法代码将在 Python 中定义。 首先,我们定义了 `encode_int`,用于将指定精度的无符号整数封送为字符串。 同时还定义了它的逆函数。 +以下算法代码将在 Python 中定义。 首先,我们给出 `encode_int`,用于将指定精度的无符号整数封送为字符串。 同时还定义了它的逆函数。 ```python NUM_BITS = 512 def encode_int(x): - "Encode an integer x as a string of 64 characters using a big-endian scheme" + "使用大端方案将整数 x 编码为 64 个字符的字符串" o = '' for _ in range(NUM_BITS / 8): o = chr(x % 256) + o @@ -37,7 +37,7 @@ def encode_int(x): return o def decode_int(s): - "Unencode an integer x from a string using a big-endian scheme" + "使用大端方案从字符串中解码整数 x" x = 0 for c in s: x *= 256 @@ -45,7 +45,7 @@ def decode_int(s): return x ``` -接下来我们假设 `sha3` 是一个需要输入整数,然后输出整数的函数,而 `dbl_sha3` 是一个 double-sha3 函数;如果将此引用代码转换为实现,使用以下代码: +接下来我们假设 `sha3` 是一个接收整数并输出整数的函数,而 `dbl_sha3` 是一个 double-sha3 函数;如果要将此参考代码转换为实现,请使用: ```python from pyethereum import utils @@ -65,26 +65,26 @@ def dbl_sha3(x): 该算法使用的参数有: ```python -SAFE_PRIME_512 = 2**512 - 38117 # Largest Safe Prime less than 2**512 +SAFE_PRIME_512 = 2**512 - 38117 # 小于 2**512 的最大安全素数 params = { - "n": 4000055296 * 8 // NUM_BITS, # Size of the dataset (4 Gigabytes); MUST BE MULTIPLE OF 65536 - "n_inc": 65536, # Increment in value of n per period; MUST BE MULTIPLE OF 65536 - # with epochtime=20000 gives 882 MB growth per year - "cache_size": 2500, # Size of the light client's cache (can be chosen by light - # client; not part of the algo spec) - "diff": 2**14, # Difficulty (adjusted during block evaluation) - "epochtime": 100000, # Length of an epoch in blocks (how often the dataset is updated) - "k": 1, # Number of parents of a node - "w": w, # Used for modular exponentiation hashing - "accesses": 200, # Number of dataset accesses during hashimoto - "P": SAFE_PRIME_512 # Safe Prime for hashing and random number generation + "n": 4000055296 * 8 // NUM_BITS, # 数据集的大小(4 GB);必须是 65536 的倍数 + "n_inc": 65536, # 每个时段的 n 值增量;必须是 65536 的倍数 + # epochtime=20000 时,每年增长 882 MB + "cache_size": 2500, # 轻客户端的缓存大小(可由轻客户端选择; + # 不属于算法规范) + "diff": 2**14, # 难度(在区块评估期间调整) + "epochtime": 100000, # 一个时段的区块长度(数据集的更新频率) + "k": 1, # 节点的父节点数量 + "w": w, # 用于模幂哈希 + "accesses": 200, # hashimoto 期间的数据集访问次数 + "P": SAFE_PRIME_512 # 用于哈希和随机数生成的安全素数 } ``` -`P` 在这种情况下为优先选择,因此 `log₂(P)` 仅略小于 512。512 对应于我们用来代表我们数目的 512 字节。 请注意,实际上只需要存储有向无环图的后半部分,因此,实际内存要求最初为 1 GB,每年增长 441 MB。 +在这种情况下,`P` 是一个质数,其选择要使 `log₂(P)` 略小于 512,这对应于我们一直用来表示数字的 512 位。 请注意,实际上只需要存储有向无环图的后半部分,因此,实际内存要求最初为 1 GB,每年增长 441 MB。 -### Dagger 建图 {#dagger-graph-building} +### Dagger 图构建 {#dagger-graph-building} Dagger 建图基本式的定义如下: @@ -101,11 +101,11 @@ def produce_dag(params, seed, length): return o ``` -基本上,建图从单个节点 `sha3(seed)` 开始,然后根据随机的先前节点按顺序添加到其他节点上。 创建一个新的节点后,将计算种子的模块化能力,以随机选择一些小于 `i` 的索引(使用上述 `x % i`),并且使用这些索引上的节点值进行计算,以产生新的 `x` 值,随后该值被提供给一个小的工作量证明函数(基于 XOR),最终在索引 `i` 生成图值。 这种特殊设计背后的基本原理是强制按顺序访问有向无环图。如果当前值未知,则无法确定要访问的下一个有向无环图的值。 最后,模幂运算会使结果更加恶化。 +本质上,它以单个节点 `sha3(seed)` 启动一个图,然后从那里开始,根据随机的先前节点顺序添加其他节点。 当创建一个新节点时,会计算种子的模幂,以随机选择一些小于 `i` 的索引(使用上面的 `x % i`),然后使用这些索引处节点的值进行计算,以生成新的 `x` 值,该值再被送入一个小的(基于 XOR 的)工作量证明函数,最终生成索引为 `i` 的图值。 这种特殊设计背后的基本原理是强制按顺序访问有向无环图。如果当前值未知,则无法确定要访问的下一个有向无环图的值。 最后,模幂运算会使结果更加恶化。 这种算法依赖于数字理论的若干结果。 讨论情况见下文附录。 -## 轻量级客户端评估 {#light-client-evaluation} +## 轻客户端评估 {#light-client-evaluation} 上述构图旨在实现图中每个节点的重构,只计算少量节点的子树,并且仅需少量的辅助内存。 请注意,当 k=1 时,子树只是一个上升到有向无环图第一个元素的值链。 @@ -131,11 +131,11 @@ def quick_calc(params, seed, p): return quick_calc_cached(p) ``` -本质上,它只是对上述算法的重写,删除了计算整个有向无环图值的循环,并用递归调用或缓存查找替换了早期的节点查找。 请注意,对于 `k=1` 的情况,缓存是不必要的,尽管进一步的优化实际上预先计算了有向无环图的前几千个值,并将其作为静态缓存进行计算;有关此代码实现,请参见附录。 +本质上,它只是对上述算法的重写,删除了计算整个有向无环图值的循环,并用递归调用或缓存查找替换了早期的节点查找。 请注意,对于 `k=1` 的情况,缓存是不必要的,尽管进一步的优化实际上预先计算了 DAG 的前几千个值,并将其作为静态缓存进行计算;有关此代码的实现,请参见附录。 -## 有向无环图的双倍缓冲 {#double-buffer} +## DAG 的双缓冲 {#double-buffer} -在完整客户端中,使用了上述公式生成的 2 个有向无环图的[_双倍缓冲_](https://wikipedia.org/wiki/Multiple_buffering)。 具体概念是,根据上述参数,每个 `epochtime` 生成一个有向无环图。 但客户端使用的并非是最新生成的有向无环图,而是前一个。 这样做的好处是,有向无环图可以随着时间的推移而被替换掉,无需包含矿工必须突然重新计算所有数据的步骤。 否则,定期的链处理可能会突然暂时放缓,并大幅提高中心化程度。 因此,在重新计算所有数据之前的几分钟时间内,存在 51% 的攻击风险。 +在全客户端中,会使用由上述公式生成的 2 个 DAG 的[_双缓冲_](https://wikipedia.org/wiki/Multiple_buffering)。 其思想是,根据上述参数,每隔 `epochtime` 个区块就会生成一个 DAG。 但客户端使用的并非是最新生成的有向无环图,而是前一个。 这样做的好处是,有向无环图可以随着时间的推移而被替换掉,无需包含矿工必须突然重新计算所有数据的步骤。 否则,定期的链处理可能会突然暂时放缓,并大幅提高中心化程度。 因此,在重新计算所有数据之前的几分钟时间内,存在 51% 的攻击风险。 要生成用于块工作计算的有向无环图集,算法如下: @@ -164,7 +164,7 @@ def get_daggerset(params, block): dagsz = get_dagsize(params, block) seedset = get_seedset(params, block) if seedset["front_hash"] <= 0: - # No back buffer is possible, just make front buffer + # 无法使用后向缓冲,仅创建前向缓冲 return {"front": {"dag": produce_dag(params, seedset["front_hash"], dagsz), "block_number": 0}} else: @@ -211,7 +211,7 @@ def quick_hashimoto(seed, dagsize, params, header, nonce): return dbl_sha3(mix) ``` -## 挖矿与验证 {#mining-and-verifying} +## 挖矿和验证 {#mining-and-verifying} 现在,将它们全部整合到挖矿算法中: @@ -254,56 +254,52 @@ def light_verify(params, header, nonce): - 为了使双层验证起效,区块头必须同时具有随机数和中间值 pre-sha3 - 在某处,区块头必须存储当前种子集的 sha3 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ ## 附录 {#appendix} -如前所述,用于生成有向无环图的随机数生成依赖于数论的一些结果。 Lehmer 随机数生成程序是 `picker` 变量的基础,因此我们首先确保它具有很宽的周期。 其次,只要一开始 `x ∈ [2,P-2]`,我们便能证明 `pow(x,3,P)` 不会将 `x` 映射到 `1` 或 `P-1`。 最后,我们证明 `pow(x,3,P)` 在被视为散列函数时具有较低的冲突率。 +如前所述,用于生成有向无环图的随机数生成依赖于数论的一些结果。 首先,我们保证作为 `picker` 变量基础的 Lehmer RNG 具有很长的周期。 其次,我们证明只要 `x ∈ [2,P-2]`,`pow(x,3,P)` 就不会将 `x` 映射到 `1` 或 `P-1`。 最后,我们证明当 `pow(x,3,P)` 被当作哈希函数时,其冲突率很低。 -### Lehmer 随机数生成程序 {#lehmer-random-number} +### Lehmer 随机数生成器 {#lehmer-random-number} -虽然 `produce_dag` 函数不需要生成无偏随机数,但潜在的威胁是 `seed**i % P` 只取少数几个值。 这可以为矿工识别模式提供优势。 +虽然 `produce_dag` 函数不需要生成无偏随机数,但一个潜在的威胁是 `seed**i % P` 只会取少数几个值。 这可以为矿工识别模式提供优势。 -为了避免这种情况,可采用数论结果。 [_安全素数_](https://en.wikipedia.org/wiki/Safe_prime)定义为素数 `P`,从而 `(P-1)/2` 也是素数。 [乘数组](https://en.wikipedia.org/wiki/Multiplicative_group_of_integers_modulo_n)中 `x` 的_顺序_ (乘数组 `ℤ/nℤ`)定义为最小 `m`,以使
xᵐ mod P ≡ 1
-鉴于这些定义,我们得到: +为了避免这种情况,可采用数论结果。 [_安全素数_](https://en.wikipedia.org/wiki/Safe_prime) 定义为素数 `P`,其中 `(P-1)/2` 也是素数。 [乘法群](https://en.wikipedia.org/wiki/Multiplicative_group_of_integers_modulo_n) `ℤ/nℤ` 的成员 `x` 的_阶_定义为最小的 `m`,使得
xᵐ mod P ≡ 1
+根据这些定义,我们有: -> 观察 1。 令 `x` 成为乘法组 `ℤ/Pℤ` 的一员,以获得安全素数 `P`。 如果 `x mod P ≠ 1 mod P` 和 `x mod P ≠ P-1 mod P`,那么 `x` 的顺序是 ` P-1` 或 `(P-1)/2`。 +> 观察 1。 设 `x` 是乘法群 `ℤ/Pℤ` 的一个成员,其中 `P` 是一个安全素数。 如果 `x mod P ≠ 1 mod P` 且 `x mod P ≠ P-1 mod P`,那么 `x` 的阶是 `P-1` 或 `(P-1)/2`。 -_证明_。 由于 `P` 是一个安全素数,那么根据 \[Lagrange's Theorem\]\[lagrange\],我们得到 `x` 的顺序为 `1`、`2`、`(P-1)/2` 或 `P-1`。 +_证明_。 由于 `P` 是一个安全素数,那么根据[拉格朗日定理][lagrange],我们可知 `x` 的阶是 `1`、`2`、`(P-1)/2` 或 `P-1`。 -`x` 的顺序不能是 `1`,因为根据费马小定理,我们得出: +`x` 的阶不可能是 `1`,因为根据费马小定理,我们有:
xP-1 mod P ≡ 1
-因此,`x` 必须是 `ℤ/nℤ` 的乘法单位,并且是唯一的乘法单位。 由于我们假设 `x ≠ 1`,所以这是不可能的。 +因此,`x` 必须是 `ℤ/nℤ` 的乘法单位元,而乘法单位元是唯一的。 由于我们已经假设 `x ≠ 1`,所以这是不可能的。 -`x` 的顺序不能是 `2`,除非 `x = P-1`,因为这将违反 `P` 是素数的事实。 +`x` 的阶不可能是 `2`,除非 `x = P-1`,因为这将违背 `P` 是素数这一事实。 -从以上命题中,我们可以知道,迭代 `(picker * init) % P` 的循环长度至少为 `(P-1)/2`。 这是因为我们选择 `P` 作为安全素数,强度几乎翻倍,且 `init` 处于 `[2,2**256+1]` 区间内。 考虑到 `P` 的量级,我们不应期待模幂运算具有周期性。 +从以上命题中,我们可以认识到,迭代 `(picker * init) % P` 的循环长度至少为 `(P-1)/2`。 这是因为我们选择的 `P` 是一个安全素数,约等于 2 的一个较高次幂,并且 `init` 在区间 `[2,2**256+1]` 内。 考虑到 `P` 的数量级,我们不应该期望模幂运算会出现循环。 -在有向无环图中分配第一个单元时(变量标签为 `init`),我们会计算 `pow(sha3(seed) + 2, 3, P)`。 初看起来,这并不能保证结果既不是 `1` 也不是 `P-1`。 然而,既然 `P-1` 是一个安全素数,我们还提供以下额外保证,这是观察 1 的必然结果: +在分配 DAG 中的第一个单元格(标记为 `init` 的变量)时,我们计算 `pow(sha3(seed) + 2, 3, P)`。 乍一看,这并不能保证结果既不是 `1` 也不是 `P-1`。 然而,由于 `P-1` 是一个安全素数,我们有以下额外的保证,这是观察 1 的一个推论: -> 观察 2。 令 `x` 成为乘法组 `ℤ/Pℤ` 的一员,以获得安全素数 `P`,并让 `w` 成为自然数。 如果 `x mod P ≠ 1 mod P`、`x mod P ≠ P-1 mod P`,且 `w mod P ≠ P-1 mod P`、`w mod P ≠ 0 mod P`,那么 `xʷ mod P ≠ 1 mod P` 且 `xʷ mod P ≠ P-1 mod P` +> 观察 2。 设 `x` 是乘法群 `ℤ/Pℤ` 的一个成员(其中 `P` 是一个安全素数),并设 `w` 是一个自然数。 如果 `x mod P ≠ 1 mod P` 且 `x mod P ≠ P-1 mod P`,并且 `w mod P ≠ P-1 mod P` 且 `w mod P ≠ 0 mod P`,那么 `xʷ mod P ≠ 1 mod P` 且 `xʷ mod P ≠ P-1 mod P` -### 模幂运算用作散列函数 {#modular-exponentiation} +### 作为哈希函数的模幂运算 {#modular-exponentiation} -对于特定的 `P` 值和 `w` 值,函数 `pow(x, w, P)` 可能存在许多冲突。 例如,`pow(x,9,19)` 的值只能接受 `{1,18}`。 +对于 `P` 和 `w` 的某些值,函数 `pow(x, w, P)` 可能会有很多冲突。 例如,`pow(x,9,19)` 只取 `{1,18}` 这几个值。 -鉴于 `P` 为素数,可以使用以下结果,选择一个用于模幂运算哈希函数的适当 `w` 值: +鉴于 `P` 是素数,可以使用以下结果为模幂哈希函数选择一个合适的 `w`: -> 观察 3。 令 `P` 为素数;当且仅当用于 `ℤ/Pℤ` 中所有 `a` 和 `b` 满足以下条件时,`w` 和 `P-1` 才能为互素。 -> ->
-> `aʷ mod P ≡ bʷ mod P`,当且仅当 `a mod P ≡ b mod P` ->
+> 观察 3。 设 `P` 是一个素数;`w` 和 `P-1` 互素,当且仅当对于 `ℤ/Pℤ` 中的所有 `a` 和 `b`:
`aʷ mod P ≡ bʷ mod P` 当且仅当 `a mod P ≡ b mod P`
-因此,鉴于 `P` 为素数,且 `w` 与 `P-1` 为互素,我们得出 `|{pow(x, w, P) : x ∈ ℤ}| = P`,表示散列函数具有尽可能小的冲突率。 +因此,鉴于 `P` 是素数且 `w` 与 `P-1` 互素,我们有 `|{pow(x, w, P) : x ∈ ℤ}| = P`,这意味着该哈希函数具有最小的可能冲突率。 -在特殊情况下,`P` 是我们选择的安全素数,那么 `P-1` 仅有系数 1、2、`(P-1)/2` 和 `P-1`。 由于 `P` > 7,我们知道 3 与 `P-1` 互素,因此 `w=3` 满足上述命题。 +在我们所选的 `P` 是安全素数的特殊情况下,`P-1` 仅有因子 1、2、`(P-1)/2` 和 `P-1`。 由于 `P` > 7,我们知道 3 与 `P-1` 互素,因此 `w=3` 满足上述命题。 -## 更有效的缓存评估算法 {#cache-based-evaluation} +## 更高效的基于缓存的评估算法 {#cache-based-evaluation} ```python def quick_calc(params, seed, p): diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/index.md index 44ebb9a5e50..8132b5af7e4 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash/index.md @@ -1,6 +1,6 @@ --- title: Ethash -description: Ethash 算法详细介绍。 +description: "Ethash 算法详细介绍。" lang: zh --- @@ -8,12 +8,12 @@ lang: zh - Ethash 是以太坊的工作量证明挖矿算法。 工作量证明现在已经被**完全关闭**,取而代之,以太坊现在使用[权益证明](/developers/docs/consensus-mechanisms/pos/)来保证安全。 阅读更多关于[合并](/roadmap/merge/)、[权益证明](/developers/docs/consensus-mechanisms/pos/)和[质押](/staking/)的信息。 此页面是为了满足对历史的兴趣! + Ethash 是以太坊的工作量证明挖矿算法。 工作量证明现在已经被**完全关闭**,取而代之,以太坊现在使用[权益证明](/developers/docs/consensus-mechanisms/pos/)来保证安全。 阅读更多关于[合并](/roadmap/merge/)、[权益证明](/developers/docs/consensus-mechanisms/pos/)和[质押](/staking/)的信息。 此页面是为了满足对历史的兴趣! -Ethash 是 [Dagger-Hashimoto](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto) 算法的修改版本。 Ethash 工作量证明是[内存密集型](https://wikipedia.org/wiki/Memory-hard_function)算法,这被认为使算法可抵御专用集成电路。 Ethash 专用集成电路最终被开发出来,但在工作量证明被关闭之前,图形处理单元挖矿仍然是一个可行的选择。 Ethash 仍然用于在其他非以太坊工作量证明网络上挖掘其他币。 +Ethash 是 [Dagger-Hashimoto](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto) 算法的修改版本。 Ethash 工作量证明是[内存困难](https://wikipedia.org/wiki/Memory-hard_function)的,这被认为使该算法具有抗 ASIC 的特性。 Ethash 专用集成电路最终被开发出来,但在工作量证明被关闭之前,图形处理单元挖矿仍然是一个可行的选择。 Ethash 仍然用于在其他非以太坊工作量证明网络上挖掘其他币。 ## Ethash 是如何工作的? {#how-does-ethash-work} @@ -21,9 +21,9 @@ Ethash 是 [Dagger-Hashimoto](/developers/docs/consensus-mechanisms/pow/mining/m 该算法采取的一般路线如下: -1. 有一个**种子**,可以通过扫描区块头直到该点来为每个区块计算种子。 -2. 从种子中可以计算出 **16 MB 的伪随机缓存**。 轻量级客户端存储缓存。 -3. 我们可以从缓存中生成一个 **1 GB 数据集**,数据集中每个项目仅依赖于一小部分缓存中的项目。 全客户端和矿工存储数据集。 数据集随着时间的流逝而呈线性增长。 +1. 存在一个**种子**,它可以通过扫描截止到该区块的区块头来计算得出。 +2. 从种子可以计算出一个 **16 MB 的伪随机缓存**。 轻量级客户端存储缓存。 +3. 从缓存中,我们可以生成一个 **1 GB 的数据集**,其特性是,数据集中的每个项目仅依赖于缓存中的少量项目。 全客户端和矿工存储数据集。 数据集随着时间的流逝而呈线性增长。 4. 采矿会抢走数据集的随机片段并将它们散列在一起。 可以通过使用缓存来重新生成你需要的数据集中的特定区块,以较低的内存进行验证,以使你只需要存储缓存。 每隔 30000 个区块更新一次大数据集,因此,矿工的绝大部分工作都是读取数据集,而不是对其进行修改。 @@ -33,23 +33,26 @@ Ethash 是 [Dagger-Hashimoto](/developers/docs/consensus-mechanisms/pow/mining/m 我们采用以下定义: ``` -WORD_BYTES = 4 # bytes in word -DATASET_BYTES_INIT = 2**30 # bytes in dataset at genesis -DATASET_BYTES_GROWTH = 2**23 # dataset growth per epoch -CACHE_BYTES_INIT = 2**24 # bytes in cache at genesis -CACHE_BYTES_GROWTH = 2**17 # cache growth per epoch -CACHE_MULTIPLIER=1024 # Size of the DAG relative to the cache -EPOCH_LENGTH = 30000 # blocks per epoch -MIX_BYTES = 128 # width of mix -HASH_BYTES = 64 # hash length in bytes -DATASET_PARENTS = 256 # number of parents of each dataset element -CACHE_ROUNDS = 3 # number of rounds in cache production -ACCESSES = 64 # number of accesses in hashimoto loop +WORD_BYTES = 4 # 字中的字节数 +DATASET_BYTES_INIT = 2**30 # 创世时数据集字节数 +DATASET_BYTES_GROWTH = 2**23 # 每个时段的数据集增长量 +CACHE_BYTES_INIT = 2**24 # 创世时缓存字节数 +CACHE_BYTES_GROWTH = 2**17 # 每个时段的缓存增长量 +CACHE_MULTIPLIER=1024 # DAG 相对于缓存的大小 +EPOCH_LENGTH = 30000 # 每个时段的区块数 +MIX_BYTES = 128 # mix 宽度 +HASH_BYTES = 64 # 哈希长度(以字节为单位) +DATASET_PARENTS = 256 # 每个数据集元素的父项数 +CACHE_ROUNDS = 3 # 缓存生成中的轮数 +ACCESSES = 64 # hashimoto 循环中的访问次数 ``` ### 使用“SHA3” {#sha3} -以太坊的开发恰逢 SHA3 标准的制定, 标准进程对最终确定的哈希算法的填充做了后期改动,使得以太坊的 “sha3_256”和“sha3_512”哈希值不是标准的 sha3 哈希值,而是在其他情况下 常被称为“Keccak-256”和“Keccak-512”的变量。 讨论请见[此处](https://eips.ethereum.org/EIPS/eip-1803)、[此处](http://ethereum.stackexchange.com/questions/550/which-cryptographic-hash-function-does-ethereum-use)或[此处](http://bitcoin.stackexchange.com/questions/42055/what-is-the-approach-to-calculate-an-ethereum-address-from-a-256-bit-private-key/42057#42057)。 +以太坊的开发恰逢 SHA3 标准的制定, +标准进程对最终确定的哈希算法的填充做了后期改动,使得以太坊的 +“sha3_256”和“sha3_512”哈希值不是标准的 sha3 哈希值,而是在其他情况下 +常被称为“Keccak-256”和“Keccak-512”的变量。 例如,请参阅[此处](https://eips.ethereum.org/EIPS/eip-1803)、[此处](http://ethereum.stackexchange.com/questions/550/which-cryptographic-hash-function-does-ethereum-use)或[此处](http://bitcoin.stackexchange.com/questions/42055/what-is-the-approach-to-calculate-an-ethereum-address-from-a-256-bit-private-key/42057#42057)的讨论。 请记住这一点,因为下面的算法描述中提到了“sha3”哈希值。 @@ -83,12 +86,12 @@ def get_full_size(block_number): def mkcache(cache_size, seed): n = cache_size // HASH_BYTES - # Sequentially produce the initial dataset + # 顺序生成初始数据集 o = [sha3_512(seed)] for i in range(1, n): o.append(sha3_512(o[-1])) - # Use a low-round version of randmemohash + # 使用低轮数版本的 randmemohash for _ in range(CACHE_ROUNDS): for i in range(n): v = o[i][0] % n @@ -97,11 +100,11 @@ def mkcache(cache_size, seed): return o ``` -缓存生成过程中,先按顺序填充 32 MB 内存,然后从 [_严格内存硬哈希函数 _(2014)](http://www.hashcash.org/papers/memohash.pdf) 执行两次 Sergio Demian Lerner 的 _RandMemoHash_ 算法。 输出一组 524288 个 64 字节值。 +缓存生成过程首先需要按顺序填满 32 MB 内存,然后执行两轮 Sergio Demian Lerner 的 _RandMemoHash_ 算法,该算法出自 [_Strict Memory Hard Hashing Functions_ (2014)](http://www.hashcash.org/papers/memohash.pdf)。 输出一组 524288 个 64 字节值。 ## 数据聚合函数 {#date-aggregation-function} -我们使用灵感来自 [FNV 哈希](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function)的算法,在部分情况下,这种算法可用作逻辑异或的不相关替代。 请注意,我们使用全 32 位输入乘以素数,与之相对地,FNV-1 spec 用 1 个字节(8 个字节)依次乘以素数。 +在某些情况下,我们使用一种受 [FNV 哈希](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function) 启发的算法,作为异或运算 (XOR) 的非关联替代。 请注意,我们使用全 32 位输入乘以素数,与之相对地,FNV-1 spec 用 1 个字节(8 个字节)依次乘以素数。 ```python FNV_PRIME = 0x01000193 @@ -120,11 +123,11 @@ def fnv(v1, v2): def calc_dataset_item(cache, i): n = len(cache) r = HASH_BYTES // WORD_BYTES - # initialize the mix + # 初始化 mix mix = copy.copy(cache[i % n]) mix[0] ^= i mix = sha3_512(mix) - # fnv it with a lot of random cache nodes based on i + # 根据 i,用大量随机缓存节点对其进行 fnv 运算 for j in range(DATASET_PARENTS): cache_index = fnv(i ^ j, mix[j % r]) mix = map(fnv, mix, cache[cache_index % n]) @@ -140,27 +143,27 @@ def calc_dataset(full_size, cache): ## 主循环 {#main-loop} -现在,我们指定了类似“hashimoto”的主要循环。在此循环中,我们聚合整个数据集的数据,以生成特定区块头和随机数的最终值。 在下面的代码中,`header` 代表一个_被截断_区块头的递归长度前缀表示的 SHA3-256 _哈希值_。被截断是指区块头被截去了 **mixHash** 和**随机数**字段。 `nonce` 是指一个 64 位无符号整数的八个字节,按大端序排列。 因此 `nonce[::-1]` 是上述值的八字节小端序表示: +现在,我们指定了类似“hashimoto”的主要循环。在此循环中,我们聚合整个数据集的数据,以生成特定区块头和随机数的最终值。 在下面的代码中,`header` 代表一个_截断_区块头的 RLP 编码的 SHA3-256 _哈希_,也就是移除了 **mixHash** 和 **nonce** 字段的区块头。 `nonce` 是一个 64 位无符号整数的八个字节,采用大端序。 因此 `nonce[::-1]` 是该值的八字节小端序表示: ```python def hashimoto(header, nonce, full_size, dataset_lookup): n = full_size / HASH_BYTES w = MIX_BYTES // WORD_BYTES mixhashes = MIX_BYTES / HASH_BYTES - # combine header+nonce into a 64 byte seed + # 将 header 和 nonce 组合成一个 64 字节的种子 s = sha3_512(header + nonce[::-1]) - # start the mix with replicated s + # 用复制的 s 开始混合 mix = [] for _ in range(MIX_BYTES / HASH_BYTES): mix.extend(s) - # mix in random dataset nodes + # 混入随机数据集节点 for i in range(ACCESSES): p = fnv(i ^ s[0], mix[i % w]) % (n // mixhashes) * mixhashes newdata = [] for j in range(MIX_BYTES / HASH_BYTES): newdata.extend(dataset_lookup(p + j)) mix = map(fnv, mix, newdata) - # compress mix + # 压缩 mix cmix = [] for i in range(0, len(mix), 4): cmix.append(fnv(fnv(fnv(mix[i], mix[i+1]), mix[i+2]), mix[i+3])) @@ -176,9 +179,9 @@ def hashimoto_full(full_size, dataset, header, nonce): return hashimoto(header, nonce, full_size, lambda x: dataset[x]) ``` -基本上,我们保持着一个宽 128 字节的“混合物”,并多次按顺序从整个数据集中获取 128 字节,并使用 `fnv` 函数将其与混合物结合起来。 使用 128 字节的序列访问,以便每轮算法总是能从随机访问内存获取完整的页面,从而尽量减少转译后备缓冲区的疏忽,而专用集成电路在理论上能够避免这些疏忽。 +从本质上讲,我们维护一个 128 字节宽的 "mix",并从完整数据集中重复顺序获取 128 字节,然后使用 `fnv` 函数将其与 mix 合并。 使用 128 字节的序列访问,以便每轮算法总是能从随机访问内存获取完整的页面,从而尽量减少转译后备缓冲区的疏忽,而专用集成电路在理论上能够避免这些疏忽。 -如果此算法的输出低于所需目标,即证明随机数是有效的。 请注意,在最后额外应用 `sha3_256` 将确保中间随机数的存在。提供此证据可以证明至少做了少量工作;而且此快速外部工作量证明验证可以用于反分布式拒绝服务目的。 也可提供统计保证,说明结果是一个无偏 256 位数字。 +如果此算法的输出低于所需目标,即证明随机数是有效的。 请注意,末尾额外应用的 `sha3_256` 确保了中间随机数的存在,可以提供该随机数来证明至少完成了少量的工作;这种快速的外部 PoW 验证可用于抵御 DDoS 攻击。 也可提供统计保证,说明结果是一个无偏 256 位数字。 ## 挖矿 {#mining} @@ -186,7 +189,7 @@ def hashimoto_full(full_size, dataset, header, nonce): ```python def mine(full_size, dataset, header, difficulty): - # zero-pad target to compare with hash on the same digit + # 将目标补零,以便与相同位数的哈希进行比较 target = zpad(encode_int(2**256 // difficulty), 64)[::-1] from random import randint nonce = randint(0, 2**64) @@ -209,9 +212,9 @@ def mine(full_size, dataset, header, difficulty): 请注意,为了顺利挖矿和验证,我们建议在单个线程中预先计算未来的种子哈希值和数据集。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ ## 附录 {#appendix} @@ -220,7 +223,7 @@ _还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ ```python import sha3, copy -# Assumes little endian bit ordering (same as Intel architectures) +# 假设为小端字节序(与 Intel 架构相同) def decode_int(s): return int(s[::-1].encode('hex'), 16) if s else 0 @@ -248,7 +251,7 @@ def serialize_cache(ds): serialize_dataset = serialize_cache -# sha3 hash function, outputs 64 bytes +# sha3 哈希函数,输出 64 字节 def sha3_512(x): return hash_words(lambda v: sha3.sha3_512(v).digest(), 64, x) @@ -868,7 +871,7 @@ cache_sizes = [ 166985408, 167116736, 167246656, 167378368, 167508416, 167641024, 167771584, 167903168, 168034112, 168164032, 168295744, 168427456, 168557632, 168688448, 168819136, 168951616, 169082176, 169213504, -169344832, 169475648, 169605952, 169738048, 169866304, 169999552, +169344832, 169475648, 169605952, 169738048, 169866304, 16999552, 170131264, 170262464, 170393536, 170524352, 170655424, 170782016, 170917696, 171048896, 171179072, 171310784, 171439936, 171573184, 171702976, 171835072, 171966272, 172097216, 172228288, 172359232, diff --git a/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/index.md b/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/index.md index 4621f4bda46..a1bf6583e7e 100644 --- a/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/index.md +++ b/public/content/translations/zh/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/index.md @@ -1,6 +1,6 @@ --- -title: 挖矿算法 -description: 以太坊挖矿所用的算法的详细介绍 +title: "挖矿算法" +description: "以太坊挖矿所用的算法的详细介绍" lang: zh --- @@ -8,7 +8,7 @@ lang: zh -工作量证明不再是以太坊共识机制的基础,这意味着挖矿已终结。 取而代之的是,以太坊将由质押了以太币的验证者保护。 你可以立即开始质押以太币。 阅读更多关于合并权益证明质押的信息。 此页面仅为满足对历史的兴趣。 +工作量证明不再是以太坊共识机制的基础,这意味着挖矿已被关闭。 取而代之的是,以太坊由质押以太币的验证者来保证安全。 你可以立即开始质押以太币。 阅读更多关于合并权益证明质押的信息。 此页面仅展示历史内容。 @@ -17,26 +17,26 @@ lang: zh ## 前提条件 {#prerequisites} -为了更好地理解本页内容,推荐你先阅读[工作量证明共识](/developers/docs/consensus-mechanisms/pow)和[挖矿](/developers/docs/consensus-mechanisms/pow/mining)。 +为了更好地理解本页内容,我们建议您先阅读有关[工作量证明共识](/developers/docs/consensus-mechanisms/pow)和[挖矿](/developers/docs/consensus-mechanisms/pow/mining)的内容。 ## Dagger Hashimoto {#dagger-hashimoto} Dagger Hashimoto 是以太坊挖矿的先导研究算法,现已被 Ethash 取代。 它是两种不同算法:Dagger 和 Hashimoto的融合。 它只是一个研究实现,并在以太坊主网启动时被 Ethash 取代。 -[Dagger](http://www.hashcash.org/papers/dagger.html) 会生成一个[有向无环图](https://en.wikipedia.org/wiki/Directed_acyclic_graph),将共同取哈希值的内容随机划分。 其核心原理是,每个随机数只取总数据树的一小部分。 挖矿禁止为每个随机数重新计算子树,因此需要总存储树,但若为验证某个随机数的价值,则可以重新计算。 Dagger 的设计目的是替代诸如Scrypt的已有算法。后者是“内存困难算法”,但当它们的内存困难程度增加到可信的安全水平时将很难验证。 然而,Dagger 容易受到共享内存硬件加速的影响,因此我们放弃了这种算法,转而采用了其他研究途径。 +[Dagger](http://www.hashcash.org/papers/dagger.html) 涉及生成一个[有向无环图](https://en.wikipedia.org/wiki/Directed_acyclic_graph),它的随机切片会被一起哈希。 其核心原理是,每个随机数只取总数据树的一小部分。 挖矿禁止为每个随机数重新计算子树,因此需要总存储树,但若为验证某个随机数的价值,则可以重新计算。 Dagger 的设计目的是替代诸如Scrypt的已有算法。后者是“内存困难算法”,但当它们的内存困难程度增加到可信的安全水平时将很难验证。 然而,Dagger 容易受到共享内存硬件加速的影响,因此我们放弃了这种算法,转而采用了其他研究途径。 -[Hashimoto](http://diyhpl.us/%7Ebryan/papers2/bitcoin/meh/hashimoto.pdf) 算法通过实现输入/输出密集的特性(即,内存读取速度是挖矿过程中的限制因素)来增加对专用集成电路的抵抗性。 理论上来说使用内存比使用计算能力更容易;已有价值数十亿美元的经费投入被用于研究针对不同应用场景的内存优化,通常涉及近随机访问模式(即“随机存取存储器”)。 因此,现有的内存对评价算法效率的能力更接近最优。 Hashimoto 使用区块链作为数据源,同时满足上述第 (1) 和第 (3) 条。 +[Hashimoto](http://diyhpl.us/%7Ebryan/papers2/bitcoin/meh/hashimoto.pdf) 是一种通过受 I/O 限制(即,内存读取是挖矿过程中的限制因素)来增加抗 ASIC 性的算法。 理论上来说使用内存比使用计算能力更容易;已有价值数十亿美元的经费投入被用于研究针对不同应用场景的内存优化,通常涉及近随机访问模式(即“随机存取存储器”)。 因此,现有的内存对评价算法效率的能力更接近最优。 Hashimoto 使用区块链作为数据源,同时满足上述第 (1) 和第 (3) 条。 -Dagger-Hashimoto 是在 Dagger 和 Hashimoto 的基础上改进而来的以太币挖矿算法。 Dagger Hashimoto 和 Hashimoto 的差别在于,Dagger Hashimoto 的数据来源并非是区块链,而是自定义生成的数据集,这些数据集将基于所有 N 区块上的区块数据进行更新。 这些数据集采用 Dagger 算法生成,可为轻量级客户端的验证算法高效计算特定于每个随机数的子集。 Dagger Hashimoto 算法和 Dagger 算法的差别在于,与原来的 Dagger 不同,用于查询区块的数据集只是暂时的,只会偶尔更新(例如每周更新一次)。 这意味着生成数据集的工作量接近于零,所以 Sergio Lerner 关于共享内存加速的论据变得微不足道。 +Dagger-Hashimoto 是在 Dagger 和 Hashimoto 的基础上改进而来的以太币挖矿算法。 Dagger Hashimoto 和 Hashimoto 的差别在于,Dagger Hashimoto 的数据来源并非是区块链,而是自定义生成的数据集,这些数据集将基于所有 N 区块上的区块数据进行更新。 这些数据集采用 Dagger 算法生成,可为轻量级客户端的验证算法高效计算特定于每个随机数的子集。 Dagger Hashimoto 和 Dagger 的区别在于,与原来的 Dagger 不同,用于查询区块的数据集是半永久性的,只会偶尔更新(例如,每周更新一次)。 这意味着生成数据集的工作量接近于零,所以 Sergio Lerner 关于共享内存加速的论据变得微不足道。 -有关 [Dagger-Hashimoto](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto) 的更多信息。 +更多关于 [Dagger-Hashimoto](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/dagger-hashimoto) 的内容。 ## Ethash {#ethash} Ethash 是在现已弃用的工作量证明架构下,实际用于真正的以太坊主网的挖矿算法。 Ethash 实际上是为 Dagger Hashimoto 算法进行重要更新后的一个特殊版本命名的新名称,但它仍然继承了其前身的基本原理。 以太坊主网只采用过 Ethash——Dagger Hashimoto 是挖矿算法的研发版本,在以太坊主网开始挖矿前被取代。 -[有关 Ethash 的更多信息](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash)。 +更多关于 [Ethash](/developers/docs/consensus-mechanisms/pow/mining/mining-algorithms/ethash) 的内容。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ diff --git a/public/content/translations/zh/developers/docs/dapps/index.md b/public/content/translations/zh/developers/docs/dapps/index.md index bbe1be5f053..f3b0ac33a3e 100644 --- a/public/content/translations/zh/developers/docs/dapps/index.md +++ b/public/content/translations/zh/developers/docs/dapps/index.md @@ -1,94 +1,94 @@ --- -title: 去中心化应用程序简介 +title: "去中心化应用程序技术介绍" description: lang: zh --- -去中心化应用程序 (dapp) 是在去中心化网络上构建的应用程序,结合了[智能合约](/developers/docs/smart-contracts/)和前端用户界面。 请注意,就像开放 API 一样,以太坊智能合约具有可访问性和透明性,所以你的 dapp 里甚至可以包含其他人写过的智能合约。 +去中心化应用程序 (dapp) 是在去中心化网络上构建的应用程序,它结合了[智能合约](/developers/docs/smart-contracts/)和前端用户界面。 请注意,就像开放 API 一样,以太坊智能合约具有可访问性和透明性,所以你的 dapp 里甚至可以包含其他人写过的智能合约。 ## 前提条件 {#prerequisites} -在学习 dapp 之前,你应该了解[区块链基础知识](/developers/docs/intro-to-ethereum/),并了解以太坊网络及其去中心化方式。 +在学习去中心化应用程序之前,您应该先了解[区块链基础知识](/developers/docs/intro-to-ethereum/),并阅读有关以太坊网络及其去中心化方式的资料。 -## dapp 的定义 {#definition-of-a-dapp} +## 去中心化应用程序的定义 {#definition-of-a-dapp} 一个 dapp 的后端代码在一个去中心化 P2P 网络上运行。 与此相对应的,是在中心化服务器上运行后端代码的应用程序。 -dapp 可以用任何语言编写(就像是一个 app)。它有前端代码和用户界面,能调用其后端。 此外,它的前端可以托管在去中心化存储上,例如 [IPFS](https://ipfs.io/)。 +一个去中心化应用程序可以用任何语言编写前端代码和用户界面(就像一个应用程序一样),来调用其后端。 此外,其前端可以托管在 [IPFS](https://ipfs.io/) 等去中心化存储上。 -- **去中心化** - dapp 在以太坊上运行,这是一个开放的公共去中心化平台,没有任何一个人或团体可以控制 -- **确定性** ,无论执行的环境如何,都执行相同的功能 -- **图灵完备** - dapp 可以根据所需资源执行任何操作 -- **隔离性** - 它们在称为 EVM 的虚拟环境中执行。即使智能合约出现问题,也不会妨碍区块链网络的正常运行 +- **去中心化** - 去中心化应用程序在以太坊上运行,这是一个开放的公共去中心化平台,没有任何个人或团体可以控制 +- **确定性** - 无论在何种环境中执行,去中心化应用程序都会执行相同的功能 +- **图灵完备** - 只要有必需的资源,去中心化应用程序就能执行任何操作 +- **隔离性** - 去中心化应用程序在称为以太坊虚拟机的虚拟环境中执行,因此,即使智能合约存在漏洞,也不会妨碍区块链网络的正常运作 -### 智能合约 {#on-smart-contracts} +### 关于智能合约 {#on-smart-contracts} -要引入 dapp,我们需要引入智能合约 —— dapp 的后端,因为缺少更好的术语。 有关详细概述,请访问我们的[智能合约](/developers/docs/smart-contracts/)部分。 +要引入 dapp,我们需要引入智能合约 —— dapp 的后端,因为缺少更好的术语。 要了解详细概览,请前往我们的[智能合约](/developers/docs/smart-contracts/)部分。 智能合约是一种在以太坊网络上的计算机程序,它严格按照事先编写的代码来运行。 智能合约一旦部署到以太坊网络中,就无法更改。 Dapps 可以是去中心化的,就是由于它们受智能合约的既定逻辑控制,而不是个人或公司。 这也意味着你需要非常仔细地设计合约,并进行全面测试。 -## Dapp 开发的好处 {#benefits-of-dapp-development} +## 去中心化应用程序开发的好处 {#benefits-of-dapp-development} -- **零停机时间** – 一旦将某 dapp 的智能合约部署到区块链上,整个网络都能为那些希望与合约互动的客户提供服务。 因此,恶意参与者无法针对单个 dapp 发起 DoS 攻击。 -- **隐私** – 你不需要提供真实世界的身份来部署或与 dapp 进行交互。 -- **抵制审查** – 网络上没有任何一个实体可以阻止用户提交交易、部署 dapp 或读取区块链上的数据。 -- **数据完整性** – 由于采用了加密基元,存储在区块链上的数据是不可更改和无可争议的。 恶意行为者无法伪造已经公开的交易或其他数据。 -- **去信任的计算/可验证的行为** – 智能合约可以分析并保证以可预测的方式执行,而去信任中心化组织。 这在传统模式下是不存在的,比如我们使用网上银行系统时,我们要相信金融机构不会滥用我们的金融数据,不会篡改记录,也不会被黑客攻击。 +- **零停机时间** – 一旦智能合约部署在区块链上,整个网络将始终能够为希望与合约交互的客户端提供服务。 因此,恶意参与者无法针对单个 dapp 发起 DoS 攻击。 +- **隐私** – 您无需提供真实身份即可部署去中心化应用程序或与之交互。 +- **抗审查** – 网络上没有任何单个实体可以阻止用户提交交易、部署去中心化应用程序或从区块链读取数据。 +- **完整的数据完整性** – 得益于加密基元,存储在区块链上的数据是不可变且无可争议的。 恶意行为者无法伪造已经公开的交易或其他数据。 +- **无需信任的计算/可验证的行为** – 智能合约可以被分析并保证以可预测的方式执行,而无需信任一个中心化的权威机构。 这在传统模式下并非如此;例如,当我们使用网上银行系统时,我们必须相信金融机构不会滥用我们的金融数据、篡改记录或遭到黑客攻击。 -## Dapp 开发的缺陷 {#drawbacks-of-dapp-development} +## 去中心化应用程序开发的缺点 {#drawbacks-of-dapp-development} -- **维护** – dapp 可能更难维护,因为发布到区块链的代码和数据更难修改。 在部署后,开发人员很难对去中心化应用程序(或其存储的底层数据)进行更新,即使在旧版本中发现了漏洞或安全风险。 -- **性能开销** – 巨大的性能开销,而且难以扩展更多性能。 为了达到以太坊所追求的安全、完整、透明和可靠的水平,每个节点都会运行和存储每一笔交易。 除此之外,达成权益证明共识也需要时间。 -- **网络拥塞** – 至少在当前模型中,如果一个 dapp 使用了太多的计算资源,整个网络都会承担影响。 目前,该网络每秒只能处理约 10-15 笔交易;如果交易发送的速度超过这个速度,未确认的交易池会迅速膨胀。 -- **用户体验** – 设计用户友好的体验可能更难。普通终端用户可能会发现,很难以真正安全的方式设置与区块链互动所需的工具堆栈。 -- **集中化** — 无论如何,建立在以太坊基础层之上的用户友好型和开发人员友好型解决方案最终看起来都像集中式服务。 例如,这种服务可以在服务器端存储密钥或其他敏感信息,使用中心化服务器为前端服务,或在写到区块链之前在中心化服务器上运行重要的业务逻辑。 这消除了区块链与传统模式相比的许多(并不是全部)优势。 +- **维护** – 去中心化应用程序可能更难维护,因为发布到区块链的代码和数据更难修改。 在部署后,开发人员很难对去中心化应用程序(或其存储的底层数据)进行更新,即使在旧版本中发现了漏洞或安全风险。 +- **性能开销** – 存在巨大的性能开销,并且扩容非常困难。 为了达到以太坊所追求的安全、完整、透明和可靠的水平,每个节点都会运行和存储每一笔交易。 除此之外,达成权益证明共识也需要时间。 +- **网络拥堵** – 当一个去中心化应用程序使用过多的计算资源时,整个网络都会堵塞。 目前,该网络每秒只能处理约 10-15 笔交易;如果交易发送的速度超过这个速度,未确认的交易池会迅速膨胀。 +- **用户体验** – 设计用户友好的体验可能更难,因为普通最终用户可能会发现,要以真正安全的方式设置与区块链交互所需的工具栈非常困难。 +- **中心化** – 无论如何,在以太坊基础层之上构建的用户友好型和开发者友好型解决方案,最终可能看起来都像中心化服务。 例如,这种服务可以在服务器端存储密钥或其他敏感信息,使用中心化服务器为前端服务,或在写到区块链之前在中心化服务器上运行重要的业务逻辑。 这消除了区块链与传统模式相比的许多(并不是全部)优势。 ## 更愿意通过视频学习? {#visual-learner} -## 用来创建去中心化应用程序的工具 {#dapp-tools} +## 创建去中心化应用程序的工具 {#dapp-tools} -**Scaffold-ETH _ - 使用能自适应智能合约的前端,快速尝试 Solidity。_** +**Scaffold-ETH _- 使用能适应您的智能合约的前端,快速进行 Solidity 实验。_** - [GitHub](https://github.com/scaffold-eth/scaffold-eth-2) -- [示例 dapp](https://punkwallet.io/) +- [示例去中心化应用程序](https://punkwallet.io/) -**创建以太坊应用程序 _- 使用一个命令创建以太坊驱动的应用程序。_** +**Create Eth App _- 用一个命令创建以太坊驱动的应用程序。_** - [GitHub](https://github.com/paulrberg/create-eth-app) -**一键去中心化 _- 用于从 [ABI](/glossary/#abi) 生成去中心化应用程序前端的免费和开放源代码软件工具。_** +**One Click Dapp _- 一款 FOSS 工具,用于从 [ABI](/glossary/#abi) 生成去中心化应用程序前端。_** - [oneclickdapp.com](https://oneclickdapp.com) - [GitHub](https://github.com/oneclickdapp/oneclickdapp-v1) -**Etherflow _ - 供以太坊开发者测试节点,并在浏览器中编写和调试 RPC 调用的免费和开放源代码软件工具。_** +**Etherflow _- 供以太坊开发者测试节点,并在浏览器中编写和调试 RPC 调用的 FOSS 工具。_** - [etherflow.quiknode.io](https://etherflow.quiknode.io/) - [GitHub](https://github.com/abunsen/etherflow) -**thirdweb _- 为 Web3 开发提供各种语言的软件开发工具包、智能合约、工具和基础设施。_** +**thirdweb _- 为 Web3 开发提供各种语言的 SDK、智能合约、工具和基础设施。_** - [主页](https://thirdweb.com/) -- [相关文档](https://portal.thirdweb.com/) +- [文档](https://portal.thirdweb.com/) - [GitHub](https://github.com/thirdweb-dev/) -**Crossmint _- 企业级 Web3 开发平台,可用于部署智能合约,支持信用卡和跨链支付方式,可利用应用程序接口创建、分发、销售、存储、编辑非同质化代币。_** +**Crossmint _- 企业级 Web3 开发平台,用于部署智能合约,支持信用卡和跨链支付,并使用 API 来创建、分发、销售、存储和编辑 NFT。_** - [crossmint.com](https://www.crossmint.com) -- [相关文档](https://docs.crossmint.com) +- [文档](https://docs.crossmint.com) - [Discord](https://discord.com/invite/crossmint) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [探索去中心化应用程序](/apps) -- [Web 3.0 应用程序架构](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) - _Preethi Kasireddy_ +- [Web 3.0 应用程序的架构](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) - _Preethi Kasireddy_ - [2021 年去中心化应用程序指南](https://limechain.tech/blog/what-are-dapps-the-2021-guide/) - _LimeChain_ - [什么是去中心化应用程序?](https://www.gemini.com/cryptopedia/decentralized-applications-defi-dapps) - _Gemini_ - [热门去中心化应用程序](https://www.alchemy.com/dapps) - _Alchemy_ -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ ## 相关主题 {#related-topics} diff --git a/public/content/translations/zh/developers/docs/data-and-analytics/block-explorers/index.md b/public/content/translations/zh/developers/docs/data-and-analytics/block-explorers/index.md index 0425e1b2b8d..9f443285781 100644 --- a/public/content/translations/zh/developers/docs/data-and-analytics/block-explorers/index.md +++ b/public/content/translations/zh/developers/docs/data-and-analytics/block-explorers/index.md @@ -1,6 +1,6 @@ --- -title: 区块浏览器 -description: 这是对于区块浏览器的介绍,让你进入区块链数据世界的大门,在这里你可以查询交易、帐户、合约以及更多以太坊区块链相关数据。 +title: "区块浏览器" +description: "这是对于区块浏览器的介绍,让你进入区块链数据世界的大门,在这里你可以查询交易、帐户、合约以及更多以太坊区块链相关数据。" lang: zh sidebarDepth: 3 --- @@ -9,23 +9,21 @@ sidebarDepth: 3 ## 前提条件 {#prerequisites} -你应该理解以太坊的基本概念,以便你能够理解区块浏览器向你展示的数据。 开始[介绍以太坊](/developers/docs/intro-to-ethereum/)。 +你应该理解以太坊的基本概念,以便你能够理解区块浏览器向你展示的数据。 从[以太坊简介](/developers/docs/intro-to-ethereum/)开始。 ## 服务 {#services} -- [Etherscan](https://etherscan.io/) -_ 还支持中文、韩语、俄语和日语_ +- [Etherscan](https://etherscan.io/) -_还提供中文、韩语、俄语和日语版本_ - [3xpl](https://3xpl.com/ethereum) - [Beaconcha.in](https://beaconcha.in/) -- [Blockchair](https://blockchair.com/ethereum) -_ 还支持西班牙语、法语、意大利语、荷兰语、葡萄牙语、俄语、中文和波斯语_ +- [Blockchair](https://blockchair.com/ethereum) -_还提供西班牙语、法语、意大利语、荷兰语、葡萄牙语、俄语、中文和波斯语版本_ - [Blockscout](https://eth.blockscout.com/) - [Chainlens](https://www.chainlens.com/) - [DexGuru 区块浏览器](https://ethereum.dex.guru/) - [Etherchain](https://www.etherchain.org/) -- [Ethernow](https://www.ethernow.xyz/) -- [Ethplorer](https://ethplorer.io/) -_ 还支持中文、西班牙语、法语、土耳其语、俄语、韩语和越南语_ +- [Ethplorer](https://ethplorer.io/) -_还提供中文、西班牙语、法语、土耳其语、俄语、韩语和越南语版本_ - [EthVM](https://www.ethvm.com/) - [OKLink](https://www.oklink.com/eth) -- [Rantom](https://rantom.app/) - [Ethseer](https://ethseer.io) ## 开源工具 {#open-source-tools} @@ -95,7 +93,7 @@ sidebarDepth: 3 - 燃料限制 – 此交易可以消耗的最大燃料单位数 - 消耗的燃料 – 交易消耗的实际燃料单位数量 - 燃料价格 – 每燃料单位设定的价格 -- 随机数 – `from` 地址的交易号(请记住,它从 0 开始,所以随机数 ` 100` 实际上是该帐户提交的第 101 个交易 +- 随机数 - `from` 地址的交易编号(请注意,此编号从 0 开始,因此随机数为 `100` 的交易实际上是此帐户提交的第 101 笔交易) - 输入数据 – 交易所需的任何额外信息 ### 帐户 {#accounts} @@ -238,20 +236,18 @@ sidebarDepth: 3 ## 区块浏览器 {#block-explorers} -- [Etherscan](https://etherscan.io/) - 可以用来获取以太坊主网和 Sepolia 测试网数据的区块浏览器 -- [3xpl](https://3xpl.com/ethereum) - 无广告、开源的以太坊浏览器,允许你下载自己的数据集 -- [Beaconcha.in](https://beaconcha.in/) - 用于以太坊主网和 Sepolia 测试网的开源区块浏览器 -- [Blockchair](https://blockchair.com/ethereum) - 最具隐私保护性的以太坊浏览器。 也用于排序和过滤(内存池)数据 -- [Etherchain](https://www.etherchain.org/) - 以太坊主网的区块浏览器 -- [Ethplorer](https://ethplorer.io/) - 专注于以太坊主网和 Kovan 测试网代币的区块浏览器 -- [Rantom](https://rantom.app/) - 是一个好用的开源去中心化金融非同质化代币交易查看器,用于提供详细的交易信息。& -- [Ethernow](https://www.ethernow.xyz/) - 一个实时交易浏览器,可让您查看以太坊主网预链层 +- [Etherscan](https://etherscan.io/) - 一款可用于获取以太坊主网和测试网数据的区块浏览器 +- [3xpl](https://3xpl.com/ethereum) - 一款无广告的开源以太坊浏览器,可下载其数据集 +- [Beaconcha.in](https://beaconcha.in/) - 一款用于以太坊主网和测试网的开源区块浏览器 +- [Blockchair](https://blockchair.com/ethereum) - 最具隐私性的以太坊浏览器。 也用于排序和过滤(内存池)数据 +- [Etherchain](https://www.etherchain.org/) - 一款以太坊主网区块浏览器 +- [Ethplorer](https://ethplorer.io/) - 一款专注于以太坊主网和 Kovan 测试网代币的区块浏览器 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -_还有哪些社区资源对你有所帮助? 编辑本页面以添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [交易](/developers/docs/transactions/) - [帐户](/developers/docs/accounts/) diff --git a/public/content/translations/zh/developers/docs/data-and-analytics/index.md b/public/content/translations/zh/developers/docs/data-and-analytics/index.md index a5b74cc5d57..067b77fc406 100644 --- a/public/content/translations/zh/developers/docs/data-and-analytics/index.md +++ b/public/content/translations/zh/developers/docs/data-and-analytics/index.md @@ -1,55 +1,72 @@ --- -title: 数据和分析学 -description: 如何获取在链分析和数据以用于你的去中心化应用程序。 +title: "数据和分析" +description: "如何获取在链分析和数据以用于你的去中心化应用程序" lang: zh --- -## 介绍 {#Introduction} +## 简介 {#Introduction} -随着网络利用率不断提高,链上数据中将有越来越多的宝贵信息。 随着数据量的迅速增加,计算和汇总此信息以报告或驱动一个去中心化应用程序可能变成很费时间和体力的过程。 +随着网络利用率不断提高,链上数据中将有越来越多有价值的信息。 随着数据量的迅速增加,计算和汇总此信息以报告或驱动一个去中心化应用程序可能变成很费时间和体力的过程。 -利用现有数据提供商可以加快发展,产生更准确的结果,并减少正在进行的维护工作。 这将使一个团队能够集中精力处理试图在项目中提供的核心功能。 +利用现有数据提供商可以加快开发、产生更准确的结果,并减少持续的维护工作。 这将使一个团队能够集中精力处理试图在项目中提供的核心功能。 ## 前提条件 {#prerequisites} -你应该理解[区块浏览器](/developers/docs/data-and-analytics/block-explorers/) 的基本概念,以便更好地理解在数据分析环境中使用它们。 此外,熟悉[索引](/glossary/#index)概念,以了解它们给系统设计带来的好处。 +你应该了解[区块浏览器](/developers/docs/data-and-analytics/block-explorers/)的基本概念,以便更好地理解在数据分析环境中使用它们。 此外,请熟悉[索引](/glossary/#index)的概念,以了解其为系统设计带来的好处。 -就架构基础而言,也要从理论上了解[应用程序接口](https://www.wikipedia.org/wiki/API)和 [REST](https://www.wikipedia.org/wiki/Representational_state_transfer) 是什么。 +在架构基础方面,即使只是理论上,也要了解什么是 [API](https://www.wikipedia.org/wiki/API) 和 [REST](https://www.wikipedia.org/wiki/Representational_state_transfer)。 ## 区块浏览器 {#block-explorers} -许多[区块浏览器](/developers/docs/data-and-analytics/block-explorers/)提供 [RESTful](https://www.wikipedia.org/wiki/Representational_state_transfer) [应用程序接口](https://www.wikipedia.org/wiki/API)网关,它将使开发者可以看见关于区块、交易、验证者、帐户和其他链上活动的实时数据。 +许多[区块浏览器](/developers/docs/data-and-analytics/block-explorers/)都提供 [RESTful](https://www.wikipedia.org/wiki/Representational_state_transfer) [API](https://www.wikipedia.org/wiki/API) 网关,让开发者能够查看有关区块、交易、验证者、帐户及其他链上活动的实时数据。 -然后开发者可以处理和转换此数据,让他们的用户有独特的洞察力并与[区块链](/glossary/#blockchain)交互。 例如,[Etherscan](https://etherscan.io) 在每个 12 秒时隙都提供执行和共识数据。 +然后,开发者可以处理和转换这些数据,为其用户提供与[区块链](/glossary/#blockchain)的独特见解和互动。 例如,[Etherscan](https://etherscan.io) 和 [Blockscout](https://eth.blockscout.com) 为每个 12 秒的时隙提供执行层和共识层数据。 -## Graph {#the-graph} +## The Graph {#the-graph} -[Graph 网络](https://thegraph.com/)是用于组织区块链数据的去中心化索引协议。 通过 Graph 网络,开发者可以建立完全在公共基础设施上运行的无服务器应用程序,而不是建立和管理链外和集中的数据存储来聚合链上数据。 +[The Graph](https://thegraph.com/) 是一个索引协议,通过被称为子图 (subgraphs) 的开放 API 提供便捷的区块链数据查询方式。 -使用 [GraphQL](https://graphql.org/),开发人员可以查询任何管理的开放应用程序接口(称为子图),以获取驱动去中心化应用程序所需的信息。 通过查询这些索引子图,报告和去中心化应用程序不仅可以获得性能和可扩展性优势,还可以获得网络共识提供的内置准确性。 当网络中新增改进和/或子图表时,你的项目可以快速迭代,以利用这些增强功能。 +使用 The Graph,开发者可以获得以下优势: -## 客户端多样性 +- 去中心化索引:通过多个索引者索引区块链数据,从而消除任何单点故障 +- GraphQL 查询:提供强大的 GraphQL 接口用于查询已索引数据,使数据检索极为便捷 +- 自定义:定义您自己的逻辑来转换和存储区块链数据,并重用 The Graph 网络上其他开发者发布的子图。 -[客户端多样性](/developers/docs/nodes-and-clients/client-diversity/)对于以太坊网络的整体健康很重要,因为它提供了对错误和漏洞利用的弹性。 目前,出现了一些客户端多样性仪表板,包括 [clientdiversity.org](https://clientdiversity.org/)、[rated.network](https://www.rated.network)、[supermajority.info](https://supermajority.info//) 和 [Ethernodes](https://ethernodes.org/)。 +请按照此[快速入门](https://thegraph.com/docs/en/quick-start/)指南,在 5 分钟内创建、部署和查询子图。 + +## 客户端多样性 {#client-diversity} + +[客户端多样性](/developers/docs/nodes-and-clients/client-diversity/)对以太坊网络的整体健康至关重要,因为它能针对程序错误和漏洞利用提供弹性。 现在有多个客户端多样性仪表板,包括 [clientdiversity.org](https://clientdiversity.org/)、[rated.network](https://www.rated.network)、[supermajority.info](https://supermajority.info//) 和 [Ethernodes](https://ethernodes.org/)。 ## Dune Analytics {#dune-analytics} -[Dune Analytics](https://dune.com/) 对区块链数据进行预处理,并存入关系型数据库 (DuneSQL) 表中,以便用户能够使用结构化查询语言 (SQL) 查询区块链数据并基于查询结果构建仪表板。 链上数据被组织为 4 个原始表:`blocks`、`transactions`、(事件)`logs` 和(调用)`traces`。 常见的合约和协议都已解码,并且每个都有自己的事件集和调用表。 这些事件和调用表被进一步处理并按协议类型组织成抽象表,例如去中心化交易所、借贷、稳定币等。 +[Dune Analytics](https://dune.com/) 对区块链数据进行预处理,并存入关系型数据库 (DuneSQL) 表中,以便用户能够使用 SQL 查询区块链数据并基于查询结果构建仪表板。 链上数据整理到 4 个原始表中:`blocks`、`transactions`、(事件)`logs` 和(调用)`traces`。 常见的合约和协议都已解码,并且每个都有自己的事件集和调用表。 这些事件和调用表被进一步处理并按协议类型组织成抽象表,例如去中心化交易所、借贷、稳定币等。 + +## SQD {#sqd} + +[SQD](https://sqd.dev/) 是一个去中心化的超大规模可扩展数据平台,经过优化,可提供对海量数据的高效、无许可访问。 它目前提供历史链上数据,包括事件日志、交易收据、轨迹以及每笔交易的状态差异。 SQD 提供强大的工具箱,用于创建自定义数据提取和处理管道,使索引速度达到最高每秒 15 万区块。 + +要开始使用,请访问[文档](https://docs.sqd.dev/)或查看可使用 SQD 构建的 [EVM 示例](https://github.com/subsquid-labs/squid-evm-examples)。 ## SubQuery 网络 {#subquery-network} -[SubQuery](https://subquery.network/) 是一个领先的数据索引器,为开发者的 Web3 项目提供快速、可靠、去中心化和定制的应用程序接口。 SubQuery 为超过 165 个生态系统(包括以太坊)的开发者赋能,利用丰富的索引数据,为他们的用户构建直观的、沉浸式体验。 SubQuery 网络通过其富有韧性且去中心化的网络基础设施,为你势不可挡的应用程序提供支持。 使用 SubQuery 的区块链开发者工具包来构建未来的 Web3 应用程序,无需花费时间为数据处理活动搭建定制的后端。 +[SubQuery](https://subquery.network/) 是一个领先的数据索引器,可为开发者的 web3 项目提供快速、可靠、去中心化和定制化的 API。 SubQuery 为超过 165 个生态系统(包括以太坊)的开发者赋能,利用丰富的索引数据,为他们的用户构建直观的、沉浸式体验。 SubQuery 网络通过其富有韧性且去中心化的网络基础设施,为你势不可挡的应用程序提供支持。 使用 SubQuery 的区块链开发者工具包来构建未来的 Web3 应用程序,无需花费时间为数据处理活动搭建定制的后端。 + +要开始使用,请访问[以太坊快速入门指南](https://academy.subquery.network/quickstart/quickstart_chains/ethereum-gravatar.html),以便在几分钟内于本地 Docker 环境中开始索引以太坊区块链数据进行测试,然后再上线到 [SubQuery 的托管服务](https://managedservice.subquery.network/)或 [SubQuery 的去中心化网络](https://app.subquery.network/dashboard)。 -在使用[ SubQuery 托管服务](https://managedservice.subquery.network/)或[ SubQuery 去中心化网络](https://app.subquery.network/dashboard)之前,请先访问[以太坊快速入门指南](https://academy.subquery.network/quickstart/quickstart_chains/ethereum-gravatar.html),在本地 Docker 环境中花几分钟索引以太坊区块链数据作为测试。 +## EVM 查询语言 {#evm-query-language} -## Ethernow - 内存池数据程序 {#ethernow} -[Blocknative](https://www.blocknative.com/) 提供对其以太坊历史[内存池数据归档](https://www.ethernow.xyz/mempool-data-archive)的开放访问。 这使得研究者和社区优秀项目能够探索以太坊主网的链前层。 该数据集得到积极维护,代表了以太坊生态系统中最全面的内存池交易事件历史记录。 在 [Ethernow](https://www.ethernow.xyz/) 了解更多信息。 +EVM 查询语言 (EQL) 是一种类似 SQL 的语言,旨在查询 EVM(以太坊虚拟机)链的信息。 EQL 的目标是对 EVM 链一等实体(区块、账户和交易)进行复杂的关系查询,同时为开发人员和研究人员提供日常使用的人体工程学语法。 使用 EQL,开发人员可以使用熟悉的类似 SQL 的语法获取区块链数据,无需复杂的样板代码。 EQL 支持标准区块链数据请求(例如,检索以太坊上帐户的随机数和余额或了解当前区块大小和时间戳),并且不断支持更复杂的请求和功能。 -## 延伸阅读 {#further-reading} +## 扩展阅读 {#further-reading} -- [Graph 网络概览](https://thegraph.com/docs/en/about/) -- [Graph 查询实战](https://thegraph.com/explorer/subgraph/graphprotocol/graph-network-mainnet?version=current) -- [EtherScan 上的应用程序接口代码示例](https://etherscan.io/apis#contracts) +- [探索加密数据 I:数据流架构](https://web.archive.org/web/20250125012042/https://research.2077.xyz/exploring-crypto-data-1-data-flow-architectures) +- [Graph 网络概述](https://thegraph.com/docs/en/about/) +- [Graph 查询演练场](https://thegraph.com/explorer/subgraph/graphprotocol/graph-network-mainnet?version=current) +- [Etherscan 上的 API 代码示例](https://etherscan.io/apis#contracts) +- [Blockscout 上的 API 文档](https://docs.blockscout.com/devs/apis) - [Beaconcha.in 信标链浏览器](https://beaconcha.in) - [Dune 基础知识](https://docs.dune.com/#dune-basics) - [SubQuery 以太坊快速入门指南](https://academy.subquery.network/indexer/quickstart/quickstart_chains/ethereum-gravatar.html) +- [SQD 网络概述](https://docs.sqd.dev/) +- [EVM 查询语言](https://eql.sh/blog/alpha-release-notes) diff --git a/public/content/translations/zh/developers/docs/data-availability/blockchain-data-storage-strategies/index.md b/public/content/translations/zh/developers/docs/data-availability/blockchain-data-storage-strategies/index.md index 72bc1e63f42..1ce27c11aeb 100644 --- a/public/content/translations/zh/developers/docs/data-availability/blockchain-data-storage-strategies/index.md +++ b/public/content/translations/zh/developers/docs/data-availability/blockchain-data-storage-strategies/index.md @@ -1,6 +1,6 @@ --- -title: 区块链数据存储策略 -description: 有几种使用区块链储存数据的方式。 本文将比较不同的策略、它们的费用和权衡,以及安全使用策略的要求。 +title: "区块链数据存储策略" +description: "有几种使用区块链储存数据的方式。 本文将比较不同的策略、它们的费用和权衡,以及安全使用策略的要求。" lang: zh --- @@ -10,13 +10,13 @@ lang: zh - 调用数据 - 具有一层网络机制的链下 - 合约“代码” -- 事件 +- 活动 - 以太坊虚拟机存储 使用方法的选择基于几个标准: - 信息来源。 调用数据中的信息不能直接来自区块链本身。 -- 信息目的地。 Calldata 仅在其发起的交易中可用。 链上完全无法访问事件。 +- 信息目的地。 Calldata 仅在包含它的交易中可用。 链上完全无法访问事件。 - 能够接受多少麻烦? 相比在浏览器内运行的应用程序中的轻客户端,运行全节点的计算机能够执行更多处理。 - 是否有必要使来自每个节点的信息易于访问? - 安全要求。 @@ -63,7 +63,7 @@ EIP-4844 二进制大对象的主要使用案例是供卷叠发布其交易。 [ 这是将数据永久放在区块链上最便宜的方法。 每个字节的费用为 4 执行燃料(如果字节为 0) 或 16 执行燃料(如果字节为任意其他值)。 如果数据经过压缩(这是标准做法),则每个字节的值几乎相等,所以每个字节的平均费用约为 15.95 燃料。 -撰写本文时的价格为 12 Gwei/燃料(2300 美元/以太币),这意味着每个字节的费用约为 45 美分。 由于这是 EIP-4844 之前最便宜的方法,卷叠使用此方法来储存交易信息,这些交易信息必须在[缺陷质询期](https://docs.optimism.io/stack/protocol/overview#fault-proofs)内可用,但无需直接在链上访问。 +撰写本文时的价格为 12 Gwei/燃料(2300 美元/以太币),这意味着每千字节的费用约为 45 美分。 由于这是 EIP-4844 之前最便宜的方法,卷叠使用此方法来储存交易信息,这些交易信息必须在[缺陷质询期](https://docs.optimism.io/stack/protocol/overview#fault-proofs)内可用,但无需直接在链上访问。 在以下地址可以查看一些知名卷叠发布的交易。 @@ -114,5 +114,5 @@ EIP-4844 二进制大对象的主要使用案例是供卷叠发布其交易。 [ | 调用数据 | 链下 | 由以太坊永久保证(区块链的一部分) | 只有被写入合约时于该交易可用 | | | 具有一层网络机制的链下 | 链下 | 在质询期内由“一名诚实的验证者”保证 | 仅哈希可用 | 仅在质询期内由质询机制提供保证 | | 合约代码 | 链上或链下 | 由以太坊永久保证(区块链的一部分) | 是 | 写入到一个不以 `0xEF` 开头的“随机”地址 | -| 事件 | 链上 | 由以太坊永久保证(区块链的一部分) | 否 | | +| 活动 | 链上 | 由以太坊永久保证(区块链的一部分) | 否 | | | 存储 | 链上 | 由以太坊永久保证(区块链的一部分,并保持当前状态直至被覆盖) | 是 | | diff --git a/public/content/translations/zh/developers/docs/data-availability/index.md b/public/content/translations/zh/developers/docs/data-availability/index.md index df19a599b8e..f0334072709 100644 --- a/public/content/translations/zh/developers/docs/data-availability/index.md +++ b/public/content/translations/zh/developers/docs/data-availability/index.md @@ -1,84 +1,84 @@ --- -title: 数据可用性 -description: 以太坊中数据可用性问题和解决方案概述 +title: "数据可用性" +description: "以太坊中数据可用性问题和解决方案概述" lang: zh --- “不信任,验证”是以太坊中通用的信条。 这种观念是指,你的节点可以通过执行从对等节点接收的区块中的所有交易来独立验证它收到的信息是正确的,以此来确保提议的更改与其独立计算出的更改完全一致。 这意味着节点无需相信区块的发送者是诚实的。 但如果数据遗失,就无法验证。 -**数据可用性**是指用户能够确信,验证区块所需的数据确实可供所有网络参与者使用。 对于在以太坊一层网络上的全节点来说,数据可用性相对简单;全节点下载每个区块中所有数据的副本 - 这些数据_必须_可用才能使下载得以进行。 数据缺失的区块将被丢弃,而不是添加进区块链。 这就是“链上数据可用性”,是单片式区块链的特征。 无法欺骗全节点让其接受无效交易,因为它们自己下载并执行所有交易。 然而,对于模块化区块链、二层网络卷叠和轻客户端来说,数据可用性局面更加复杂,需要更加复杂的验证程序。 +**数据可用性**是指用户能够确信,验证区块所需的数据确实可供所有网络参与者使用。 对于以太坊 Layer 1 上的全节点来说,这相对简单;全节点会下载每个区块中所有数据的副本——数据_必须_可用,下载才可能进行。 数据缺失的区块将被丢弃,而不是添加进区块链。 这就是”链上数据可用性“,是单片式区块链的特征。 无法欺骗全节点让其接受无效交易,因为它们自己下载并执行所有交易。 然而,对于模块化区块链、二层网络卷叠和轻客户端来说,数据可用性局面更加复杂,需要更加复杂的验证程序。 -## 前言 {#prerequisites} +## 前提条件 {#prerequisites} -你应该很好地理解[区块链基础知识](/developers/docs/intro-to-ethereum/),尤其是[共识机制](/developers/docs/consensus-mechanisms/)。 本页面还假设读者熟悉[区块](/developers/docs/blocks/)、[交易](/developers/docs/transactions/)、[节点](/developers/docs/nodes-and-clients/)、[扩容解决方案](/developers/docs/scaling/)和其他相关主题。 +你应该对[区块链基础知识](/developers/docs/intro-to-ethereum/)有很好的了解,尤其是[共识机制](/developers/docs/consensus-mechanisms/)。 本页面还假设读者熟悉[区块](/developers/docs/blocks/)、[交易](/developers/docs/transactions/)、[节点](/developers/docs/nodes-and-clients/)、[扩容解决方案](/developers/docs/scaling/)及其他相关主题。 ## 数据可用性问题 {#the-data-availability-problem} 数据可用性问题是指,需要向整个网络证明正在被添加到区块链中的某些汇总交易数据确实代表一组有效的交易,但在证明时不需要所有节点下载所有数据。 完整的交易数据是独立验证块所必需的,但要求所有节点下载所有交易数据是对扩容的阻碍。 解决数据可用性问题的目的是充分保证,自己不下载和存储数据的网络参与者可以使用全部交易数据进行验证。 -对于需要可靠的数据可用性保障但无法自己下载和处理交易数据的网络参与者,[轻节点](/developers/docs/nodes-and-clients/light-clients)和[二层网络卷叠](/developers/docs/scaling)是两个重要示例。 无需下载交易数据是轻节点之所以轻量并让卷叠成为有效扩容解决方案的原因。 +[轻节点](/developers/docs/nodes-and-clients/light-clients)和 [Layer 2 卷叠](/developers/docs/scaling)是重要的网络参与者示例,它们需要强大的数据可用性保证,但无法自行下载和处理交易数据。 无需下载交易数据是轻节点之所以轻量并让卷叠成为有效扩容解决方案的原因。 -对于无需下载并存储数据以验证区块的未来[“无状态”](/roadmap/statelessness)以太坊客户端,数据可用性也是一个重要关切点。 无状态客户端仍需要确认数据_在某处_可用并且已被正确处理。 +数据可用性对于未来的["无状态"](/roadmap/statelessness)以太坊客户端来说也是一个关键问题,这些客户端无需下载和存储状态数据即可验证区块。 无状态客户端仍需要确定数据_在某个地方_是可用的,并且已被正确处理。 ## 数据可用性解决方案 {#data-availability-solutions} ### 数据可用性采样 (DAS) {#data-availability-sampling} -数据可用性采样 (DAS) 是网络在不给任何单个节点带来过多压力的情况下检查数据是否可用的一种方法。 每个节点(包括非质押节点)下载全部数据中随机选择的数据小子集。 成功地下载样本便可以非常肯定地确认所有数据都是可用的。 这依赖于数据纠删码,即用冗余信息扩展给定的数据集(实现方法是将一个称为_多项式_的函数与数据拟合,并在额外的点上对该多项式进行评估)。 这样可以在必要时从冗余数据中恢复原始数据。 这种数据创建的结果是,如果原始数据中的_任何_部分不可用,那么_一半_的扩展数据将丢失! 每个节点下载的数据样本量可以进行调整,以便_在_实际上不到一半的数据可用时,每个客户端采样的数据片段_极有可能_至少缺失一个。 +数据可用性采样 (DAS) 是网络在不给任何单个节点带来过多压力的情况下检查数据是否可用的一种方法。 每个节点(包括非质押节点)下载全部数据中随机选择的数据小子集。 成功地下载样本便可以非常肯定地确认所有数据都是可用的。 这依赖于数据纠删码,它用冗余信息来扩展给定的数据集(实现方法是将一个称为_多项式_的函数与数据拟合,并在额外的点上对该多项式进行评估)。 这样可以在必要时从冗余数据中恢复原始数据。 这种数据创建的一个后果是,如果_任何_原始数据不可用,那么扩展数据中的_一半_将会丢失! 每个节点下载的数据样本量可以调整,这样_如果_实际可用的数据不足一半,那么每个客户端采样的数据片段就_极有_可能至少会丢失一个。 -DAS 将用于确保汇总运营商在实施[完整 Danksharding](/roadmap/danksharding/#what-is-danksharding) 后提供其交易数据。 以太坊节点将使用上述冗余方案,随机采样二进制大对象中提供的交易数据,以确保所有数据都存在。 同样的技术也可用于确保区块生产者让将其所有数据可用,以保护轻客户端的安全。 同样,在[提议者-构建者分离](/roadmap/pbs)的情况下,只要求区块构建者处理整个区块,其他验证者将使用数据可用性采样进行验证。 +在[完整 Danksharding](/roadmap/danksharding/#what-is-danksharding) 实施后,DAS 将用于确保卷叠运营方公布其交易数据。 以太坊节点将使用上述冗余方案,随机采样二进制大对象中提供的交易数据,以确保所有数据都存在。 同样的技术也可用于确保区块生产者让将其所有数据可用,以保护轻客户端的安全。 同样,在[提议者-构建者分离](/roadmap/pbs)下,只需要区块构建者处理整个区块——其他验证者将使用数据可用性采样进行验证。 ### 数据可用性委员会 {#data-availability-committees} -数据可用性委员会 (DAC) 是提供或证明数据可用性的可信参与方。 可以使用数据可用性委员会而非数据可用性采样,或者可以[两者结合](https://hackmd.io/@vbuterin/sharding_proposal#Why-not-use-just-committees-and-not-DAS)使用。 数据可用性委员会提供的安全保证取决于具体设置。 例如,以太坊使用随机抽样的验证者子集来证明轻节点的数据可用性。 +数据可用性委员会 (DAC) 是提供或证明数据可用性的可信参与方。 数据可用性委员会 (DAC) 可以替代 DAS,[或与](https://hackmd.io/@vbuterin/sharding_proposal#Why-not-use-just-committees-and-not-DAS) DAS 结合使用。 数据可用性委员会提供的安全保证取决于具体设置。 例如,以太坊使用随机抽样的验证者子集来证明轻节点的数据可用性。 一些 Validium 也使用数据可用性委员会。 数据可用性委员会是一组可信节点,它们在线下存储数据副本。 在出现争议时,需要通过数据可用性委员会来确保数据可用。 数据可用性委员会的成员还需要发布链上认证来证明这些数据确实是可用的。 有些 Validium 使用权益证明 (PoS) 验证者系统代替数据可用性委员会。 在该系统中,任何人都能成为验证者并在链下存储数据。 然而,他们必须提供“保证金”,并且保证金存入到智能合约中。 在发生恶意行为时,例如验证者隐藏数据,保证金会被罚没。 权益证明数据可用性委员会在安全性方面明显优于一般数据可用性委员,因为它们直接激励诚实的行为。 -## 数据可用性与轻节点 {#data-availability-and-light-nodes} +## 数据可用性和轻节点 {#data-availability-and-light-nodes} -[轻节点](/developers/docs/nodes-and-clients/light-clients)需要验证收到的区块头的正确性,不用下载区块数据。 轻节点轻量化的代价就是无法像全节点那样在本地独立地重新执行交易以验证区块头。 +[轻节点](/developers/docs/nodes-and-clients/light-clients)需要验证所接收区块头的正确性,而无需下载区块数据。 轻节点轻量化的代价就是无法像全节点那样在本地独立地重新执行交易以验证区块头。 -以太坊轻节点信任由 512 个验证者组成的随机验证者组,该验证者组被分配到一个_同步委员会_。 同步委员会充当数据可用性委员会,使用加密签名向轻节点表明区块头中的数据是正确的。 同步委员会每天都刷新。 每个区块头都提醒轻节点哪些验证者应签核_下一个_区块,这样轻节点就不会被骗相信假装成真正同步委员会的恶意小组。 +以太坊轻节点信任由 512 个验证者组成的随机集合,这些验证者被分配到一个_同步委员会_。 同步委员会充当数据可用性委员会,使用加密签名向轻节点表明区块头中的数据是正确的。 同步委员会每天都刷新。 每个区块头都会提醒轻节点,预期哪些验证者会签发_下一个_区块,这样它们就不会被骗去信任一个冒充真实同步委员会的恶意团体。 -但是,如果攻击者_确实_想方设法向轻节点传输了恶意区块头,并使轻节点相信它是由诚实的同步委员会签核的,会发生什么? 在这种情况下,攻击者可能会添加无效的交易,而轻节点将会盲目地接受它们,因为轻节点无法独立验证汇总在区块头中的所有状态变化。 为了防止这种情况,轻节点可以使用欺诈证明。 +但是,如果攻击者_确实_设法将恶意区块头传递给轻客户端,并使他们相信该区块头是由诚实的同步委员会签署的,会发生什么? 在这种情况下,攻击者可能会添加无效的交易,而轻节点将会盲目地接受它们,因为轻节点无法独立验证汇总在区块头中的所有状态变化。 为了防止这种情况,轻节点可以使用欺诈证明。 欺诈证明的工作原理如下:全节点发现一个无效状态转换在网络上广播时,可以快速生成证明已提议状态转换不可能源自给定一组交易的一小段数据,并把这段数据广播到对等节点。 轻节点可以选取这些欺诈证明并用来丢弃有害的区块头,确保它们和全节点留在相同的诚实区块链上。 这仰仗于全节点能够访问完整的交易数据。 广播有害区块头并且不提供交易数据的攻击者可能能够阻止全节点生成欺诈证明。 全节点也许可以发出关于有害区块的警告,但没有证据来证明它们的警告,因为没有可用于生成证明据的数据! -数据可用性采样可以解决这个数据可用性问题。 轻节点下载完整状态数据的小随机片段,并使用这些样本验证完整数据集可用。 在下载 N 个随机片段后,对完整数据的可用性做出错误估计的真实可能性是可以计算的([如果是 100 个数据片段,则概率是 10^-30](https://dankradfeist.de/ethereum/2019/12/20/data-availability-checks.html),也就是说几乎不可能)。 +数据可用性采样可以解决这个数据可用性问题。 轻节点下载完整状态数据的小随机片段,并使用这些样本验证完整数据集可用。 在下载 N 个随机数据块后错误地假定数据完全可用的实际可能性是可以计算的([下载 100 个数据块的概率为 10^-30](https://dankradfeist.de/ethereum/2019/12/20/data-availability-checks.html),即极不可能)。 即使出现错误估计,仅仅隐藏几个字节的攻击,可能不会被发出随机数据请求的客户端所察觉。 纠删码通过重建丢失的小数据片段来解决这个问题,这些数据片段可用来检查提议的状态变化。 然后,可以使用重建的数据构建欺诈证明,防止轻节点接受有害的区块头。 -**注意:**数据可用性采样和欺诈证明尚未在权益证明以太坊轻客户端上实现,但它们已经在规划中,很可能采取基于 ZK-SNARK 证明的形式。 目前,轻客户端依赖于一种数据可用性委员会:它们验证同步委员会的身份,然后信任接收到的已签名区块头。 +\*\*注意:\*\*数据可用性采样 (DAS) 和欺诈证明尚未为权益证明以太坊轻客户端实现,但它们已在路线图上,很可能采取基于 ZK-SNARK 的证明形式。 目前,轻客户端依赖于一种数据可用性委员会:它们验证同步委员会的身份,然后信任接收到的已签名区块头。 ## 数据可用性和二层网络卷叠 {#data-availability-and-layer-2-rollups} -[二层网络扩容方案](/layer-2/)(例如[卷叠](/glossary/#rollups))通过在链下处理交易减少交易费用并增加以太坊的吞吐量。 卷叠交易是分批次压缩并发布到以太坊上。 批次表示将成千上万单个链下交易打包到以太坊上的单个交易中。 这减少了基础层的拥塞并降低了用户费用。 +[二层网络扩容解决方案](/layer-2/),例如[卷叠](/glossary/#rollups),通过在链下处理交易来降低交易成本并提高以太坊的吞吐量。 卷叠交易是分批次压缩并发布到以太坊上。 批次表示将成千上万单个链下交易打包到以太坊上的单个交易中。 这减少了基础层的拥塞并降低了用户费用。 然而,只有提议的状态变化可被独立验证并确认是应用所有单独链下交易的结果时,才能信任发布到以太坊上的“汇总”交易。 如果卷叠运营者不提供进行此验证所需的交易数据,那么它们可以将不正确的数据发送至以太坊。 -[乐观卷叠](/developers/docs/scaling/optimistic-rollups/)将压缩交易数据发布到以太坊并等待一定时间(通常为 7 天),以便独立验证者检查数据。 如果有任何验证者发现问题,它们可以生成欺诈证明并用来质疑卷叠。 这将导致链回滚并丢弃无效区块。 只有在数据可用时,才能实现这一点。 目前,乐观卷叠有两种方式将交易数据发布到一层网络。 有些卷叠使数据以 `CALLDATA` 的形式永久可用,并永久存在于链上。 随着 EIP-4844 的实施,一些卷叠将其交易数据发布到更便宜的二进制大对象存储中。 它不是永久存储。 独立验证者必须在数据从以太坊第 1 层删除之前约 18 天内查询二进制大对象并提出挑战。 通过以太坊协议,数据可用性仅在一个短暂的固定窗口期内得到保证。 此后,数据可用性成为以太坊生态系统中其他实体的责任。 任何节点都可以使用数据可用性采样来验证数据可用性,即下载二进制大对象数据的随机小样本。 +[乐观卷叠](/developers/docs/scaling/optimistic-rollups/)将压缩后的交易数据发布到以太坊,并等待一段时间(通常为 7 天),以允许独立验证者检查数据。 如果有任何验证者发现问题,它们可以生成欺诈证明并用来质疑卷叠。 这将导致链回滚并丢弃无效区块。 只有在数据可用时,才能实现这一点。 目前,乐观卷叠有两种方式将交易数据发布到一层网络。 一些卷叠以 `CALLDATA` 的形式使数据永久可用,这些数据永久存在于链上。 随着 EIP-4844 的实施,一些卷叠将其交易数据发布到更便宜的二进制大对象存储中。 它不是永久存储。 独立验证者必须在数据从以太坊第 1 层删除之前约 18 天内查询二进制大对象并提出挑战。 通过以太坊协议,数据可用性仅在一个短暂的固定窗口期内得到保证。 此后,数据可用性成为以太坊生态系统中其他实体的责任。 任何节点都可以使用 DAS 验证数据可用性,即通过下载 blob 数据的小型随机样本。 -[零知识 (ZK) 卷叠](/developers/docs/scaling/zk-rollups)无需发布交易数据,因为[零知识有效性证明](/glossary/#zk-proof)可保证状态转换的正确性。 然而,数据可用性依然是一个问题,因为在不访问其状态数据的情况下我们无法担保零知识卷叠的功能(或与之交互)。 例如,如果运营者隐瞒了卷叠状态的细节,用户就无法知道自己的余额。 而且,用户也不能使用新添加区块中的信息来执行状态更新。 +[零知识 (ZK) 卷叠](/developers/docs/scaling/zk-rollups)不需要发布交易数据,因为[零知识有效性证明](/glossary/#zk-proof)保证了状态转换的正确性。 然而,数据可用性依然是一个问题,因为在不访问其状态数据的情况下我们无法担保零知识卷叠的功能(或与之交互)。 例如,如果运营者隐瞒了卷叠状态的细节,用户就无法知道自己的余额。 而且,用户也不能使用新添加区块中的信息来执行状态更新。 ## 数据可用性与数据可检索性 {#data-availability-vs-data-retrievability} 数据可用性不同于数据可检索性。 数据可用性是一种保障,它确保全节点能够访问和验证与某个特定区块相关的全部交易。 然而,数据也不见得始终可以访问。 -数据可检索性是指节点从区块链中检索_历史信息_的能力。 验证新区块不需要此历史数据,历史数据仅用于将全节点与创世区块同步或者满足具体的历史数据请求。 +数据可检索性是节点从区块链中检索_历史信息_的能力。 验证新区块不需要此历史数据,历史数据仅用于将全节点与创世区块同步或者满足具体的历史数据请求。 -核心以太坊协议主要涉及数据可用性,而不是数据可检索性。 数据可检索性可由第三方管理的少数归档节点提供,或者可以通过去中心化文件存储(如 [Portal Network](https://www.ethportal.net/))来分散到整个网络。 +核心以太坊协议主要涉及数据可用性,而不是数据可检索性。 数据可检索性可以由第三方运行的少量存档节点提供,也可以使用去中心化文件存储(例如 [Portal Network](https://www.ethportal.net/))分布在整个网络中。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [到底什么是数据可用性?](https://medium.com/blockchain-capital-blog/wtf-is-data-availability-80c2c95ded0f) -- [什么是数据可用性?](https://coinmarketcap.com/alexandria/article/what-is-data-availability) -- [以太坊链下数据可用性概况](https://blog.celestia.org/ethereum-off-chain-data-availability-landscape/) -- [数据可用性检查入门知识](https://dankradfeist.de/ethereum/2019/12/20/data-availability-checks.html) -- [分片 + 数据可用性委员会提案释义](https://hackmd.io/@vbuterin/sharding_proposal#ELI5-data-availability-sampling) +- [什么是数据可用性?](https://medium.com/blockchain-capital-blog/wtf-is-data-availability-80c2c95ded0f) +- [什么是数据可用性?](https://coinmarketcap.com/academy/article/what-is-data-availability) +- [数据可用性检查入门](https://dankradfeist.de/ethereum/2019/12/20/data-availability-checks.html) +- [分片 + DAS 提案解说](https://hackmd.io/@vbuterin/sharding_proposal#ELI5-data-availability-sampling) - [关于数据可用性和纠删码的说明](https://github.com/ethereum/research/wiki/A-note-on-data-availability-and-erasure-coding#can-an-attacker-not-circumvent-this-scheme-by-releasing-a-full-unavailable-block-but-then-only-releasing-individual-bits-of-data-as-clients-query-for-them) - [数据可用性委员会。](https://medium.com/starkware/data-availability-e5564c416424) - [权益证明数据可用性委员会。](https://blog.matter-labs.io/zkporter-a-breakthrough-in-l2-scaling-ed5e48842fbf) - [数据可检索性问题的解决方案](https://notes.ethereum.org/@vbuterin/data_sharding_roadmap#Who-would-store-historical-data-under-sharding) -- [数据可用性或:卷叠如何学会停止担忧并爱上以太坊](https://ethereum2077.substack.com/p/data-availability-in-ethereum-rollups) +- [数据可用性,或:卷叠如何学会不再担忧并爱上以太坊](https://web.archive.org/web/20250515194659/https://web.archive.org/web/20241108192208/https://research.2077.xyz/data-availability-or-how-rollups-learned-to-stop-worrying-and-love-ethereum) +- [EIP-7623:增加 Calldata 成本](https://web.archive.org/web/20250515194659/https://research.2077.xyz/eip-7623-increase-calldata-cost) diff --git a/public/content/translations/zh/developers/docs/data-structures-and-encoding/index.md b/public/content/translations/zh/developers/docs/data-structures-and-encoding/index.md index 826e55f2689..95e82078aef 100644 --- a/public/content/translations/zh/developers/docs/data-structures-and-encoding/index.md +++ b/public/content/translations/zh/developers/docs/data-structures-and-encoding/index.md @@ -1,32 +1,32 @@ --- -title: 数据结构与编码 -description: 以太坊基础数据结构概览。 +title: "数据结构与编码" +description: "以太坊基础数据结构概览。" lang: zh sidebarDepth: 2 --- -以太坊会产生、存储和传输大量的数据。 这些数据必须以标准且节约内存的方式格式化,以便任何人都能在相对普通的消费级硬件上[运行节点](/run-a-node/)。 为实现这一目的,以太坊协议栈中使用了一些特殊的数据结构。 +以太坊会产生、存储和传输大量的数据。 这些数据必须以标准且节约内存的方式格式化,以便任何人都可以在相对普通的消费级硬件上[运行节点](/run-a-node/)。 为实现这一目的,以太坊协议栈中使用了一些特殊的数据结构。 ## 前提条件 {#prerequisites} -在继续阅读本文章之前,你应当对以太坊和[客户端软件](/developers/docs/nodes-and-clients/)的基本原理已经有所了解。 若是熟悉网络层这一概念和[以太坊白皮书](/whitepaper/)的话会更好。 +你应该了解以太坊和[客户端软件](/developers/docs/nodes-and-clients/)的基础知识。 建议熟悉网络层和[以太坊白皮书](/whitepaper/)。 ## 数据结构 {#data-structures} -### 默克尔前缀树 {#patricia-merkle-tries} +### 帕特里夏-默克尔前缀树 {#patricia-merkle-tries} 默克尔前缀树是一种数据结构,将给定的键值对编码成具有确定性且经过加密验证的前缀树。 以太坊在其执行层中广泛运用这一数据结构。 -[详细了解默克尔前缀树](/developers/docs/data-structures-and-encoding/patricia-merkle-trie) +[关于帕特里夏-默克尔前缀树的更多信息](/developers/docs/data-structures-and-encoding/patricia-merkle-trie) ### 递归长度前缀 {#recursive-length-prefix} 递归长度前缀 (RLP) 是一种在以太坊执行层中广泛使用的序列化方法。 -[详细了解递归长度前缀](/developers/docs/data-structures-and-encoding/rlp) +[关于 RLP 的更多信息](/developers/docs/data-structures-and-encoding/rlp) ### 简单序列化 {#simple-serialize} 简单序列化 (SSZ) 是一种序列化格式。它能够进行默克尔化,因而成为了以太坊共识层主要的序列化格式。 -[详细了解简单序列化](/developers/docs/data-structures-and-encoding/ssz) +[关于 SSZ 的更多信息](/developers/docs/data-structures-and-encoding/ssz) diff --git a/public/content/translations/zh/developers/docs/data-structures-and-encoding/patricia-merkle-trie/index.md b/public/content/translations/zh/developers/docs/data-structures-and-encoding/patricia-merkle-trie/index.md index fc7e8507169..a6e40b674ae 100644 --- a/public/content/translations/zh/developers/docs/data-structures-and-encoding/patricia-merkle-trie/index.md +++ b/public/content/translations/zh/developers/docs/data-structures-and-encoding/patricia-merkle-trie/index.md @@ -1,23 +1,23 @@ --- -title: 默克尔帕特里夏字典树 -description: 默克尔帕特里夏树简介。 +title: "默克尔帕特里夏字典树" +description: "默克尔帕特里夏树简介。" lang: zh sidebarDepth: 2 --- 以太坊的状态(全体帐户、余额与智能合约)被编码进一个特殊版本的数据结构中,在计算机科学中,这种数据结构通常称为默克尔树。 这种结构可用于许多加密学应用,因为它在树中保存的所有单独数据之间创建了可验证的关系,产生一个可用于证明数据的单独**根**值。 -以太坊的数据结构是一个“修改版默克尔帕特里夏字典树”,之所以这样命名,不仅是因为它引入了 PATRICIA 算法(检索用字母数字编码的信息的实用算法)的一些特性,也由于它旨在实现含有以太坊状态的值的高效数据**检索**。 +以太坊的数据结构是“修改版默克尔-帕特里夏树”,之所以这样命名,不仅是因为它引入了 PATRICIA 算法(检索用字母数字编码的信息的实用算法)的一些特性,也由于它旨在实现含有以太坊状态的值的高效数据 re**trie**val(检索)。 -默克尔帕特里夏字典树是确定性的并可通过密码学验证:生成状态根的唯一方式是从每个单独的状态进行计算,且两个相同的状态可以通过比较根哈希和父节点哈希(_默克尔证明_)而轻松证明相同。 相反,也无法用同一根哈希创建两个不同的状态,任何用不同值修改状态的尝试都会产生不同的状态根哈希。 理论上,这种结构在插入、查找和删除操作上的效率达到了超乎寻常的 `O(log(n))`。 +默克尔-帕特里夏树是确定性的,并且可以通过密码学来验证:生成状态根的唯一方法是从状态的每个单独部分进行计算,并且可以通过比较根哈希以及引向它的哈希(_默克尔证明_)来轻松证明两个相同的状态。 相反,也无法用同一根哈希创建两个不同的状态,任何用不同值修改状态的尝试都会产生不同的状态根哈希。 理论上,该结构为插入、查找和删除提供了 `O(log(n))` 效率的“圣杯”。 -在不久的将来,以太坊计划迁移到[沃克尔树](/roadmap/verkle-trees)结构,这将为未来的协议改进开创更多新的可能性。 +在不久的将来,以太坊计划迁移到 [Verkle 树](/roadmap/verkle-trees)结构,这将为未来的协议改进开创更多新的可能性。 ## 前提条件 {#prerequisites} -为了更好地理解本文,具备以下基础知识将有所帮助:[哈希](https://en.wikipedia.org/wiki/Hash_function)、[默克尔树](https://en.wikipedia.org/wiki/Merkle_tree)、[字典树](https://en.wikipedia.org/wiki/Trie)和[序列化](https://en.wikipedia.org/wiki/Serialization)。 本文从描述基本的[基数树](https://en.wikipedia.org/wiki/Radix_tree)开始,并逐步介绍使以太坊数据结构更为优化的必要修改措施。 +为了更好地理解本页面,掌握一些关于[哈希](https://en.wikipedia.org/wiki/Hash_function)、[默克尔树](https://en.wikipedia.org/wiki/Merkle_tree)、[字典树](https://en.wikipedia.org/wiki/Trie)和[序列化](https://en.wikipedia.org/wiki/Serialization)的基础知识会很有帮助。 本文首先描述基本的[基数树](https://en.wikipedia.org/wiki/Radix_tree),然后逐步介绍为实现以太坊更优化的数据结构而必需的修改。 -## 基数树 {#basic-radix-tries} +## 基本基数树 {#basic-radix-tries} 在一个基数树中,每个节点如下所示: @@ -25,19 +25,19 @@ sidebarDepth: 2 [i_0, i_1 ... i_n, value] ``` -其中,`i_0 ... i_n` 代表字母表的符号(通常是二进制或十六进制),`value` 是节点的终点值,`i_0, i_1 ... i_n` 插槽的值要么是 `NULL`,要么是指向其他节点(在本例中,是其他节点的哈希)的指针。 这形成了基本的 `(key, value)` 存储。 +其中 `i_0 ...` i_n` 表示字母表的符号(通常是二进制或十六进制),`value`是节点的终端值,而`i_0, i_1 ...` 中的值 i_n` 槽位要么是 `NULL`,要么是指向其他节点的指针(在我们的例子中,是哈希)。 这形成了基本的 `(key, value)` 存储。 -假设你想使用基数树数据结构永久保存一组键值对的次序。 为了在字典树中找到与键 `dog` 映射的值,首先需要把 `dog` 转换成字母表中的字母(给出 `64 6f 67`),然后沿着该路径向下遍历字典树,直到找到该值。 也就是说,为了找到字典树的根节点,你先在平面键/值数据库中查找根哈希。 它表示一组指向其他节点的键。 你会使用索引 `6` 的值作为键,并通过在平面键/值数据库中查找该键来获取下一层的节点。 然后使用索引 `4` 查找下一个值,再使用索引 `6`,以此类推,直到遍历路径 `root -> 6 -> 4 -> 6 -> 15 -> 6 -> 7` 后,你将找到该节点的值并且返回结果。 +假设你想使用基数树数据结构永久保存一组键值对的次序。 要在树中查找当前映射到键 `dog` 的值,您需要先将 `dog` 转换为字母表中的字母(得出 `64 6f 67`),然后沿着该路径向下遍历树,直到找到该值。 也就是说,为了找到字典树的根节点,你先在平面键/值数据库中查找根哈希。 它表示一组指向其他节点的键。 您将使用索引 `6` 处的值作为键,并在平面键/值数据库中查找它,以获取下一层的节点。 然后选择索引 `4` 来查找下一个值,再选择索引 `6`,依此类推,直到您循着路径:`root -> 6 -> 4 -> 6 -> 15 -> 6 -> 7`,您就可以查到节点的值并返回结果。 -从前缀树中查询和从其底层的固定“键/值”数据库中查询存在差异。 它们都定义了“键/值”对,但底层数据库能对键执行传统的 1 步查找。 而在前缀树中查询一个键对应的值则需要在底层数据库中查询多次才能得到最终结果。 我们把后者的查询方式称作 `path`,以避免描述上的模糊。 +从前缀树中查询和从其底层的固定“键/值”数据库中查询存在差异。 它们都定义了“键/值”对,但底层数据库能对键执行传统的 1 步查找。 而在前缀树中查询一个键对应的值则需要在底层数据库中查询多次才能得到最终结果。 为了消除歧义,我们将后者称为 `path`。 基数树的更新和删除操作定义如下: -``` +```python def update(node_hash, path, value): - curnode = db.get(node_hash) if node_hash else [ NULL ] * 17 + curnode = db.get(node_hash) if node_hash else [NULL] * 17 newnode = curnode.copy() - if path == '': + if path == "": newnode[-1] = value else: newindex = update(curnode[path[0]], path[1:], value) @@ -51,7 +51,7 @@ sidebarDepth: 2 else: curnode = db.get(node_hash) newnode = curnode.copy() - if path == '': + if path == "": newnode[-1] = NULL else: newindex = delete(curnode[path[0]], path[1:]) @@ -64,107 +64,110 @@ sidebarDepth: 2 return hash(newnode) ``` -“默克尔”基数树是通过使用确定性生成的加密哈希摘要链接节点来构建的。 这种(键/值数据库中 `key == keccak256(rlp(value))`)内容寻址提供了存储数据的加密完整性保障。 如果给定字典树的根哈希是公开的,那么任何可以访问底层叶数据的人都可以通过提供将特定值与树根连接的每个节点的哈希,来证明该字典树在特定路径中包含给定值。 +“默克尔”基数树是通过使用确定性生成的加密哈希摘要链接节点来构建的。 这种内容寻址(在键/值数据库中 `key == keccak256(rlp(value))`)为存储的数据提供了加密完整性保证。 如果给定字典树的根哈希是公开的,那么任何可以访问底层叶数据的人都可以通过提供将特定值与树根连接的每个节点的哈希,来证明该字典树在特定路径中包含给定值。 -对于攻击者来说,他们无法证明 `(path, value)` 对不存在,因为根哈希从根本上基于它下方的所有哈希。 任何底层的修改都会改变根哈希。 可以将哈希看作是数据结构信息的一种压缩表示,并由哈希函数的预映射保护所保障。 +攻击者不可能提供不存在的 `(path, value)` 对的证明,因为根哈希最终基于其下的所有哈希。 任何底层的修改都会改变根哈希。 可以将哈希看作是数据结构信息的一种压缩表示,并由哈希函数的预映射保护所保障。 -我们把基数树的原子单位(例如单个十六进制字符或 4 位二进制数)称为“半字节”。 如上文所述,以半字节为单位遍历路径时,节点最多可指向 16 个子节点,不过还包含一个 `value` 元素。 因此,我们把它们表示为具有长度 17 的数组。 我们把这些有 17 个元素的数组称为“分支节点”。 +我们将基数树的原子单位(例如,单个十六进制字符或 4 位二进制数)称为“nibble”(半字节)。 如上所述,在一次遍历一个半字节的路径时,节点最多可以引用 16 个子节点,但包含一个 `value` 元素。 因此,我们把它们表示为具有长度 17 的数组。 我们把这些有 17 个元素的数组称为“分支节点”。 -## 默克尔帕特里夏树 {#merkle-patricia-trees} +## 默克尔-帕特里夏树 {#merkle-patricia-trees} -基数树有一个主要限制:效率低下。 如果你想将一个 `(path, value)` 对存储在路径长度为 64 个字符(`bytes32` 中的半字节数)的位置(如以太坊中),我们需要超过一千字节的额外空间将每个字符存储一个层级,并且每次查询或删除都需要执行完整的 64 个步骤。 下文介绍的帕特里夏字典树可以解决这个问题。 +基数树有一个主要限制:效率低下。 如果您想存储一个 `(path, value)` 绑定,其中路径(如在以太坊中)为 64 个字符长(`bytes32` 中的半字节数),我们将需要超过一千字节的额外空间来为每个字符存储一个层级,每次查找或删除都将需要完整的 64 步。 下文介绍的帕特里夏字典树可以解决这个问题。 ### 优化 {#optimization} 默克尔帕特里夏树的节点可以是以下任意一种: -1. `NULL`(表示为空字符串) -2. `branch`,一个 17 元素节点 ` [ v0 ... v15, vt ]` -3. `leaf`,一个双元素节点 `[ encodedPath, value ]` -4. `extension`,一个双元素节点 `[ encodedPath, key ]` +1. `NULL`(表示为空字符串) +2. `分支`:一个 17 项节点 `[ v0 ...` v15, vt ]` +3. `叶`:一个双元素节点 `[ encodedPath, value ]` +4. `扩展`:一个双元素节点 `[ encodedPath, key ]` -在 64 个字符的路径中,遍历前缀树的前几层后,一定会到达这样的节点:至少部分下游再无分支路径。 为了避免在路径中创建多达 15 个稀疏 `NULL` 节点,我们通过设置一个形式为 `[ encodedPath, key ]` 的 `extension` 节点来精简向下遍历,其中 `encodedPath` 包含要跳过的“部分路径”(使用下面描述的压缩编码),`key` 用于下一次数据库查询。 +在 64 个字符的路径中,遍历前缀树的前几层后,一定会到达这样的节点:至少部分下游再无分支路径。 为避免沿路径创建多达 15 个稀疏的 `NULL` 节点,我们通过设置一个 `[ encodedPath, key ]` 形式的 `extension` 节点来简化下降过程,其中 `encodedPath` 包含要跳过的“部分路径”(使用下面描述的紧凑编码),`key` 用于下一次数据库查找。 -对于 `leaf` 节点,可以使用 `encodedPath` 的第一个半字节中的标志来标记,其路径编码了所有先前节点的路径片段,并且我们可以直接查询 `value`。 +对于 `leaf` 节点,它可以通过 `encodedPath` 第一个半字节中的标志进行标记,该路径对所有先前节点的路径片段进行编码,我们可以直接查找 `value`。 然而,上述优化造成了模棱两可。 -当以半字节遍历路径时,最后我们可能需要遍历奇数个半字节,但是所有数据都需要以 `bytes` 格式存储。 两者之间是无法区分的,例如,半字节 `1` 和半字节 `01`(两者都必须存储为 `<01>`)。 要指定奇数个半字节的长度,这部分路径要使用标记位作为前缀。 +当以半字节为单位遍历路径时,我们最终可能要遍历奇数个半字节,但因为所有数据都以 `bytes` 格式存储。 例如,无法区分半字节 `1` 和半字节 `01`(两者都必须存储为 `<01>`)。 要指定奇数个半字节的长度,这部分路径要使用标记位作为前缀。 -### 规范:带有可选终止符的十六进制序列的压缩编码 {#specification} +### 规范:带可选终止符的十六进制序列的紧凑编码 {#specification} -如上文所述,_剩余部分路径长度为奇数 vs 偶数_和_叶节点 vs 扩展节点_的标记位位于任意双元素节点中部分路径的第一个半字节。 从而产生以下结果: +如上所述,标记_剩余部分路径长度为奇数还是偶数_以及_是叶节点还是扩展节点_,位于任何双元素节点的部分路径的第一个半字节中。 从而产生以下结果: - hex char bits | node type partial path length - ---------------------------------------------------------- - 0 0000 | extension even - 1 0001 | extension odd - 2 0010 | terminating (leaf) even - 3 0011 | terminating (leaf) odd +| 十六进制字符 | 比特 | 部分类型节点 | 路径长度 | +| ------ | ---- | -------- | ---- | +| 0 | 0000 | 扩展 | 偶数 | +| 1 | 0001 | 扩展 | 奇数 | +| 2 | 0010 | 终止(叶子节点) | 偶数 | +| 3 | 0011 | 终止(叶子节点) | 奇数 | -对于剩余路径长度为偶数的情况(`0` 或 `2`),一定会附加一个 `0`“占位”半字节。 +对于偶数长度的剩余路径(`0` 或 `2`),后面将始终跟着另一个 `0` “填充”半字节。 -``` +```python def compact_encode(hexarray): term = 1 if hexarray[-1] == 16 else 0 - if term: hexarray = hexarray[:-1] + if term: + hexarray = hexarray[:-1] oddlen = len(hexarray) % 2 flags = 2 * term + oddlen if oddlen: hexarray = [flags] + hexarray else: hexarray = [flags] + [0] + hexarray - // hexarray now has an even length whose first nibble is the flags. - o = '' - for i in range(0,len(hexarray),2): - o += chr(16 * hexarray[i] + hexarray[i+1]) + # hexarray 现在的长度为偶数,其第一个半字节为标志位。 + o = "" + for i in range(0, len(hexarray), 2): + o += chr(16 * hexarray[i] + hexarray[i + 1]) return o ``` -示例: +例子: -``` - > [ 1, 2, 3, 4, 5, ...] +```python + > [1, 2, 3, 4, 5, ...] '11 23 45' - > [ 0, 1, 2, 3, 4, 5, ...] + > [0, 1, 2, 3, 4, 5, ...] '00 01 23 45' - > [ 0, f, 1, c, b, 8, 10] + > [0, f, 1, c, b, 8, 10] '20 0f 1c b8' - > [ f, 1, c, b, 8, 10] + > [f, 1, c, b, 8, 10] '3f 1c b8' ``` 以下为获取默克尔帕特里夏树中节点的扩展代码: -``` - def get_helper(node_hash,path): - if path == []: return node_hash - if node_hash == '': return '' +```python + def get_helper(node_hash, path): + if path == []: + return node_hash + if node_hash == "": + return "" curnode = rlp.decode(node_hash if len(node_hash) < 32 else db.get(node_hash)) if len(curnode) == 2: (k2, v2) = curnode k2 = compact_decode(k2) - if k2 == path[:len(k2)]: - return get(v2, path[len(k2):]) + if k2 == path[: len(k2)]: + return get(v2, path[len(k2) :]) else: - return '' + return "" elif len(curnode) == 17: - return get_helper(curnode[path[0]],path[1:]) + return get_helper(curnode[path[0]], path[1:]) - def get(node_hash,path): + def get(node_hash, path): path2 = [] for i in range(len(path)): path2.push(int(ord(path[i]) / 16)) path2.push(ord(path[i]) % 16) path2.push(16) - return get_helper(node_hash,path2) + return get_helper(node_hash, path2) ``` -### 前缀树示例 {#example-trie} +### 示例树 {#example-trie} -假设我们想要一个包含四个路径/值对的树:`('do', 'verb')`、`('dog', 'puppy')`、`(' doge', 'coins')`、`('horse', 'stallion')`。 +假设我们想要一个包含四个路径/值对的字典树:`('do', 'verb')`、`('dog', 'puppy')`、`('doge', 'coins')`、`('horse', 'stallion')`。 -首先,我们将路径和值都转换为 `bytes`。 在下方代码中,_路径_的实际字节代表用 `<>` 表示。而_值_仍然显示为字符串,用 `''` 表示,以便于理解(值也应为 `bytes`): +首先,我们将路径和值都转换为 `bytes`。 下文中,_路径_的实际字节表示用 `<>` 表示,而_值_仍显示为字符串(用 `''` 表示),以便于理解(它们实际上也应该是 `bytes`): ``` <64 6f> : 'verb' @@ -183,38 +186,37 @@ sidebarDepth: 2 hashD: [ <17>, [ <>, <>, <>, <>, <>, <>, [ <35>, 'coins' ], <>, <>, <>, <>, <>, <>, <>, <>, <>, 'puppy' ] ] ``` -当一个节点在另一个节点内部被引用时,包含的内容是 `H(rlp.encode(node))`,其中 `H(x) = keccak256(x) if len(x) >= 32 else x` 和 `rlp.encode` 是[递归长度前缀](/developers/docs/data-structs-and-encoding/rlp)编码函数。 +当一个节点在另一个节点内被引用时,如果 `len(rlp.encode(node)) >= 32`,则包含的是 `keccak256(rlp.encode(node))`,否则是 `node` 本身,其中 `rlp.encode`是 [RLP](/developers/docs/data-structures-and-encoding/rlp) 编码函数。 -请注意,更新前缀树时,_如果_新创建节点的长度 >= 32,则需要将键/值对 `(keccak256(x), x)` 存储在一个持久的查询表中。 然而,如果节点比这短,则不需要存储任何数据,因为函数 f(x) = x 是可逆的。 +请注意,更新字典树时,如果新创建的节点长度 >= 32,则需要将键/值对 `(keccak256(x), x)` 存储在持久化查找表中。 然而,如果节点比这短,则不需要存储任何数据,因为函数 f(x) = x 是可逆的。 -## 以太坊中的前缀树 {#tries-in-ethereum} +## 以太坊中的树 {#tries-in-ethereum} 以太坊执行层中的所有默克尔树均使用默克尔帕特里夏树。 在区块头,有来自 3 棵前缀树的 3 个根。 -1. stateRoot -2. transactionsRoot -3. receiptsRoot +1. stateRoot +2. transactionsRoot +3. receiptsRoot ### 状态树 {#state-trie} -有一个全局状态字典树,每次客户端处理一个区块时它都会更新。 其中,`path` 始终为:`keccak256(ethereumAddress)`,`value` 始终为:`rlp(ethereumAccount)`。 更具体地说,一个以太坊 `account` 是包含 4 个元素的数组:`[nonce,balance,storageRoot,codeHash]`。 关于这一点值得注意的是,`storageRoot` 是另一个帕特里夏字典树的根: +有一个全局状态字典树,每次客户端处理一个区块时它都会更新。 其中,`path` 始终为:`keccak256(ethereumAddress)`,`value` 始终为:`rlp(ethereumAccount)`。 更具体地说,一个以太坊 `account` 是一个包含 4 个元素的数组:`[nonce,balance,storageRoot,codeHash]`。 值得注意的是,此 `storageRoot` 是另一个帕特里夏树的根: ### 存储树 {#storage-trie} -存储树是_所有_合同数据存放之处。 每个帐户都有一棵单独的存储树。 要用给定地址在特定的存储位置检索值,需要存储地址、存储器中存储数据的整数位置,以及区块 ID。 之后,这些数据可以作为参数传入 JSON-RPC 应用程序接口中定义的 `eth_getStorageAt`,例如用于检索地址 `0x295a70b2de5e3953354a6a8344e616ed314d7251` 的存储插槽 0 中的数据: +存储树是存放_所有_合约数据的地方。 每个帐户都有一棵单独的存储树。 要用给定地址在特定的存储位置检索值,需要存储地址、存储器中存储数据的整数位置,以及区块 ID。 然后,这些可以作为参数传递给 JSON-RPC API 中定义的 `eth_getStorageAt`,例如,检索地址 `0x295a70b2de5e3953354a6a8344e616ed314d7251` 的存储槽 0 中的数据: -``` +```bash curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x0", "latest"], "id": 1}' localhost:8545 {"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000004d2"} - ``` -更多的是检索存储器中的其他元素,因为必须首先计算存储树中的位置。 该位置作为地址和存储位置的 `keccak256` 哈希值进行计算,两者都从左侧开始用零填充 32 个字节的长度。 例如,地址 `0x391694e7e0b0cce554cb130d723a9d27458f9298` 的数据在存储时隙 1 中的位置是: +更多的是检索存储器中的其他元素,因为必须首先计算存储树中的位置。 该位置计算为地址和存储位置的 `keccak256` 哈希,两者都向左填充零至 32 字节长度。 例如,地址 `0x391694e7e0b0cce554cb130d723a9d27458f9298` 的存储槽 1 中数据的位置是: -``` +```python keccak256(decodeHex("000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + "0000000000000000000000000000000000000000000000000000000000000001")) ``` @@ -227,37 +229,37 @@ undefined "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9" ``` -因此,`path` 是 `keccak256(<6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9>)`。 与以前相同,此地址现在可用于从存储树检索数据: +因此,`path` 为 `keccak256(<6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9>)`。 与以前相同,此地址现在可用于从存储树检索数据: -``` +```bash curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9", "latest"], "id": 1}' localhost:8545 {"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000000162e"} ``` -注意:如果不是合约帐户,以太坊帐户的 `storageRoot` 默认为空。 +注意:如果以太坊帐户不是合约帐户,其 `storageRoot` 默认是空的。 ### 交易树 {#transaction-trie} -每个区块都有一个独立的交易字典树,也用于存储 `(key, value)` 对。 路径为:`rlp(transactionIndex)`,代表了对应一个值的键,值由以下决定: +每个区块都有一棵单独的交易树,同样存储 `(key, value)` 对。 这里的路径是:`rlp(transactionIndex)`,它表示与以下确定的值相对应的键: -``` +```python if legacyTx: value = rlp(tx) else: value = TxType | encode(tx) ``` -关于这个问题的更多信息可以在 [EIP 2718](https://eips.ethereum.org/EIPS/eip-2718) 文档中找到。 +更多相关信息请参阅 [EIP 2718](https://eips.ethereum.org/EIPS/eip-2718) 文档。 ### 收据树 {#receipts-trie} -每个区块都有自己的收据树。 此处的 `path` 是:`rlp(transactionIndex)`。 `transactionIndex` 是它所在区块中的索引。 收据字典树从不更新。 与交易字典树类似,它也有当前和以前的收据。 为了在收据字典树中查询特定的收据,需要提供区块中交易的索引、收据有效载荷以及交易类型。 返回的收据可以是 `Receipt` 类型,定义为 `TransactionType` 和 `ReceiptPayload` 的串联;也可以是 `LegacyReceipt` 类型,定义为`rlp([status, cumulativeGasUsed, logsBloom, logs])`。 +每个区块都有自己的收据树。 此处的 `path` 是:`rlp(transactionIndex)`。 `transactionIndex` 是它所在区块中的索引。 收据字典树从不更新。 与交易字典树类似,它也有当前和以前的收据。 为了在收据字典树中查询特定的收据,需要提供区块中交易的索引、收据有效载荷以及交易类型。 返回的收据可以是 `Receipt` 类型(定义为 `TransactionType` 和 `ReceiptPayload` 的串联),也可以是 `LegacyReceipt` 类型(定义为 `rlp([status, cumulativeGasUsed, logsBloom, logs])`)。 -关于这个问题的更多信息可以在 [EIP 2718](https://eips.ethereum.org/EIPS/eip-2718) 文档中找到。 +更多相关信息请参阅 [EIP 2718](https://eips.ethereum.org/EIPS/eip-2718) 文档。 -## 延伸阅读 {#further-reading} +## 扩展阅读 {#further-reading} -- [修改后的默克尔帕特里夏字典树 — 如何保存以太坊状态](https://medium.com/codechain/modified-merkle-patricia-trie-how-ethereum-saves-a-state-e6d7555078dd) -- [以太坊中的默克尔树](https://blog.ethereum.org/2015/11/15/merkling-in-ethereum/) -- [了解以太坊的字典树](https://easythereentropy.wordpress.com/2014/06/04/understanding-the-ethereum-trie/) +- [修改后的默克尔-帕特里夏树 — 以太坊如何保存状态](https://medium.com/codechain/modified-merkle-patricia-trie-how-ethereum-saves-a-state-e6d7555078dd) +- [以太坊中的默克尔化](https://blog.ethereum.org/2015/11/15/merkling-in-ethereum/) +- [理解以太坊树](https://easythereentropy.wordpress.com/2014/06/04/understanding-the-ethereum-trie/) diff --git a/public/content/translations/zh/developers/docs/data-structures-and-encoding/rlp/index.md b/public/content/translations/zh/developers/docs/data-structures-and-encoding/rlp/index.md index 2176f41308c..d8251558fca 100644 --- a/public/content/translations/zh/developers/docs/data-structures-and-encoding/rlp/index.md +++ b/public/content/translations/zh/developers/docs/data-structures-and-encoding/rlp/index.md @@ -1,24 +1,24 @@ --- -title: 递归长度前缀 (RLP) 序列化 -description: 以太坊执行层中递归长度前缀 (RLP) 编码的定义。 +title: "递归长度前缀 (RLP) 序列化" +description: "以太坊执行层中递归长度前缀 (RLP) 编码的定义。" lang: zh sidebarDepth: 2 --- -递归长度前缀 (RLP) 序列化广泛用于以太坊的执行客户端。 数据在节点之间以节省空间的格式传输,而递归长度前缀可使这一过程标准化。 递归长度前缀的目的在于,对任意嵌套的二进制数据数组进行编码,而递归长度前缀是用于序列化以太坊执行层中对象的主要编码方法。 递归长度前缀的主要目的是对结构进行编码;除正整数外,递归长度前缀将特定数据类型(例如字符串、浮点数)的编码委托给更高阶协议。 正整数必须以不带前导零的大端二进制形式表示(从而使整数值零相当于空字节数组)。 任何使用递归长度前缀的高阶协议都必须将带前导零的反序列化正整数视为无效。 +递归长度前缀 (RLP) 序列化广泛用于以太坊的执行客户端。 数据在节点之间以节省空间的格式传输,而递归长度前缀可使这一过程标准化。 递归长度前缀的目的在于,对任意嵌套的二进制数据数组进行编码,而递归长度前缀是用于序列化以太坊执行层中对象的主要编码方法。 RLP 的主要目的是对结构进行编码;除了正整数,RLP 将特定数据类型(例如,字符串、浮点数)的编码委托给高阶协议。 正整数必须以不带前导零的大端二进制形式表示(从而使整数值零相当于空字节数组)。 任何使用递归长度前缀的高阶协议都必须将带前导零的反序列化正整数视为无效。 -更多信息请见[以太坊黄皮书(附录 B)](https://ethereum.github.io/yellowpaper/paper.pdf#page=19)。 +更多信息请参阅[《以太坊黄皮书》(附录 B)](https://ethereum.github.io/yellowpaper/paper.pdf#page=19)。 要使用递归长度前缀对字典进行编码,建议的两种规范形式为: -- 使用 `[[k1,v1],[k2,v2]...]` 加上按字典顺序排列的键 +- 使用 `[[k1,v1],[k2,v2]...]`,其中的密钥按字典顺序排列 - 像以太坊一样使用更高级别的前缀树编码 ## 定义 {#definition} 递归长度前缀编码函数接受一个项目。 该项目的定义如下: -- 一个字符串(即字节数组)是一个项目 +- 一个字符串(即字节数组)是一个项 - 项目列表也是一个项目 - 正整数是一个项目 @@ -35,12 +35,12 @@ sidebarDepth: 2 递归长度前缀编码的定义如下: - 对于正整数,将其转换为最短字节数组,其大端解释为整数,然后根据以下规则编码为字符串。 -- 对于值在 `[0x00, 0x7f]`(十进制 `[0, 127]`)范围内的单个字节,该字节即是它自己的递归长度前缀编码。 -- 否则,如果字符串的长度为 0-55 个字节,则递归长度前缀编码包含一个值为 **0x80**(十进制 128)的单字节,加上该字符串之后字符串的长度。 因此,第一个字节的范围是 `[0x80, 0xb7]`(十进制 `[128, 183]`)。 -- 如果字符串的长度超过 55 个字节,则递归长度前缀编码由一个值为 **0xb7**(十进制为 183)的单个字节,加上二进制字符串长度的以字节为单位的长度,后跟字符串的长度,然后是字符串。 例如,一个长 1024 字节的字符串将被编码为 `\xb9\x04\x00`(十进制 `185, 4, 0`)后跟该字符串。 在这里,`0xb9` (183 + 2 = 185) 为第一个字节,然后是表示实际字符串长度的 2 个字节 `0x0400`(十进制 1024)。 因此,第一个字节的范围是 `[0xb8, 0xbf]`(十进制 `[184, 191]`)。 +- 对于值在 `[0x00, 0x7f]`(十进制 `[0, 127]`)范围内的单个字节,该字节即是它自己的 RLP 编码。 +- 否则,如果字符串的长度为 0-55 字节,RLP 编码将由一个值为 **0x80**(十进制 128)的单字节加上字符串的长度,后跟该字符串本身构成。 因此,第一个字节的范围是 `[0x80, 0xb7]`(十进制 `[128, 183]`)。 +- 如果字符串长度超过 55 字节,RLP 编码由一个值为 **0xb7**(十进制 183)的单字节,加上字符串长度的二进制形式的字节长度,后跟字符串长度,再后跟字符串本身构成。 例如,一个长 1024 字节的字符串将被编码为 `\xb9\x04\x00`(十进制 `185, 4, 0`)后跟该字符串。 在这里,`0xb9` (183 + 2 = 185) 为第一个字节,然后是表示实际字符串长度的 2 个字节 `0x0400`(十进制 1024)。 因此,第一个字节的范围是 `[0xb8, 0xbf]`(十进制 `[184, 191]`)。 - 如果字符串的长度为 2^64 字节或更长,则可能不会对其进行编码。 -- 如果列表的总有效载荷长度(即其所有经过递归长度前缀编码的项目的组合长度)为 0-55 个字节,则递归长度前缀编码包含一个值为 **0xc0** 的单字节,加上有效载荷长度,后跟一串项目的递归长度前缀编码。 因此,第一个字节的范围是 `[0xc0, 0xf7]`(十进制 `[192, 247]`)。 -- 如果列表的总有效载荷长度超过 55 个字节,则递归长度前缀编码包含一个值为 **0xf7** 的单字节,加上二进制格式的有效载荷长度的以字节为单位的长度,后跟有效载荷的长度,然后是项目递归长度前缀编码串。 因此,第一个字节的范围是 `[0xf8, 0xff]`(十进制 `[248, 255]`)。 +- 如果列表的总有效负载(即其所有 RLP 编码项的组合长度)为 0-55 字节长,则 RLP 编码由一个值为 **0xc0** 的单字节,加上有效负载的长度,后跟各项 RLP 编码的串联组成。 因此,第一个字节的范围是 `[0xc0, 0xf7]`(十进制 `[192, 247]`)。 +- 如果列表的总有效负载超过 55 字节,RLP 编码由一个值为 **0xf7** 的单字节,加上有效负载长度的二进制形式的字节长度,后跟有效负载长度,再后跟各项 RLP 编码的串联构成。 因此,第一个字节的范围是 `[0xf8, 0xff]`(十进制 `[248, 255]`)。 对应的代码为: @@ -62,7 +62,7 @@ def encode_length(L, offset): elif L < 256**8: BL = to_binary(L) return chr(len(BL) + offset + 55) + BL - raise Exception("input too long") + raise Exception("input too long") def to_binary(x): if x == 0: @@ -80,30 +80,30 @@ def to_binary(x): - 字节 '\\x00' = `[ 0x00 ]` - 字节 '\\x0f' = `[ 0x0f ]` - 字节 '\\x04\\x00' = `[ 0x82, 0x04, 0x00 ]` -- 3 的[集合论表示](http://en.wikipedia.org/wiki/Set-theoretic_definition_of_natural_numbers),`[ [], [[]], [ [], [[]] ] ] = [ 0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0 ]` -- 字符串“Lorem ipsum dolor sit amet, consectetur adipisicing elit”= `[ 0xb8, 0x38, 'L', 'o', 'r', 'e', 'm', ' ', ... , 'e', 'l', 'i', 't' ]` +- 三的[集合论表示法](http://en.wikipedia.org/wiki/Set-theoretic_definition_of_natural_numbers),`[ [], [[]], [ [], [[]] ] ] = [ 0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0 ]` +- 字符串 "Lorem ipsum dolor sit amet, consectetur adipisicing elit" = `[ 0xb8, 0x38, 'L', 'o', 'r', 'e', 'm', ' ', ... , 'e', 'l', 'i', 't' ]` -## 递归长度前缀解码 {#rlp-decoding} +## RLP 解码 {#rlp-decoding} 根据递归长度前缀编码的规则和过程,递归长度前缀译码的输入被视为一个二进制数据数组。 递归长度前缀解码过程如下: -1. 根据输入数据的第一个字节(即前缀),解码数据类型、实际数据的长度和偏移量; +1. 根据输入数据的第一个字节(即前缀),解码数据类型、实际数据的长度和偏移量; -2. 根据数据的类型和偏移量,遵循正整数的最小编码规则,对数据进行相应的解码; +2. 根据数据的类型和偏移量,遵循正整数的最小编码规则,对数据进行相应的解码; -3. 继续解码输入的其余部分; +3. 继续解码输入的其余部分; 其中,解码数据类型和偏移量的规则如下: -1. 如果第一个字节(即前缀)的范围是 [0x00, 0x7f],则数据为字符串,并且字符串本身就是第一个字节; +1. 如果第一个字节(即前缀)的范围是 `[0x00, 0x7f]`,则数据为字符串,且该字符串就是第一个字节本身; -2. 如果第一个字节的范围是 [0x80, 0xb7],则数据为字符串,并且第一个字节后跟长度等于第一个字节减去 0x80 的字符串; +2. 如果第一个字节的范围是 [0x80, 0xb7],则数据为字符串,并且第一个字节后跟长度等于第一个字节减去 0x80 的字符串; -3. 如果第一个字节的范围是 [0xb8, 0xbf],则数据为字符串,第一个字节后跟长度等于第一字节减去 0xb7 的字符串长度,而字符串则跟在字符串长度后面 +3. 如果第一个字节的范围是 [0xb8, 0xbf],则数据为字符串,第一个字节后跟长度等于第一字节减去 0xb7 的字符串长度,而字符串则跟在字符串长度后面 -4. 如果第一个字节的范围是 [0xc0, 0xf7],则数据为列表,第一字节后跟列表中所有项目的递归长度前缀编码串,而列表的总有效载荷等于第一字节减去 0xc0。 +4. 如果第一个字节的范围是 [0xc0, 0xf7],则数据为列表,第一字节后跟列表中所有项目的递归长度前缀编码串,而列表的总有效载荷等于第一字节减去 0xc0。 -5. 如果第一个字节的范围是 [0xf8, 0xff],则数据为列表,第一个字节后跟长度等于第一字节减去 0xf7 的总有效载荷,而列表所有项目的递归长度前缀编码串则跟在列表的总有效载荷之后; +5. 如果第一个字节的范围是 [0xf8, 0xff],则数据为列表,第一个字节后跟长度等于第一字节减去 0xf7 的总有效载荷,而列表所有项目的递归长度前缀编码串则跟在列表的总有效载荷之后; 对应的代码为: @@ -152,12 +152,12 @@ def to_integer(b): return ord(substr(b, -1)) + to_integer(substr(b, 0, -1)) * 256 ``` -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [以太坊中的递归长度前缀](https://medium.com/coinmonks/data-structure-in-ethereum-episode-1-recursive-length-prefix-rlp-encoding-decoding-d1016832f919) -- [底层以太坊:递归长度前缀](https://medium.com/coinmonks/ethereum-under-the-hood-part-3-rlp-decoding-df236dc13e58) -- [Coglio, A. (2020)。 以太坊 ACL2 中的递归长度前缀。 arXiv 预印本 arXiv:2009.13769。](https://arxiv.org/abs/2009.13769) +- [以太坊中的 RLP](https://medium.com/coinmonks/data-structure-in-ethereum-episode-1-recursive-length-prefix-rlp-encoding-decoding-d1016832f919) +- [以太坊底层机制:RLP](https://medium.com/coinmonks/ethereum-under-the-hood-part-3-rlp-decoding-df236dc13e58) +- Coglio, A. (2020)。 以太坊 ACL2 中的递归长度前缀。 arXiv preprint arXiv:2009.13769.](https://arxiv.org/abs/2009.13769) -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} -- [默克尔前缀树](/developers/docs/data-structures-and-encoding/patricia-merkle-trie) +- [帕特里夏-默克尔树](/developers/docs/data-structures-and-encoding/patricia-merkle-trie) diff --git a/public/content/translations/zh/developers/docs/data-structures-and-encoding/ssz/index.md b/public/content/translations/zh/developers/docs/data-structures-and-encoding/ssz/index.md index 2dbabd0578f..b488d3f8d3f 100644 --- a/public/content/translations/zh/developers/docs/data-structures-and-encoding/ssz/index.md +++ b/public/content/translations/zh/developers/docs/data-structures-and-encoding/ssz/index.md @@ -1,11 +1,11 @@ --- -title: 简单序列化 -description: 以太坊简单序列化 (SSZ) 格式的说明。 +title: "简单序列化" +description: "以太坊简单序列化 (SSZ) 格式的说明。" lang: zh sidebarDepth: 2 --- -**简单序列化 (SSZ)** 是信标链上使用的序列化方法。 这种方法取代了除对等点发现协议以外的共识层各处执行层上所用的递归长度前缀序列化。 简单序列化设计具有确定性,也可以有效地进行默克尔化。 可以认为,简单序列化有两个组成部分:序列化方案和默克尔化方案,后者设计用于有效地处理序列化数据结构。 +**简单序列化 (SSZ)** 是信标链上使用的序列化方法。 这种方法取代了除对等点发现协议以外的共识层各处执行层上所用的递归长度前缀序列化。 要详细了解 RLP 序列化,请参阅[递归长度前缀 (RLP)](/developers/docs/data-structures-and-encoding/rlp/)。 简单序列化设计具有确定性,也可以有效地进行默克尔化。 可以认为,简单序列化有两个组成部分:序列化方案和默克尔化方案,后者设计用于有效地处理序列化数据结构。 ## 简单序列化的工作原理 {#how-does-ssz-work} @@ -16,7 +16,7 @@ sidebarDepth: 2 - 无符号整数 - 布尔值 -对于复杂的“复合”类型,序列化更加复杂,因为复合类型包含多个可能具有不同类型或不同大小或两者兼有的元素。 在这些对象都具有固定长度的情况下(即元素的大小将始终保持不变,而与它们的实际值无关),序列化只是将复合类型中的每个元素转换为小端字节串。 这些字节串会连接在一起。 序列化对象用字节列表表示,列表中的元素具有固定长度,它们的排列顺序与在反序列化对象中的顺序相同。 +对于复杂的“复合”类型,序列化更加复杂,因为复合类型包含多个可能具有不同类型或不同大小或两者兼有的元素。 如果这些对象都具有固定长度(即,无论元素的实际值如何,其大小始终是恒定的),序列化就只是按顺序将复合类型中的每个元素转换为小端字节串。 这些字节串会连接在一起。 序列化对象用字节列表表示,列表中的元素具有固定长度,它们的排列顺序与在反序列化对象中的顺序相同。 对于具有可变长度的类型,实际数据将被序列化对象中该元素位置的“偏移”值替换。 实际数据会添加到序列化对象末尾的堆中。 偏移值是堆中实际数据开始的索引,充当指向相关字节的指针。 @@ -50,8 +50,7 @@ sidebarDepth: 2 [37, 0, 0, 0, 55, 0, 0, 0, 16, 0, 0, 0, 22, 0, 0, 0, 1, 2, 3, 4] ------------ ----------- ----------- ----------- ---------- | | | | | - number1 number2 offset for number 3 value for - vector vector + number1 number2 vector 的偏移量 number 3 vector 的值 ``` @@ -59,11 +58,11 @@ sidebarDepth: 2 ``` [ - 37, 0, 0, 0, # little-endian encoding of `number1`. - 55, 0, 0, 0, # little-endian encoding of `number2`. - 16, 0, 0, 0, # The "offset" that indicates where the value of `vector` starts (little-endian 16). - 22, 0, 0, 0, # little-endian encoding of `number3`. - 1, 2, 3, 4, # The actual values in `vector`. + 37, 0, 0, 0, # `number1` 的小端编码。 + 55, 0, 0, 0, # `number2` 的小端编码。 + 16, 0, 0, 0, # 指示 `vector` 值起始位置的“偏移量”(小端 16)。 + 22, 0, 0, 0, # `number3` 的小端编码。 + 1, 2, 3, 4, # `vector` 中的实际值。 ] ``` @@ -71,23 +70,23 @@ sidebarDepth: 2 ``` [ - 10100101000000000000000000000000 # little-endian encoding of `number1` - 10110111000000000000000000000000 # little-endian encoding of `number2`. - 10010000000000000000000000000000 # The "offset" that indicates where the value of `vector` starts (little-endian 16). - 10010110000000000000000000000000 # little-endian encoding of `number3`. - 10000001100000101000001110000100 # The actual value of the `bytes` field. + 10100101000000000000000000000000 # `number1` 的小端编码 + 10110111000000000000000000000000 # `number2` 的小端编码。 + 10010000000000000000000000000000 # 指示 `vector` 值起始位置的“偏移量”(小端 16)。 + 10010110000000000000000000000000 # `number3` 的小端编码。 + 10000001100000101000001110000100 # `bytes` 字段的实际值。 ] ``` 因此,可变长度类型的实际值存储在序列化对象末尾的堆中,它们的偏移量则存储在有序字段列表中的正确位置。 -还有一些特殊情况需要特殊处理,比如 `BitList` 类型需要在序列化过程中添加长度上限,并在反序列化过程中移除该上限。 [简单序列化规范](https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md)中提供了完整的详细信息。 +还有一些特殊情况需要特殊处理,比如 `BitList` 类型,它需要在序列化过程中添加长度上限,并在反序列化过程中移除该上限。 完整详情请参阅 [SSZ 规范](https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md)。 ### 反序列化 {#deserialization} 反序列化此对象需要一个方案。 方案需定义序列化数据的精确布局,以便每个特定元素都可以从一组字节反序列化为一些有意义的对象,其中元素具有正确的类型、值、大小和位置。 正是方案告诉反序列化程序哪些值是实际值,哪些是偏移值。 当对象被序列化时,所有字段名称都会消失,但会根据方案在反序列化时重新实例化。 -请参阅 [ssz.dev](https://www.ssz.dev/overview) 了解有关此主题的交互式说明。 +请参阅 [ssz.dev](https://www.ssz.dev/overview),获取关于此内容的交互式解说。 ## 默克尔化 {#merkleization} @@ -109,26 +108,27 @@ sidebarDepth: 2 在某些情况下,树的叶子不会像上面示例中那样自然均匀地分布。 例如,叶子 4 可能是一个包含多个元素的容器,需要向默克尔树添加额外的“深度”,从而形成不均匀的树。 -与其将这些树元素称为叶子 X、节点 X 等,我们可以给它们赋予广义索引,从根 = 1 开始,沿着每个级别从左到右计数。 这即是前述广义索引。 序列化列表中的每个元素都有一个等于 `2**depth + idx` 的广义索引,其中 idx 是其在序列化对象中的零索引位置,depth 是默克尔树中的层数,可以计算为元素(叶子)数量的二进制对数。 +与其将这些树元素称为叶子 X、节点 X 等,我们可以给它们赋予广义索引,从根 = 1 开始,沿着每个级别从左到右计数。 这即是前述广义索引。 序列化列表中的每个元素都有一个广义索引,其值等于 `2**depth + idx`,其中 idx 是其在序列化对象中的从零开始的索引位置,depth 是默克尔树中的层数,可通过元素(叶)数量的以 2 为底的对数来确定。 ## 广义索引 {#generalized-indices} -广义索引是一个整数,表示二元默克尔树中的一个节点,其中每个节点都有一个广义索引 `2 ** depth + index in row`。 +广义索引是一个整数,表示二叉默克尔树中的一个节点,其中每个节点都有一个广义索引 `2 ** depth + index in row`。 ``` - 1 --depth = 0 2**0 + 0 = 1 - 2 3 --depth = 1 2**1 + 0 = 2, 2**1+1 = 3 - 4 5 6 7 --depth = 2 2**2 + 0 = 4, 2**2 + 1 = 5... + 1 --深度 = 0 2**0 + 0 = 1 + 2 3 --深度 = 1 2**1 + 0 = 2, 2**1+1 = 3 + 4 5 6 7 --深度 = 2 2**2 + 0 = 4, 2**2 + 1 = 5... ``` 这种表示为默克尔树中的每条数据生成一个节点索引。 -## 多值证明 {#multiproofs} +## 多重证明 {#multiproofs} -提供表示特定元素的广义索引列表使我们可以对照哈希树根来对其进行验证。 这个根是我们接受的现实版本, 我们提供的任何数据都可以对照现实进行验证,方法是将其插入默克尔树中的正确位置(由其广义索引确定),然后观察根是否保持不变。 请参阅[此处](https://github.com/ethereum/consensus-specs/blob/dev/ssz/merkle-proofs.md#merkle-multiproofs)的规范,其中一些函数展示了如何计算验证一组特定广义索引的内容所需的最小节点集。 +提供表示特定元素的广义索引列表使我们可以对照哈希树根来对其进行验证。 这个根是我们接受的现实版本, 我们提供的任何数据都可以对照现实进行验证,方法是将其插入默克尔树中的正确位置(由其广义索引确定),然后观察根是否保持不变。 [此处的规范](https://github.com/ethereum/consensus-specs/blob/dev/ssz/merkle-proofs.md#merkle-multiproofs)中提供了一些函数,展示了如何计算验证特定广义索引集的内容所需的最小节点集。 -例如,要验证下面树中索引 9 中的数据,我们需要索引 8、9、5、3、1 处数据的哈希值。 (8,9) 的哈希值应该等于哈希值 (4),它与 5 进行哈希计算可生成 2,与 3 进行哈希计算可生成树根 1。 如果为 9 提供了不正确的数据,根会发生改变,我们会检测到这一问题,从而无法验证分支。 +例如,要验证下面树中索引 9 中的数据,我们需要索引 8、9、5、3、1 处数据的哈希值。 +(8,9) 的哈希值应该等于哈希值 (4),它与 5 进行哈希计算可生成 2,与 3 进行哈希计算可生成树根 1。 如果为 9 提供了不正确的数据,根会发生改变,我们会检测到这一问题,从而无法验证分支。 ``` * = 生成证明所需的数据 @@ -140,10 +140,10 @@ sidebarDepth: 2 ``` -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [升级以太坊:简单序列化](https://eth2book.info/altair/part2/building_blocks/ssz) +- [升级以太坊:SSZ](https://eth2book.info/altair/part2/building_blocks/ssz) - [升级以太坊:默克尔化](https://eth2book.info/altair/part2/building_blocks/merkleization) -- [简单序列化实现](https://github.com/ethereum/consensus-specs/issues/2138) -- [简单序列化计算器](https://simpleserialize.com/) +- [SSZ 实现](https://github.com/ethereum/consensus-specs/issues/2138) +- [SSZ 计算器](https://simpleserialize.com/) - [SSZ.dev](https://www.ssz.dev/) diff --git a/public/content/translations/zh/developers/docs/data-structures-and-encoding/web3-secret-storage/index.md b/public/content/translations/zh/developers/docs/data-structures-and-encoding/web3-secret-storage/index.md new file mode 100644 index 00000000000..e849d065369 --- /dev/null +++ b/public/content/translations/zh/developers/docs/data-structures-and-encoding/web3-secret-storage/index.md @@ -0,0 +1,195 @@ +--- +title: "Web3 密钥存储定义" +description: "Web3 密钥存储的正式定义" +lang: zh +sidebarDepth: 2 +--- + +为了让应用程序在以太坊上运行,你可以使用 web3.js 程序库提供的 web3 对象。 它在底层通过远程过程调用与本地节点通信。 [web3](https://github.com/ethereum/web3.js/) 可以与任何公开远程过程调用 (RPC) 层的以太坊节点协同工作。 + +`web3` 包含 `eth` 对象 - web3.eth。 + +```js +var fs = require("fs") +var recognizer = require("ethereum-keyfile-recognizer") + +fs.readFile("keyfile.json", (err, data) => { + var json = JSON.parse(data) + var result = recognizer(json) +}) + +/** result + * [ 'web3', 3 ] web3 (v3) 密钥文件 + * [ 'ethersale', undefined ] Ethersale 密钥文件 + * null 无效密钥文件 + */ +``` + +本文介绍 Web3 密钥存储定义的**第 3 版**。 + +## 定义 {#definition} + +文件的实际编码和解码与第 1 版相比基本没有变化,只是加密算法不再固定为 AES-128-CBC(AES-128-CTR 目前是最低要求)。 大部分含义/算法与版本 1 相似,但 `mac` 除外,它是派生密钥的次左边 16 个字节与完整的 `ciphertext` 拼接后内容的 SHA3 (keccak-256) 哈希值。 + +密钥文件直接存储在 `~/.web3/keystore`(类 Unix 系统)和 `~/AppData/Web3/keystore`(Windows 系统)中。 它们可以任意命名,但一个好的约定是 `.json`,其中 `` 是分配给密钥的 128 位 UUID(密钥地址的隐私保护代理)。 + +所有这些文件都有一个关联的密码。 要派生给定 `.json` 文件的密钥,首先派生该文件的加密密钥;此操作通过获取该文件的密码,并将其传递到由 `kdf` 键描述的密钥派生函数来完成。 KDF 函数中依赖于 KDF 的静态和动态参数在 `kdfparams` 键中描述。 + +PBKDF2 必须得到所有符合最低标准的实现的支持,表示为: + +- `kdf`:`pbkdf2` + +对于 PBKDF2,kdfparams 包括: + +- `prf`:必须是 `hmac-sha256`(将来可能会扩展); +- `c`:迭代次数; +- `salt`:传递给 PBKDF 的盐; +- `dklen`:派生密钥的长度。 必须 >= 32。 + +派生出文件的密钥后,应该通过派生 MAC 来验证它。 MAC 的计算方法是:将派生密钥的次左边 16 个字节与 `ciphertext` 键的内容拼接,形成一个字节数组,然后计算该数组的 SHA3 (keccak-256) 哈希值,即: + +```js +KECCAK(DK[16..31] ++ ) +``` + +(其中 `++` 是拼接运算符) + +应将此值与 `mac` 键的内容进行比较;如果二者不同,则应请求输入其他密码(或取消操作)。 + +文件密钥验证通过后,即可使用由 `cipher` 键指定、并由 `cipherparams` 键参数化的对称加密算法,来解密密文(即文件中 `ciphertext` 键的值)。 如果派生密钥的大小和算法密钥的大小不匹配,则用零来填充。派生密钥的最右边字节应该作为算法的密钥。 + +所有符合最低标准的实现必须支持 AES-128-CTR 算法,表示为: + +- `cipher: aes-128-ctr` + +该密码需要以下参数,作为 cipherparams 密钥的密钥: + +- `iv`:加密算法的 128 位初始化向量。 + +加密算法的密钥是派生密钥最左边的 16 字节,即 `DK[0..15]`。 + +密钥的创建/加密本质上应是这些指令的逆向操作。 确保 `uuid`、`salt` 和 `iv` 确实是随机的。 + +除了作为版本“硬”标识符的 `version` 字段外,实现方也可以使用 `minorversion` 来跟踪对格式的较小的、非破坏性的更改。 + +## 测试向量 {#test-vectors} + +详细信息: + +- `地址`:`008aeeda4d805471df9b2a5b0f38a0c3bcba786b` +- `ICAP`:`XE542A5PZHH8PYIZUBEJEO0MFWRAPPIL67` +- `UUID`:`3198bc9c-6672-5ab3-d9954942343ae5b6` +- `密码`:`testpassword` +- `机密`:`7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d` + +### PBKDF2-SHA-256 {#PBKDF2-SHA-256} + +使用 `AES-128-CTR` 和 `PBKDF2-SHA-256` 的测试向量: + +`~/.web3/keystore/3198bc9c-6672-5ab3-d9954942343ae5b6.json` 的文件内容: + +```json +{ + "crypto": { + "cipher": "aes-128-ctr", + "cipherparams": { + "iv": "6087dab2f9fdbbfaddc31a909735c1e6" + }, + "ciphertext": "5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46", + "kdf": "pbkdf2", + "kdfparams": { + "c": 262144, + "dklen": 32, + "prf": "hmac-sha256", + "salt": "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd" + }, + "mac": "517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2" + }, + "id": "3198bc9c-6672-5ab3-d995-4942343ae5b6", + "version": 3 +} +``` + +**中间值**: + +`派生密钥`:`f06d69cdc7da0faffb1008270bca38f5e31891a3a773950e6d0fea48a7188551` +`MAC 正文`:`e31891a3a773950e6d0fea48a71885515318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46` +`MAC`:`517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2` +`加密密钥`:`f06d69cdc7da0faffb1008270bca38f5` + +### Scrypt {#scrypt} + +使用 AES-128-CTR 和 Scrypt 的测试向量: + +```json +{ + "crypto": { + "cipher": "aes-128-ctr", + "cipherparams": { + "iv": "740770fce12ce862af21264dab25f1da" + }, + "ciphertext": "dd8a1132cf57db67c038c6763afe2cbe6ea1949a86abc5843f8ca656ebbb1ea2", + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "n": 262144, + "p": 1, + "r": 8, + "salt": "25710c2ccd7c610b24d068af83b959b7a0e5f40641f0c82daeb1345766191034" + }, + "mac": "337aeb86505d2d0bb620effe57f18381377d67d76dac1090626aa5cd20886a7c" + }, + "id": "3198bc9c-6672-5ab3-d995-4942343ae5b6", + "version": 3 +} +``` + +**中间值**: + +`派生密钥`:`7446f59ecc301d2d79bc3302650d8a5cedc185ccbb4bf3ca1ebd2c163eaa6c2d` +`MAC 正文`:`edc185ccbb4bf3ca1ebd2c163eaa6c2ddd8a1132cf57db67c038c6763afe2cbe6ea1949a86abc5843f8ca656ebbb1ea2` +`MAC`:`337aeb86505d2d0bb620effe57f18381377d67d76dac1090626aa5cd20886a7c` +`加密密钥`:`7446f59ecc301d2d79bc3302650d8a5c` + +## 与版本 1 的改动 {#alterations-from-v2} + +此版本修复了与[此处](https://github.com/ethereum/homestead-guide/blob/master/old-docs-for-reference/go-ethereum-wiki.rst/Passphrase-protected-key-store-spec.rst)发布的版本 1 的几处不一致。 简短来说,它们是: + +- 大小写不合理和不一致(scrypt 小写,Kdf 大小写混合,MAC 大写)。 +- 地址不必要并损害了隐私。 +- `Salt` 本质上是密钥派生函数的一个参数,因此应与该函数相关联,而不是与整个加密机制相关联。 +- _SaltLen_ 是不必要的(直接从 Salt 派生即可)。 +- 给出了密钥派生函数,但加密算法是硬性指定的。 +- `Version` 本质上是一个数字,然而却是一个字符串(结构化版本管理可以用一个字符串来实现,但对于一个很少变化的配置文件格式来说,可以认为是超出了范围)。 +- `KDF` 和 `cipher` 在概念上是同级关系,但组织方式却不同。 +- `MAC` 是通过一段与空白字符无关的数据计算的(!) + +我们对格式进行了修改,得到了以下文件,其功能和之前链接页面上的示例一样: + +```json +{ + "crypto": { + "cipher": "aes-128-cbc", + "ciphertext": "07533e172414bfa50e99dba4a0ce603f654ebfa1ff46277c3e0c577fdc87f6bb4e4fe16c5a94ce6ce14cfa069821ef9b", + "cipherparams": { + "iv": "16d67ba0ce5a339ff2f07951253e6ba8" + }, + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "n": 262144, + "p": 1, + "r": 8, + "salt": "06870e5e6a24e183a5c807bd1c43afd86d573f7db303ff4853d135cd0fd3fe91" + }, + "mac": "8ccded24da2e99a11d48cda146f9cc8213eb423e2ea0d8427f41c3be414424dd", + "version": 1 + }, + "id": "0498f19a-59db-4d54-ac95-33901b4f1870", + "version": 2 +} +``` + +## 与版本 2 的改动 {#alterations-from-v2} + +第 2 版是早期 C++ 实现的版本,有很多漏洞。 所有重要内容保持不变。 diff --git a/public/content/translations/zh/developers/docs/design-and-ux/dex-design-best-practice/index.md b/public/content/translations/zh/developers/docs/design-and-ux/dex-design-best-practice/index.md index 92e6b7c2c7f..cac3cb52dc1 100644 --- a/public/content/translations/zh/developers/docs/design-and-ux/dex-design-best-practice/index.md +++ b/public/content/translations/zh/developers/docs/design-and-ux/dex-design-best-practice/index.md @@ -1,6 +1,6 @@ --- -title: 去中心化交易所 (DEX) 设计最佳做法 -description: 说明代币交换用户体验/用户界面决策的指南 +title: "去中心化交易所 (DEX) 设计最佳做法" +description: "说明代币交换用户体验/用户界面决策的指南" lang: zh --- @@ -206,7 +206,7 @@ Figma 工具包也附于本文底部 - 请随意使用,快速制作你自己 ![主要行动号召中显示的错误信息](./17.png) -### 使用此 figma 文件构建你自己的设计 {#build-your-own-with-this-figma-file} +## 使用此 figma 文件构建你自己的设计 {#build-your-own-with-this-figma-file} 得益于多个协议的共同作用,去中心化交易所设计已经有了显著改进。 我们知道用户需要哪些信息,应该如何展示这些信息,以及如何使流程尽可能流畅。 希望这篇文章提供了关于用户体验原则的全面概述。 diff --git a/public/content/translations/zh/developers/docs/design-and-ux/heuristics-for-web3/index.md b/public/content/translations/zh/developers/docs/design-and-ux/heuristics-for-web3/index.md index 71f9c3cd9fc..98961cff158 100644 --- a/public/content/translations/zh/developers/docs/design-and-ux/heuristics-for-web3/index.md +++ b/public/content/translations/zh/developers/docs/design-and-ux/heuristics-for-web3/index.md @@ -1,11 +1,11 @@ --- -title: Web3 界面设计的 7 个启发法 -description: 改进 Web3 可用性的原则 +title: "Web3 界面设计的 7 个启发法" +description: "改进 Web3 可用性的原则" lang: zh --- 可用性启发法包含广泛的“经验法则”,你可以用它来衡量网站的可用性。 -这 7 种启发法是为 Web3 量身定制的,并且应该与 Jakob Nielsen 的 [界面设计的 10 条基本原则] (https://www.nngroup.com/articles/ten-usability-heuristics/) 一起使用。 +这 7 种启发法是为 Web3 量身定制的,并且应该与 Jakob Nielsen 的 [界面设计的 10 条基本原则](https://www.nngroup.com/articles/ten-usability-heuristics/) 一起使用。 ## Web3 的 7 个可用性启发法 {#seven-usability-heuristics-for-web3} @@ -54,7 +54,7 @@ lang: zh **示例:** 在页脚以显眼的尺寸包含你的审计内容。 -![在网站页脚引用的审计内容](./Image2.png) +![网站页脚中引用的审计](./Image2.png) ### 3. 突显最重要的信息 {#the-most-important-info-is-obvious} diff --git a/public/content/translations/zh/developers/docs/design-and-ux/index.md b/public/content/translations/zh/developers/docs/design-and-ux/index.md index bce01f31939..1e06acd29cc 100644 --- a/public/content/translations/zh/developers/docs/design-and-ux/index.md +++ b/public/content/translations/zh/developers/docs/design-and-ux/index.md @@ -1,91 +1,86 @@ --- -title: Web3 中的设计和用户体验 -description: 介绍 Web3 领域和以太坊中的用户体验设计和研究 +title: "Web3 中的设计和用户体验" +description: "介绍 Web3 领域和以太坊中的用户体验设计和研究" lang: zh --- 你不熟悉用以太坊进行设计吗? 如果是的话,那么这个地方你来对了。 以太坊社区已经编写了很多资源,介绍 Web3 的设计和研究基础知识。 你将学习一些核心概念,它们可能与你熟悉的其他应用程序设计不同。 -需要先对 Web3 有更基本的了解吗? 请浏览[**学习中心**](/learn/)。 +需要先对 Web3 有更基本的了解吗? 查看[**学习中心**](/learn/)。 ## 从用户研究开始 {#start-with-user-research} -有效的设计不仅仅是创建赏心悦目的用户界面。 还涉及到深入了解用户的需求、目标以及驱动因素。 因此,我们强烈建议所有设计师采用一种设计流程,例如[**双钻流程**](https://en.wikipedia.org/wiki/Double_Diamond_(design_process_model)),以确保其设计经过深思熟虑且有意为之。 +有效的设计不仅仅是创建赏心悦目的用户界面。 还涉及到深入了解用户的需求、目标以及驱动因素。 因此,我们强烈建议所有设计师采用一种设计流程,例如[**双钻流程**](https://en.wikipedia.org/wiki/Double_Diamond_\(design_process_model\)),以确保其设计经过深思熟虑且有意为之。 -- [Web3 需要更多用户体验研究人员和设计师](https://blog.akasha.org/akasha-conversations-9-web3-needs-more-ux-researchers-and-designers) - 当前设计成熟度概述 -- [在 Web3 中进行用户体验研究的简明指南](https://uxplanet.org/a-complete-guide-to-ux-research-for-web-3-0-products-d6bead20ebb1) - 研究方法简明指南 -- [如何在 Web3 中进行用户体验决策](https://archive.devcon.org/archive/watch/6/data-empathy-how-to-approach-ux-decisions-in-web3/) - 定量和定性研究简要概述及两者之间的区别(6 分钟视频) -- [在 Web3 中担任用户体验研究人员](https://medium.com/@georgia.rakusen/what-its-like-being-a-user-researcher-in-web3-6a4bcc096849) - 在 Web3 中担任用户体验研究人员的感受之个人看法 +- [Web3 需要更多的用户体验研究员和设计师](https://blog.akasha.org/akasha-conversations-9-web3-needs-more-ux-researchers-and-designers) - 当前设计成熟度概述 +- [web3 用户体验研究简明指南](https://uxplanet.org/a-complete-guide-to-ux-research-for-web-3-0-products-d6bead20ebb1) - 如何开展研究的简明指南 +- [如何在 Web3 中进行用户体验决策](https://archive.devcon.org/archive/watch/6/data-empathy-how-to-approach-ux-decisions-in-web3/) - 定量和定性研究简要概述及两者之间的区别(视频,6 分钟) +- [在 web3 中担任用户体验研究员](https://medium.com/@georgia.rakusen/what-its-like-being-a-user-researcher-in-web3-6a4bcc096849) - 关于在 web3 中担任用户体验研究员的个人观点 -## 针对 Web3 中的研究的调查 {#research-in-web3} +## Web3 研究 {#research-in-web3} 下面是一份已在 Web3 中进行的用户研究的精选清单,可能对设计和产品决策有所裨益,也可为自行进行研究提供灵感。 -| 关注领域 | 姓名 | -|:----------------------------------------------------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 加密货币入门 | [WalletConnect Pulse 2024:加密货币消费者的情绪及使用情况](https://walletconnect.com/pulse-2024-crypto-consumer-report) | -| 加密货币入门 | [CRADL:加密货币中的用户体验](https://docs.google.com/presentation/d/1s2OPSH5sMJzxRYaJSSRTe8W2iIoZx0PseIV-WeZWD1s/edit?usp=sharing) | -| 加密货币入门 | [CRADL:加密货币入门](https://docs.google.com/presentation/d/1R9nFuzA-R6SxaGCKhoMbE4Vxe0JxQSTiHXind3LVq_w/edit?usp=sharing) | -| 加密货币入门 | [比特币用户体验报告](https://github.com/patestevao/BitcoinUX-report/blob/master/report.md) | -| 加密货币入门 | [ConSensys:2023 年全球 Web3 认知度状况](https://consensys.io/insight-report/web3-and-crypto-global-survey-2023) | -| 加密货币入门 | [NEAR:加速采用之路](https://drive.google.com/file/d/1VuaQP4QSaQxR5ddQKTMGI0b0rWdP7uGn/view) | -| 权益质押 | [OpenUX:Rocket Pool 节点运营商的用户体验](https://storage.googleapis.com/rocketpool/RocketPool-NodeOperator-UX-Report-Jan-2024.pdf) | -| 权益质押 | [质押:主要趋势、要点与预测 - Eth Staker](https://lookerstudio.google.com/u/0/reporting/cafcee00-e1af-4148-bae8-442a88ac75fa/page/p_ja2srdhh2c?s=hmbTWDh9hJo) | -| 权益质押 | [多重应用程序质押](https://github.com/threshold-network/UX-User-Research/blob/main/Multi-App%20Staking%20(MAS)/iterative-user-study/MAS%20Iterative%20User%20Study.pdf) | -| 去中心化自治组织 | [2022 年去中心化自治组织研究更新:去中心化自治组织构建者需要什么?](https://blog.aragon.org/2022-dao-research-update/) | -| 去中心化金融 | [2024 年去中心化金融状况](https://stateofdefi.org/)(调查进行中) | -| 去中心化金融 | [保险池](https://github.com/threshold-network/UX-User-Research/tree/main/Keep%20Coverage%20Pool) | -| 去中心化金融 | [ConSensys:2022 年去中心化金融用户研究报告](https://cdn2.hubspot.net/hubfs/4795067/ConsenSys%20Codefi-Defi%20User%20ResearchReport.pdf) | -| 元宇宙 | [元宇宙:用户研究报告](https://www.politico.com/f/?id=00000187-7685-d820-a7e7-7e85d1420000) | -| 元宇宙 | [野外冒险:对元宇宙用户的研究](https://archive.devcon.org/archive/watch/6/going-on-safari-researching-users-in-the-metaverse/?tab=YouTube)(27 分钟视频) | -| Ethereum.org 用户体验数据 | [可用性与用户满意度调查仪表板 - Ethereum.org](https://lookerstudio.google.com/reporting/0a189a7c-a890-40db-a5c6-009db52c81c9) | - -## Web3 相关设计 {#design-for-web3} - -- [Web3 用户体验设计手册](https://web3ux.design/) - 设计 Web3 应用程序实用指南 -- [Web3 设计原则](https://medium.com/@lyricalpolymath/web3-design-principles-f21db2f240c1) - 区块链去中心化应用程序的用户体验规则构架 +| 关注领域 | 名称 | +| :------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 加密货币入门 | [The Reown Pulse 2024:加密货币消费者情绪和使用情况](https://reown.com/blog/unveiling-walletconnects-consumer-crypto-report) | +| 加密货币入门 | [CRADL:加密货币的用户体验](https://docs.google.com/presentation/d/1s2OPSH5sMJzxRYaJSSRTe8W2iIoZx0PseIV-WeZWD1s/edit?usp=sharing) | +| 加密货币入门 | [CRADL:加密货币入门](https://docs.google.com/presentation/d/1R9nFuzA-R6SxaGCKhoMbE4Vxe0JxQSTiHXind3LVq_w/edit?usp=sharing) | +| 加密货币入门 | [比特币用户体验报告](https://github.com/patestevao/BitcoinUX-report/blob/master/report.md) | +| 加密货币入门 | [Consensys:2023 年全球 Web3 认知状况](https://consensys.io/insight-report/web3-and-crypto-global-survey-2023) | +| 加密货币入门 | [NEAR:加速采用之旅](https://drive.google.com/file/d/1VuaQP4QSaQxR5ddQKTMGI0b0rWdP7uGn/view) | +| 质押 | [OpenUX:Rocket Pool 节点运营商用户体验](https://storage.googleapis.com/rocketpool/RocketPool-NodeOperator-UX-Report-Jan-2024.pdf) | +| 质押 | [质押:主要趋势、要点和预测 - Eth Staker](https://lookerstudio.google.com/u/0/reporting/cafcee00-e1af-4148-bae8-442a88ac75fa/page/p_ja2srdhh2c?s=hmbTWDh9hJo) | +| 质押 | [多应用质押](https://github.com/threshold-network/UX-User-Research/blob/main/Multi-App%20Staking%20\(MAS\)/iterative-user-study/MAS%20Iterative%20User%20Study.pdf) | +| DAO | [2022 年 DAO 研究更新:DAO 构建者需要什么?](https://blog.aragon.org/2022-dao-research-update/) | +| DeFi | [保险池](https://github.com/threshold-network/UX-User-Research/tree/main/Keep%20Coverage%20Pool) | +| DeFi | [Consensys:2022 年 DeFi 用户研究报告](https://cdn2.hubspot.net/hubfs/4795067/ConsenSys%20Codefi-Defi%20User%20ResearchReport.pdf) | +| 元宇宙 | [元宇宙:用户研究报告](https://www.politico.com/f/?id=00000187-7685-d820-a7e7-7e85d1420000) | +| 元宇宙 | [Safari 之旅:在元宇宙中研究用户](https://archive.devcon.org/archive/watch/6/going-on-safari-researching-users-in-the-metaverse/?tab=YouTube)(视频,27 分钟) | + +## Web3 设计 {#design-for-web3} + +- [Web3 用户体验设计手册](https://web3ux.design/) - 设计 Web3 应用程序的实用指南 +- [Web3 设计原则](https://medium.com/@lyricalpolymath/web3-design-principles-f21db2f240c1) - 基于区块链的去中心化应用程序的用户体验规则框架 - [区块链设计原则](https://medium.com/design-ibm/blockchain-design-principles-599c5c067b6e) - IBM 区块链设计团队的经验教训 -- [Web3 设计模式](https://www.web3designpatterns.io/) - 真实 Web3 产品的精选设计模式库 -- [W3design.io](https://w3design.io/) - 生态系统中不同项目的精选用户界面流程库 -- [Neueux](https://neueux.com/apps) - 具有多种过滤选项的用户界面流程库 -- [Web3 的可用性危机:你需要知道的一切!](https://www.youtube.com/watch?v=oBSXT_6YDzg) - 关于以开发者为中心的项目建设中漏洞的小组讨论(34 分钟视频) +- [Neueux.com](https://neueux.com/apps) - 具有多种筛选选项的用户流程界面库 +- [Web3 的可用性危机:你需要知道什么!](https://www.youtube.com/watch?v=oBSXT_6YDzg) - 关于以开发者为中心的项目建设中陷阱的小组讨论(视频,34 分钟) -## 入门指南 {#getting-started} +## 入门 {#getting-started} -- [Web3 启发法](/developers/docs/design-and-ux/heuristics-for-web3/) - Web3 界面设计的 7 个启发法 -- [去中心化交易所 (DEX) 设计最佳实践](/developers/docs/design-and-ux/dex-design-best-practice/) - 去中心化交易所设计指南 +- [Web3 启发式方法](/developers/docs/design-and-ux/heuristics-for-web3/) - Web3 界面设计的 7 种启发式方法 +- [DEX 设计最佳实践](/developers/docs/design-and-ux/dex-design-best-practice/) - 去中心化交易所设计指南 ## Web3 设计案例研究 {#design-case-studies} -- [Deep Work Studio](https://deepwork.studio/case-studies/) -- [加密货币用户体验手册](https://www.cryptouxhandbook.com/) -- [在 OpenSea 售卖非同质化代币](https://builtformars.com/case-studies/opensea) -- [钱包用户体验分解:钱包需要怎样改变](https://www.youtube.com/watch?v=oTpuxYj8JWI&ab_channel=ETHDenver)(20 分钟视频) +- [Deep Work Studio](https://www.deepwork.studio/case-studies) +- [在 OpenSea 上出售 NFT](https://builtformars.com/case-studies/opensea) +- [钱包用户体验分析:钱包需要如何改变](https://www.youtube.com/watch?v=oTpuxYj8JWI&ab_channel=ETHDenver)(视频,20 分钟) -## 设计奖励 {#bounties} +## 设计赏金 {#bounties} - [Dework](https://app.dework.xyz/bounties) -- [Buildbox 黑客马拉松](https://app.buidlbox.io/) -- [ETHGlobal 骇客松](https://ethglobal.com/) +- [Buildbox 黑客松](https://app.buidlbox.io/) +- [ETHGlobal 黑客松](https://ethglobal.com/) -## 设计去中心化自治组织和社区 {#design-daos-and-communities} +## 设计 DAO 和社区 {#design-daos-and-communities} 加入专业的社区主导型组织或设计小组,与其他成员讨论设计和研究相关的主题和趋势。 - [Vectordao.com](https://vectordao.com/) - [Deepwork.studio](https://www.deepwork.studio/) -- [Designer-dao.xyz](https://www.designer-dao.xyz/) - [We3.co](https://we3.co/) - [Openux.xyz](https://openux.xyz/) -## 设计体系 {#design-systems} +## 设计系统和其他设计资源 {#design-systems-and-resources} -- [乐观设计](https://www.figma.com/@optimism) (Figma) -- [Ethereum.org 设计体系](https://www.figma.com/@ethdotorg) (Figma) -- [Finity,来自 Polygon 的设计体系](https://www.figma.com/community/file/1073921725197233598/finity-design-system) (Figma) -- [Kleros 设计体系](https://www.figma.com/community/file/999852250110186964/kleros-design-system) (Figma) -- [安全设计体系](https://www.figma.com/community/file/1337417127407098506/safe-design-system) (Figma) -- [ENS 设计体系](https://thorin.ens.domains/) -- [Mirror 设计体系](https://degen-xyz.vercel.app/) +- [Optimism 设计](https://www.figma.com/@optimism) (Figma) +- [Ethereum.org 设计系统](https://www.figma.com/@ethdotorg) (Figma) +- [Finity,Polygon 的一个设计系统](https://www.figma.com/community/file/1073921725197233598/finity-design-system) (Figma) +- [Kleros 设计系统](https://www.figma.com/community/file/999852250110186964/kleros-design-system) (Figma) +- [Safe 设计系统](https://www.figma.com/community/file/1337417127407098506/safe-design-system) (Figma) +- [ENS 设计系统](https://thorin.ens.domains/) +- [Mirror 设计系统](https://degen-xyz.vercel.app/) -**本页所列文章和项目并非官方认可,**仅供参考。 我们根据我们[上线政策](/contributing/design/adding-design-resources)中的条件添加本页的链接。 如果你希望我们添加某个项目/某篇文章,请在 [GitHub](https://github.com/ethereum/ethereum-org-website/blob/dev/public/content/developers/docs/design-and-ux/index.md) 上编辑本页。 +**本页所列文章和项目并非官方认可**,仅供参考。 +我们根据[上榜政策](/contributing/design/adding-design-resources)中的标准将链接添加到此页面。 如果你希望我们添加项目/文章,请在 [GitHub](https://github.com/ethereum/ethereum-org-website/blob/dev/public/content/developers/docs/design-and-ux/index.md) 上编辑此页面。 diff --git a/public/content/translations/zh/developers/docs/development-networks/index.md b/public/content/translations/zh/developers/docs/development-networks/index.md index 1c26e6d3cd0..7158a9bc13f 100644 --- a/public/content/translations/zh/developers/docs/development-networks/index.md +++ b/public/content/translations/zh/developers/docs/development-networks/index.md @@ -1,6 +1,6 @@ --- -title: 开发网络 -description: 对以太坊应用的开发网络环境与开发工具的概览。 +title: "开发网络" +description: "对以太坊应用的开发网络环境与开发工具的概览。" lang: zh --- @@ -8,9 +8,9 @@ lang: zh 这和在本地运行一个本地网页服务器相似。为了测试你的去中心化应用程序,你可以使用开发网络创建一个本地的区块链。 这些以太坊开发网络提供了能够比公共测试网更快的迭代功能(例如你不需要从测试网获取以太币)。 -## 前置要求 {#prerequisites} +## 前提条件 {#prerequisites} -你应该先理解[以太坊堆栈](/developers/docs/ethereum-stack/)和[以太坊网络](/developers/docs/networks/)基础知识才能进入开发网络。 +在深入研究开发网络之前,你应该先了解[以太坊技术栈](/developers/docs/ethereum-stack/)和[以太坊网络](/developers/docs/networks/)的基础知识。 ## 什么是开发网络? {#what-is-a-development-network} @@ -18,39 +18,37 @@ lang: zh **为什么不在本地运行一个标准的以太坊节点?** -你_可以_[运行节点](/developers/docs/nodes-and-clients/#running-your-own-node),但由于开发网络是以开发为目的而建立的,它们往往会打包一些快捷方便的功能,例如: +你_可以_[运行一个节点](/developers/docs/nodes-and-clients/#running-your-own-node),但由于开发网络是专为开发目的而构建的,它们通常会附带一些方便的功能,例如: -- 为本地区块链提供数据,这个功能很重要(例如使用以太币余额的帐户) +- 确定性地为你的本地区块链填充数据(例如,带有 ETH 余额的帐户) - 用接收的每笔交易,按照顺序即时产生区块,毫不延迟。 - 增强调试和日志功能 ## 可用工具 {#available-projects} -**注意**:大多数[开发框架](/developers/docs/frameworks/)包含一个内置的开发网络。 我们建议从一个框架开始[设置你的本地开发环境](/developers/local-environment/)。 +**注意**:大多数[开发框架](/developers/docs/frameworks/)都包含一个内置的开发网络。 我们建议从一个框架开始[设置你的本地开发环境](/developers/local-environment/)。 -### 安全帽网络 {#hardhat-network} +### Hardhat 网络 {#hardhat-network} 一个专门用于开发的本地以太坊网络。 该网络允许你部署合约,运行测试并调试代码。 -安全帽网络内置了安全帽,安全帽是专业人员的以太坊开发环境。 +Hardhat网络内置了Hardhat,Hardhat是专业人员的以太坊开发环境。 - [网站](https://hardhat.org/) -- [GitHub](https://github.com/nomiclabs/hardhat) +- [GitHub](https://github.com/NomicFoundation/hardhat) ### 本地信标链 {#local-beacon-chains} 一些共识客户端具有内置工具,用于启动本地信标链以进行测试。 提供了 Lighthouse、Nimbus 和 Lodestar 的说明: - [使用 Lodestar 的本地测试网](https://chainsafe.github.io/lodestar/contribution/advanced-topics/setting-up-a-testnet#post-merge-local-testnet/) -- [使用 Lightthouse 的本地测试网](https://lighthouse-book.sigmaprime.io/setup.html#local-testnets) +- [使用 Lighthouse 的本地测试网](https://lighthouse-book.sigmaprime.io/setup.html#local-testnets) ### 公共以太坊测试链 {#public-beacon-testchains} -以太坊还有两个维护中的公共测试网实现:Sepolia 和 Hoodi。 Sepolia 是推荐的应用程序开发标准测试网,具有封闭的验证器集以实现快速同步。 Hoodi 是一个用于验证和质押的测试网,它使用开放的验证器集,并允许任何人进行验证。 +以太坊还有两个维护中的公共测试网实现:Sepolia 和 Hoodi。 推荐使用获得长期支持的测试网 Hoodi,任何人都可以自由地在其上验证。 Sepolia 采用许可制的验证者集合,这意味着在该测试网中没有面向公众的新验证者访问权限。 -- [Hoodi 质押启动板](https://hoodi.launchpad.ethereum.org/en/) -- [Sepolia 网站](https://sepolia.dev/) -- [Hoodi 网站](https://hoodi.ethpandaops.io/) +- [Hoodi 质押启动板](https://hoodi.launchpad.ethereum.org/) ### Kurtosis 以太坊包 {#kurtosis} @@ -63,11 +61,11 @@ Kurtosis 是一个用于多容器测试环境的构建系统,让开发者能 - [GitHub](https://github.com/kurtosis-tech/kurtosis) - [相关文档](https://docs.kurtosis.com/) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [开发框架](/developers/docs/frameworks/) - [设置本地开发环境](/developers/local-environment/) diff --git a/public/content/translations/zh/developers/docs/ethereum-stack/index.md b/public/content/translations/zh/developers/docs/ethereum-stack/index.md index d58c9f614aa..99c61b33b09 100644 --- a/public/content/translations/zh/developers/docs/ethereum-stack/index.md +++ b/public/content/translations/zh/developers/docs/ethereum-stack/index.md @@ -1,6 +1,6 @@ --- -title: 以太坊堆栈简介 -description: 一次从不同层面对以太坊堆栈原理的浏览,并且了解如何让不同的以太坊堆栈融为一体。 +title: "以太坊堆栈简介" +description: "一次从不同层面对以太坊堆栈原理的浏览,并且了解如何让不同的以太坊堆栈融为一体。" lang: zh --- @@ -10,11 +10,11 @@ lang: zh ## 级别 1:以太坊虚拟机 {#ethereum-virtual-machine} -[以太坊虚拟机 (EVM)](/developers/docs/evm/) 是智能合约在以太坊上的运行环境。 以太坊区块链上的所有智能合约和状态更改都由[交易](/developers/docs/transactions/)执行。 以太坊虚拟机处理以在太坊网络上执行的所有交易。 +[以太坊虚拟机 (EVM)](/developers/docs/evm/) 是智能合约在以太坊上的运行环境。 以太坊区块链上的所有智能合约和状态变更都由[交易](/developers/docs/transactions/)执行。 以太坊虚拟机处理以在太坊网络上执行的所有交易。 -与任何虚拟机一样,以太坊虚拟机在执行代码和执行机器(以太坊节点)之间创建一个抽象级别。 目前,在世界各地散布着成千上万的正在执行的以太坊虚拟机节点。 +与任何虚拟机一样,以太坊虚拟机在执行代码和执行机器(以太坊节点)之间创建一个抽象级别。 目前,EVM 正在全球分布的数千个节点上运行。 -在后台,那些以太坊虚拟机会使用操作码执行一些特殊的任务。 这些(140 个惟一的)操作码使以太坊虚拟机具有 [图灵完备](https://en.wikipedia.org/wiki/Turing_completeness),这意味着只要提供足够的资源,以太坊虚拟机几乎可以计算任何东西。 +在后台,那些以太坊虚拟机会使用操作码执行一些特殊的任务。 这些(140 个惟一的)操作码使 EVM 能够实现[图灵完备](https://en.wikipedia.org/wiki/Turing_completeness),这意味着只要有足够的资源,EVM 几乎可以计算任何东西。 作为去中心化应用程序的开发者,除了了解以太坊虚拟机的存在之外,你不需要了解更多关于以太坊虚拟机的信息,并且可以在以太坊上畅通无阻地授权所有应用程序。 @@ -22,40 +22,40 @@ lang: zh [智能合约](/developers/docs/smart-contracts/)是在以太坊区块链上运行的可执行程序。 -智能合约使用了特定的[编程语言](/developers/docs/smart-contracts/languages/)来编译到以太坊虚拟机字节码(调用操作码的低级机器说明)。 +智能合约使用特定的[编程语言](/developers/docs/smart-contracts/languages/)编写,这些语言可以编译成 EVM 字节码(称为操作码的低级机器指令)。 -智能合约不仅是开放源码库,而且它们基本上是运行 24/7 的开放应用程序接口服务,不能被取消。 智能合约提供了为用户和应用程序([去中心化应用程序](/developers/docs/dapps/))之间交互的公开方法,无需许可。 任何应用程序都可能会与已部署的智能合约集成组成功能,如添加[数据源](/developers/docs/oracles/)或支持代币交换。 任何人都可以在以太坊上部署智能合约,以便添加自定义功能来满足其应用程序的需要。 +智能合约不仅是开放源码库,而且它们基本上是运行 24/7 的开放应用程序接口服务,不能被取消。 智能合约提供公共函数,用户和应用程序([去中心化应用程序](/developers/docs/dapps/))无需许可即可与之交互。 任何应用程序都可以与已部署的智能合约集成以组合功能,例如添加[数据馈送](/developers/docs/oracles/)或支持代币交换。 此外,任何人都可以在以太坊上部署新的智能合约,以添加自定义功能来满足其应用程序的需求。 作为一个去中心化应用程序开发者,如果你需要在以太坊区块链上添加自定义功能,需要通过写智能合约来实现。 你可能会发现你可以仅仅通过与现有智能合约进行整合来满足你项目的大部分或全部的需要。例如,如果你想要支持支付稳定币或启用分散交换代币。 ## 级别 3:以太坊节点 {#ethereum-nodes} -为了让应用程序与以太坊区块链交互,它必须连接到 [以太坊节点](/developers/docs/nodes-and-clients/)。 正在连接到一个节点,你可以读取区块链数据和/或将交易发送到网络。 +为了使应用程序能与以太坊区块链交互,它必须连接到[以太坊节点](/developers/docs/nodes-and-clients/)。 正在连接到一个节点,你可以读取区块链数据和/或将交易发送到网络。 -以太坊节点是运行着软件的电脑,这些软件也就是一个以太坊客户端。 客户端是一种以太坊的实现,它可以验证每个区块中的所有交易,从而确保网络安全和数据准确。 **以太坊节点是以太坊区块链**。 他们集体存储以太坊区块链的状态,并根据改变区块链状态的交易达成共识。 +以太坊节点是运行着软件的电脑,这些软件也就是一个以太坊客户端。 客户端是一种以太坊实现,它验证每个区块中的所有交易,从而确保网络安全和数据准确。 **以太坊节点就是以太坊区块链**。 他们集体存储以太坊区块链的状态,并根据改变区块链状态的交易达成共识。 -通过将应用程序连接到以太坊节点(通过 [JSON RPC 应用程序接口](/developers/docs/apis/json-rpc/)),应用程序可以从区块链(例如用户帐户余额)读取数据,并向网络广播新交易(例如在用户帐户之间传输以太币或执行智能合约的功能)。 +通过将你的应用程序连接到以太坊节点(通过 [JSON-RPC API](/developers/docs/apis/json-rpc/)),你的应用程序就能够从区块链读取数据(例如用户帐户余额),以及向网络广播新的交易(例如在用户帐户之间转移 ETH 或执行智能合约的函数)。 -## 级别 4:以太坊客户端应用程序接口 {#ethereum-client-apis} +## 级别 4:以太坊客户端 API {#ethereum-client-apis} 许多方便的库(由以太坊开源社区建立和维护)允许你的终端用户应用程序连接到以太坊区块链并进行通信。 -如果你的面向用户应用程序是一个 web 应用程序,你可以直接选择在你的前端使用 `npm 安装`一个 [JavaScript 应用程序接口](/developers/docs/apis/javascript/)。 或许你会选择使用 [Python](/developers/docs/programming-languages/python/) 或 [Java](/developers/docs/programming-languages/java/) 的应用程序接口在后端实现此功能。 +如果你的面向用户的应用程序是网页应用,你可以选择直接在前端 `npm install` 一个 [JavaScript API](/developers/docs/apis/javascript/)。 或者,你也可以选择使用 [Python](/developers/docs/programming-languages/python/) 或 [Java](/developers/docs/programming-languages/java/) API,在服务器端实现此功能。 -虽然这些应用程序接口不是栈必须的一部分,但它们抽象并消减了与以太坊节点直接互动的大部分复杂性。 它们还提供好用的函数(例如:将 ETH 转化为 Gwei),而作为开发者,你可以花费更少的时间处理以太坊客户端的复杂问题,从而将更多的时间集中于处理你的应用程序的独特功能。 +虽然这些应用程序接口不是栈必须的一部分,但它们抽象并消减了与以太坊节点直接互动的大部分复杂性。 它们还提供实用函数(例如将 ETH 转换为 Gwei),因此作为开发者,你可以花更少的时间处理以太坊客户端的复杂细节,将更多时间专注于应用程序的特定功能。 -## 级别 5:终端用户应用程序 {#end-user-applications} +## 级别 5:最终用户应用程序 {#end-user-applications} 在栈的顶层是面向用户的应用程序。 这些是你今天经常用和构建的标准应用程序:主要是网络程序和移动应用程序。 开发这些用户界面的方式基本上保持不变。 用户常常不需要知道他们所使用的应用程序是使用区块链构建的。 -## 准备好选择技术栈了吗? {#ready-to-choose-your-stack} +## 准备好选择技术栈了吗? 准备好选择你的技术栈了吗?{#ready-to-choose-your-stack} -查看我们的指南为你的以太坊应用程序 [设置本地开发环境](/developers/local-environment/)。 +查看我们的指南,为你的以太坊应用程序[设置本地开发环境](/developers/local-environment/)。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [一个 Web 3.0 应用的架构](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) - _Preethi Kasireddy_ +- [Web 3.0 应用程序的架构](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) - _Preethi Kasireddy_ -_还有哪些社区资源对你有所帮助? 编辑并添加本页面!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ diff --git a/public/content/translations/zh/developers/docs/evm/index.md b/public/content/translations/zh/developers/docs/evm/index.md index 58389f2286d..344cfeb7d8b 100644 --- a/public/content/translations/zh/developers/docs/evm/index.md +++ b/public/content/translations/zh/developers/docs/evm/index.md @@ -1,78 +1,88 @@ --- -title: 以太坊虚拟机 (EVM) -description: 介绍以太坊虚拟机及其与状态、交易和智能合约的关系。 +title: "以太坊虚拟机 (EVM)" +description: "介绍以太坊虚拟机及其与状态、交易和智能合约的关系。" lang: zh --- -以太坊虚拟机 (EVM) 是一个去中心化虚拟环境,它在所有以太坊节点上一种安全一致地方式执行代码。 节点运行以太坊虚拟机,以执行智能合约,利用“[燃料](/gas/)”度量执行[操作](/developers/docs/evm/opcodes/)所需的计算工作,从而确保高效的资源分配和网络安全性。 +以太坊虚拟机 (EVM) 是一个去中心化虚拟环境,它在所有以太坊节点上一种安全一致地方式执行代码。 节点运行 EVM 执行智能合约,使用“[燃料](/developers/docs/gas/)”衡量执行[操作](/developers/docs/evm/opcodes/)所需的计算工作,从而确保高效的资源分配和网络安全。 ## 前提条件 {#prerequisites} -对计算机科学中常见术语的基本了解,如[字节](https://wikipedia.org/wiki/Byte)、[内存](https://wikipedia.org/wiki/Computer_memory)和[堆栈](https://wikipedia.org/wiki/Stack_(abstract_data_type))是理解 EVM 的前提。 熟悉[哈希函数](https://wikipedia.org/wiki/Cryptographic_hash_function)和[默克尔树](https://wikipedia.org/wiki/Merkle_tree)等密码学/区块链概念也会很有帮助。 +若要理解 EVM,需要对计算机科学中的一些常见术语有基本的了解,例如[字节](https://wikipedia.org/wiki/Byte)、[内存](https://wikipedia.org/wiki/Computer_memory)和[堆栈](https://wikipedia.org/wiki/Stack_\(abstract_data_type\))。 熟悉[哈希函数](https://wikipedia.org/wiki/Cryptographic_hash_function)和[默克尔树](https://wikipedia.org/wiki/Merkle_tree)等加密/区块链概念也会有所帮助。 ## 从账本到状态机 {#from-ledger-to-state-machine} 通常使用“分布式账本”的类比来描述像比特币这样的区块链,它使用密码学的基本工具来实现去中心化的货币。 账本保存着活动记录,而活动必须遵守一套规则,这些规则限制用户在修改账本时可以做什么和不可以做什么。 例如,比特币地址不能花费比之前收到的更多的比特币。 这些规则是比特币和许多其他区块链上所有交易的基础。 -虽然以太坊有自己的本机加密货币 (ETH),遵循几乎完全相同的直观规则,但它也支持更强大的功能:[智能合约](/developers/docs/smart-contracts/)。 对于此更复杂的功能,需要一个更复杂的类比。 以太坊不是分布式账本,而是分布式[状态机器](https://wikipedia.org/wiki/Finite-state_machine)。 以太坊的状态是一个大型数据结构,它不仅保存所有帐户和余额,而且还保存一个_机器状态_,它可以根据预定义的一组规则在不同的区块之间进行更改,并且可以执行任意的机器代码。 在区块中更改状态的具体规则由 EVM 定义。 +以太坊有自己的原生加密货币(以太币),其规则非常直观,但它也实现了一个更强大的功能:[智能合约](/developers/docs/smart-contracts/)。 对于此更复杂的功能,需要一个更复杂的类比。 以太坊不是一个分布式账本,而是一个分布式[状态机](https://wikipedia.org/wiki/Finite-state_machine)。 以太坊的状态是一个大型数据结构,它不仅保存了所有的账户和余额,还保存了一个_机器状态_,它可以根据一组预定义的规则在区块之间发生变化,并且可以执行任意的机器代码。 在区块中更改状态的具体规则由 EVM 定义。 -![EVM 组成结构图](./evm.png) _示意图节选自[以太坊虚拟机图解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![展示 EVM 构成的图表](./evm.png) +_图表改编自 [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ ## 以太坊状态转换函数 {#the-ethereum-state-transition-function} -EVM 的行为就像一个数学函数:在给定输入的情况下,它会产生确定性的输出。 因此,将以太坊更正式地描述为具有**状态转换函数**非常有帮助: +EVM 的行为就像一个数学函数:在给定输入的情况下,它会产生确定性的输出。 因此,将以太坊更正式地描述为具有**状态转换函数**会很有帮助: ``` Y(S, T)= S' ``` -给定一个旧的有效状态 `(S)`> 和一组新的有效交易 `(T)`,以太坊状态转换函数 ` Y(S,T)` 产生新的有效输出状态` S'` +给定一个旧的有效状态 `(S)` 和一组新的有效交易 `(T)`,以太坊状态转换函数 `Y(S, T)` 会生成一个新的有效输出状态 `S'` ### 状态 {#state} -在以太坊环境中,状态是一种称为[改进版默克尔帕特里夏树](/developers/docs/data-structures-and-encoding/patricia-merkle-trie/)的巨大数据结构,它保存所有通过哈希关联在一起的[帐户](/developers/docs/accounts/)并可回溯到存储在区块链上的单个根哈希。 +在以太坊中,状态是一个被称为[改良默克尔帕特里夏树](/developers/docs/data-structures-and-encoding/patricia-merkle-trie/)的巨大数据结构,它保存了所有通过哈希链接的[帐户](/developers/docs/accounts/),并可归约为存储在区块链上的单个根哈希。 ### 交易 {#transactions} -交易是来自帐户的密码学签名指令。 交易分为两种:一种是消息调用交易,另一种是合约创建交易。 +交易是由帐户发出,带密码学签名的指令。 交易分为两种:一种是消息调用交易,另一种是合约创建交易。 -合约创建交易会创建一个新的合约帐户,其中包含已编译的 [智能合约](/developers/docs/smart-contracts/anatomy/) 字节码。 每当另一个帐户对该合约进行消息调用时,它都会执行其字节码。 +创建合约会创建一个新的合约帐户,其中包含已编译的[智能合约](/developers/docs/smart-contracts/anatomy/)字节码。 每当另一个帐户对该合约进行消息调用时,它都会执行其字节码。 -## EVM 说明 {#evm-instructions} +## EVM 指令 {#evm-instructions} -EVM 作为一个[堆栈机](https://wikipedia.org/wiki/Stack_machine)运行,其栈的深度为 1024 个项。 每个项目都是 256 位字,为了便于使用,选择了 256 位加密技术(如 Keccak-256 哈希或 secp256k1 签名)。 +EVM 作为[堆栈机](https://wikipedia.org/wiki/Stack_machine)执行,堆栈深度为 1024 个项。 每个项目都是 256 位字,为了便于使用,选择了 256 位加密技术(如 Keccak-256 哈希或 secp256k1 签名)。 -在执行期间,EVM 会维护一个瞬态_内存_(作为字可寻址的字节数组),该内存不会在交易之间持久存在。 +在执行期间,EVM 维护一个瞬态_内存_(一个字可寻址的字节数组),该内存不会在交易之间持久存在。 -然而,合约确实包含一个 Merkle Patricia _存储_ trie(作为可字寻址的字数组),该 trie 与帐户和部分全局状态关联。 +### 瞬态存储 -已编译的智能合约字节码作为许多 EVM [opcodes](/developers/docs/evm/opcodes)执行,它们执行标准的堆栈操作,例如 `XOR`、`AND`、`ADD`、`SUB`等。 EVM 还实现了一些区块链特定的堆栈操作,如 `ADDRESS`、`BALANCE`、`BLOCKHASH` 等。 +瞬态存储是每笔交易的键值存储,可通过 `TSTORE` 和 `TLOAD` 操作码访问。 它在同一笔交易的所有内部调用中都会持续存在,但在交易结束时会被清除。 与内存不同,瞬态存储被建模为 EVM 状态的一部分,而不是执行框架的一部分,但它不会提交到全局状态。 瞬态存储可以在一笔交易的内部调用之间实现燃料高效的临时状态共享。 -![表明 EVM 操作需要 Gas 的图表](../gas/gas.png) _示意图节选自[以太坊虚拟机图解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +### 存储 + +合约包含一个与相关帐户关联的默克尔帕特里夏_存储_树(作为字可寻址字数组),是全局状态的一部分。 这种持久化存储与瞬态存储不同,后者仅在单笔交易期间可用,并且不构成帐户持久化存储树的一部分。 + +### 操作码 + +编译后的智能合约字节码作为多个 EVM [操作码](/developers/docs/evm/opcodes)执行,这些操作码执行 `XOR`、`AND`、`ADD`、`SUB` 等标准堆栈操作。 EVM 还实现了一些区块链特有的堆栈操作,例如 `ADDRESS`、`BALANCE`、`BLOCKHASH` 等。 操作码集还包括 `TSTORE` 和 `TLOAD`,它们提供对瞬态存储的访问。 + +![一张图表,显示 EVM 操作在何处需要燃料](../gas/gas.png) +_图表改编自 [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ ## EVM 实现 {#evm-implementations} EVM 的所有实现都必须遵守以太坊黄皮书中描述的规范。 -在以太坊九年的历程中,以太坊虚拟机经过了几次修订,并且存在不同编程语言实现的以太坊虚拟机版本。 +在以太坊十年的历史中,EVM 经历了数次修订,并且有多种编程语言的 EVM 实现。 -[以太坊执行客户端](/developers/docs/nodes-and-clients/#execution-clients)都包含一个以太坊虚拟机实现。 此外,还有多个独立的实现,包括: +[以太坊执行客户端](/developers/docs/nodes-and-clients/#execution-clients)包括一个 EVM 实现。 此外,还有多个独立的实现,包括: - [Py-EVM](https://github.com/ethereum/py-evm) - _Python_ - [evmone](https://github.com/ethereum/evmone) - _C++_ - [ethereumjs-vm](https://github.com/ethereumjs/ethereumjs-vm) - _JavaScript_ - [revm](https://github.com/bluealloy/revm) - _Rust_ -## 延伸阅读 {#further-reading} +## 扩展阅读 {#further-reading} - [以太坊黄皮书](https://ethereum.github.io/yellowpaper/paper.pdf) -- [Jellopaper aka KEVM:K 中的 EVM 语法](https://jellopaper.org/) -- [The Beigepaper](https://github.com/chronaeon/beigepaper) +- [Jellopaper 又名 KEVM:K 框架中的 EVM 语义](https://jellopaper.org/) +- [米色皮书](https://github.com/chronaeon/beigepaper) - [以太坊虚拟机操作码](https://www.ethervm.io/) -- [以太坊虚拟机操作码交互参考](https://www.evm.codes/) -- [Solidity 文档的简短介绍](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html#index-6) +- [以太坊虚拟机操作码交互式参考](https://www.evm.codes/) +- [Solidity 文档中的简短介绍](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html#index-6) - [精通以太坊 - 以太坊虚拟机](https://github.com/ethereumbook/ethereumbook/blob/openedition/13evm.asciidoc) ## 相关主题 {#related-topics} -- [Gas](/developers/docs/gas/) +- [燃料](/developers/docs/gas/) diff --git a/public/content/translations/zh/developers/docs/evm/opcodes/index.md b/public/content/translations/zh/developers/docs/evm/opcodes/index.md index 7936185fd88..d4b7f68b9c0 100644 --- a/public/content/translations/zh/developers/docs/evm/opcodes/index.md +++ b/public/content/translations/zh/developers/docs/evm/opcodes/index.md @@ -1,174 +1,177 @@ --- -title: 以太坊虚拟机的操作码 -description: 以下是以太坊虚拟机可用的所有操作码的列表。 +title: "以太坊虚拟机的操作码" +description: "以下是以太坊虚拟机可用的所有操作码的列表。" lang: zh --- ## 概述 {#overview} -本文是位于 [wolflo/evm-opcodes](https://github.com/wolflo/evm-opcodes) 的以太坊虚拟机参考页面的更新版本。 本文亦节选自[黄皮书](https://ethereum.github.io/yellowpaper/paper.pdf)、[Jello Paper](https://jellopaper.org/evm/)及 [geth](https://github.com/ethereum/go-ethereum) 实现。 本文旨在作为一份易于理解的参考资料,但并不十分严谨。 如果想确保正确性并了解每种边缘情况,建议使用 Jello Paper 或客户端实现。 +这是 [wolflo/evm-opcodes](https://github.com/wolflo/evm-opcodes) 上的 EVM 参考页面的更新版本。 +内容也源自[《黄皮书》](https://ethereum.github.io/yellowpaper/paper.pdf)、[《Jello Paper》](https://jellopaper.org/evm/)和 [geth](https://github.com/ethereum/go-ethereum) 实现。 +本文旨在作为一份易于理解的参考资料,但并不十分严谨。 +如果想确保正确性并了解每种边缘情况,建议使用 Jello Paper 或客户端实现。 -在寻找交互式参考? 请查看 [evm.codes](https://www.evm.codes/)。 +在寻找交互式参考? 查看 [evm.codes](https://www.evm.codes/)。 -对于具有动态燃料成本的操作,请参考 [gas.md](https://github.com/wolflo/evm-opcodes/blob/main/gas.md)。 +有关具有动态燃料费用的操作,请参阅 [gas.md](https://github.com/wolflo/evm-opcodes/blob/main/gas.md)。 -💡温馨提示:要查看完整行,请在电脑上使用 `[shift] + scroll` 水平滚动浏览。 +💡 快速提示:要在桌面设备上查看整行,请使用 `[shift] + scroll` 水平滚动。 -| 堆栈 | 名称 | 燃料 | 起始堆栈 | 最终堆栈 | 内存 / 存储 | 注释 | -|:-----:|:-------------- |:-----------------------------------------------------------------------------------------------:|:------------------------------------------------ |:-------------------------------------------- |:----------------------------------------------------------------------------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 00 | 停止 | 0 | | | | halt execution | -| 01 | ADD | 3 | `a, b` | `a + b` | | (u)int256 addition modulo 2\*\*256 | -| 02 | MUL | 5 | `a, b` | `a * b` | | (u)int256 multiplication modulo 2\*\*256 | -| 03 | SUB | 3 | `a, b` | `a - b` | | (u)int256 addition modulo 2\*\*256 | -| 04 | DIV | 5 | `a, b` | `a // b` | | uint256 division | -| 05 | SDIV | 5 | `a, b` | `a // b` | | int256 division | -| 06 | MOD | 5 | `a, b` | `a % b` | | uint256 modulus | -| 07 | SMOD | 5 | `a, b` | `a % b` | | int256 modulus | -| 08 | ADDMOD | 8 | `a, b, N` | `(a + b) % N` | | (u)int256 addition modulo N | -| 09 | MULMOD | 8 | `a, b, N` | `(a * b) % N` | | (u)int256 multiplication modulo N | -| 0A | EXP | [A1](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a1-exp) | `a, b` | `a ** b` | | uint256 exponentiation modulo 2\*\*256 | -| 0B | SIGNEXTEND | 5 | `b, x` | `SIGNEXTEND(x, b)` | | [sign extend](https://wikipedia.org/wiki/Sign_extension) `x` from `(b+1)` bytes to 32 bytes | -| 0C-0F | _invalid_ | | | | | | -| 10 | LT | 3 | `a, b` | `a < b` | | uint256 less-than | -| 11 | GT | 3 | `a, b` | `a > b` | | uint256 greater-than | -| 12 | SLT | 3 | `a, b` | `a < b` | | int256 less-than | -| 13 | SGT | 3 | `a, b` | `a > b` | | int256 greater-than | -| 14 | EQ | 3 | `a, b` | `a == b` | | (u)int256 equality | -| 15 | ISZERO | 3 | `a` | `a == 0` | | (u)int256 iszero | -| 16 | AND | 3 | `a, b` | `a && b` | | bitwise AND | -| 17 | OR | 3 | `a, b` | `a \|\| b` | | bitwise OR | -| 18 | XOR | 3 | `a, b` | `a ^ b` | | bitwise XOR | -| 19 | NOT | 3 | `a` | `~a` | | bitwise NOT | -| 1A | BYTE | 3 | `i, x` | `(x >> (248 - i * 8)) && 0xFF` | | `i`th byte of (u)int256 `x`, from the left | -| 1B | SHL | 3 | `shift, val` | `val << shift` | | shift left | -| 1C | SHR | 3 | `shift, val` | `val >> shift` | | logical shift right | -| 1D | SAR | 3 | `shift, val` | `val >> shift` | | arithmetic shift right | -| 1E-1F | _invalid_ | | | | | | -| 20 | KECCAK256 | [A2](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a2-sha3) | `ost, len` | `keccak256(mem[ost:ost+len-1])` | | keccak256 | -| 21-2F | _invalid_ | | | | | | -| 30 | ADDRESS | 2 | `.` | `address(this)` | | address of executing contract | -| 31 | BALANCE | [A5](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a5-balance-extcodesize-extcodehash) | `addr` | `addr.balance` | | balance, in wei | -| 32 | ORIGIN | 2 | `.` | `tx.origin` | | address that originated the tx | -| 33 | CALLER | 2 | `.` | `msg.sender` | | address of msg sender | -| 34 | CALLVALUE | 2 | `.` | `msg.value` | | msg value, in wei | -| 35 | CALLDATALOAD | 3 | `idx` | `msg.data[idx:idx+32]` | | read word from msg data at index `idx` | -| 36 | CALLDATASIZE | 2 | `.` | `len(msg.data)` | | length of msg data, in bytes | -| 37 | CALLDATACOPY | [A3](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a3-copy-operations) | `dstOst, ost, len` | `.` | mem[dstOst:dstOst+len-1] := msg.data[ost:ost+len-1] | copy msg data | -| 38 | CODESIZE | 2 | `.` | `len(this.code)` | | length of executing contract's code, in bytes | -| 39 | CODECOPY | [A3](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a3-copy-operations) | `dstOst, ost, len` | `.` | | mem[dstOst:dstOst+len-1] := this.code[ost:ost+len-1] | copy executing contract's bytecode | -| 3A | GASPRICE | 2 | `.` | `tx.gasprice` | | gas price of tx, in wei per unit gas [\*\*](https://eips.ethereum.org/EIPS/eip-1559#gasprice) | -| 3B | EXTCODESIZE | [A5](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a5-balance-extcodesize-extcodehash) | `addr` | `len(addr.code)` | | size of code at addr, in bytes | -| 3C | EXTCODECOPY | [A4](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a4-extcodecopy) | `addr, dstOst, ost, len` | `.` | mem[dstOst:dstOst+len-1] := addr.code[ost:ost+len-1] | copy code from `addr` | -| 3D | RETURNDATASIZE | 2 | `.` | `size` | | size of returned data from last external call, in bytes | -| 3E | RETURNDATACOPY | [A3](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a3-copy-operations) | `dstOst, ost, len` | `.` | mem[dstOst:dstOst+len-1] := returndata[ost:ost+len-1] | copy returned data from last external call | -| 3F | EXTCODEHASH | [A5](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a5-balance-extcodesize-extcodehash) | `addr` | `哈希值` | | hash = addr.exists ? keccak256(addr.code) : 0 | -| 40 | BLOCKHASH | 20 | `blockNum` | `blockHash(blockNum)` | | | -| 41 | COINBASE | 2 | `.` | `block.coinbase` | | 当前区块提议者地址 | -| 42 | TIMESTAMP | 2 | `.` | `block.timestamp` | | timestamp of current block | -| 43 | NUMBER | 2 | `.` | `block.number` | | number of current block | -| 44 | PREVRANDAO | 2 | `.` | `randomness beacon` | | randomness beacon | -| 45 | GASLIMIT | 2 | `.` | `block.gaslimit` | | gas limit of current block | -| 46 | CHAINID | 2 | `.` | `chain_id` | | push current [chain id](https://eips.ethereum.org/EIPS/eip-155) onto stack | -| 47 | SELFBALANCE | 5 | `.` | `address(this).balance` | | balance of executing contract, in wei | -| 48 | BASEFEE | 2 | `.` | `block.basefee` | | base fee of current block | -| 49 | BLOBHASH | 3 | `idx` | `tx.blob_versioned_hashes[idx]` | | [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) | -| 4A | BLOBBASEFEE | 2 | `.` | `block.blobbasefee` | | 当前区块的二进制大对象基础费([EIP-7516](https://eips.ethereum.org/EIPS/eip-7516)) | -| 4B-4F | _invalid_ | | | | | | -| 50 | POP | 2 | `_anon` | `.` | | remove item from top of stack and discard it | -| 51 | MLOAD | 3[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost` | `mem[ost:ost+32]` | | read word from memory at offset `ost` | -| 52 | MSTORE | 3[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost, val` | `.` | mem[ost:ost+32] := val | write a word to memory | -| 53 | MSTORE8 | 3[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost, val` | `.` | mem[ost] := val && 0xFF | write a single byte to memory | -| 54 | SLOAD | [A6](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a6-sload) | `key` | `storage[key]` | | read word from storage | -| 55 | SSTORE | [A7](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a7-sstore) | `key, val` | `.` | storage[key] := val | write word to storage | -| 56 | JUMP | 8 | `dst` | `.` | | `$pc := dst` mark that `pc` is only assigned if `dst` is a valid jumpdest | -| 57 | JUMPI | 10 | `dst, condition` | `.` | | `$pc := condition ? dst : $pc + 1` | -| 58 | PC | 2 | `.` | `$pc` | | program counter | -| 59 | MSIZE | 2 | `.` | `len(mem)` | | size of memory in current execution context, in bytes | -| 5A | GAS | 2 | `.` | `gasRemaining` | | | -| 5B | JUMPDEST | 1 | | | mark valid jump destination | a valid jump destination for example a jump destination not inside the push data | -| 5C | TLOAD | 100 | `key` | `tstorage[key]` | | 从瞬态存储中读取字 ([EIP-1153](https://eips.ethereum.org/EIPS/eip-1153)) | -| 5D | TSTORE | 100 | `key, val` | `.` | tstorage[key] := val | 向瞬态存储中写入字 ([EIP-1153](https://eips.ethereum.org/EIPS/eip-1153)) | -| 5E | MCOPY | 3+3\*字+[A0](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `dstOst, ost, len` | `.` | mem[dstOst] := mem[ost:ost+len] | 将内存从一个区域复制到另一个区域 ([EIP-5656](https://eips.ethereum.org/EIPS/eip-5656)) | -| 5F | PUSH0 | 2 | `.` | `uint8` | | push the constant value 0 onto stack | -| 60 | PUSH1 | 3 | `.` | `uint8` | | push 1-byte value onto stack | -| 61 | PUSH2 | 3 | `.` | `uint16` | | push 2-byte value onto stack | -| 62 | PUSH3 | 3 | `.` | `uint24` | | push 3-byte value onto stack | -| 63 | PUSH4 | 3 | `.` | `uint32` | | push 4-byte value onto stack | -| 64 | PUSH5 | 3 | `.` | `uint40` | | push 5-byte value onto stack | -| 65 | PUSH6 | 3 | `.` | `uint48` | | push 6-byte value onto stack | -| 66 | PUSH7 | 3 | `.` | `uint56` | | push 7-byte value onto stack | -| 67 | PUSH8 | 3 | `.` | `uint64` | | push 8-byte value onto stack | -| 68 | PUSH9 | 3 | `.` | `uint72` | | push 9-byte value onto stack | -| 69 | PUSH10 | 3 | `.` | `uint80` | | push 10-byte value onto stack | -| 6A | PUSH11 | 3 | `.` | `uint88` | | push 11-byte value onto stack | -| 6B | PUSH12 | 3 | `.` | `uint96` | | push 12-byte value onto stack | -| 6C | PUSH13 | 3 | `.` | `uint104` | | push 13-byte value onto stack | -| 6D | PUSH14 | 3 | `.` | `uint112` | | push 14-byte value onto stack | -| 6E | PUSH15 | 3 | `.` | `uint120` | | push 15-byte value onto stack | -| 6F | PUSH16 | 3 | `.` | `uint128` | | push 16-byte value onto stack | -| 70 | PUSH17 | 3 | `.` | `uint136` | | push 17-byte value onto stack | -| 71 | PUSH18 | 3 | `.` | `uint144` | | push 18-byte value onto stack | -| 72 | PUSH19 | 3 | `.` | `uint152` | | push 19-byte value onto stack | -| 73 | PUSH20 | 3 | `.` | `uint160` | | push 20-byte value onto stack | -| 74 | PUSH21 | 3 | `.` | `uint168` | | push 21-byte value onto stack | -| 75 | PUSH22 | 3 | `.` | `uint176` | | push 22-byte value onto stack | -| 76 | PUSH23 | 3 | `.` | `uint184` | | push 23-byte value onto stack | -| 77 | PUSH24 | 3 | `.` | `uint192` | | push 24-byte value onto stack | -| 78 | PUSH25 | 3 | `.` | `uint200` | | push 25-byte value onto stack | -| 79 | PUSH26 | 3 | `.` | `uint208` | | push 26-byte value onto stack | -| 7A | PUSH27 | 3 | `.` | `uint216` | | push 27-byte value onto stack | -| 7B | PUSH28 | 3 | `.` | `uint224` | | push 28-byte value onto stack | -| 7C | PUSH29 | 3 | `.` | `uint232` | | push 29-byte value onto stack | -| 7D | PUSH30 | 3 | `.` | `uint240` | | push 30-byte value onto stack | -| 7E | PUSH31 | 3 | `.` | `uint248` | | push 31-byte value onto stack | -| 7F | PUSH32 | 3 | `.` | `uint256` | | push 32-byte value onto stack | -| 80 | DUP1 | 3 | `a` | `a, a` | | clone 1st value on stack | -| 81 | DUP2 | 3 | `_, a` | `a, _, a` | | clone 2nd value on stack | -| 82 | DUP3 | 3 | `_, _, a` | `a, _, _, a` | | clone 3rd value on stack | -| 83 | DUP4 | 3 | `_, _, _, a` | `a, _, _, _, a` | | clone 4th value on stack | -| 84 | DUP5 | 3 | `..., a` | `a, ..., a` | | clone 5th value on stack | -| 85 | DUP6 | 3 | `..., a` | `a, ..., a` | | clone 6th value on stack | -| 86 | DUP7 | 3 | `..., a` | `a, ..., a` | | clone 7th value on stack | -| 87 | DUP8 | 3 | `..., a` | `a, ..., a` | | clone 8th value on stack | -| 88 | DUP9 | 3 | `..., a` | `a, ..., a` | | clone 9th value on stack | -| 89 | DUP10 | 3 | `..., a` | `a, ..., a` | | clone 10th value on stack | -| 8A | DUP11 | 3 | `..., a` | `a, ..., a` | | clone 11th value on stack | -| 8B | DUP12 | 3 | `..., a` | `a, ..., a` | | clone 12th value on stack | -| 8C | DUP13 | 3 | `..., a` | `a, ..., a` | | clone 13th value on stack | -| 8D | DUP14 | 3 | `..., a` | `a, ..., a` | | clone 14th value on stack | -| 8E | DUP15 | 3 | `..., a` | `a, ..., a` | | clone 15th value on stack | -| 8F | DUP16 | 3 | `..., a` | `a, ..., a` | | clone 16th value on stack | -| 90 | SWAP1 | 3 | `a, b` | `b, a` | | | -| 91 | SWAP2 | 3 | `a, _, b` | `b, _, a` | | | -| 92 | SWAP3 | 3 | `a, _, _, b` | `b, _, _, a` | | | -| 93 | SWAP4 | 3 | `a, _, _, _, b` | `b, _, _, _, a` | | | -| 94 | SWAP5 | 3 | `a, ..., b` | `b, ..., a` | | | -| 95 | SWAP6 | 3 | `a, ..., b` | `b, ..., a` | | | -| 96 | SWAP7 | 3 | `a, ..., b` | `b, ..., a` | | | -| 97 | SWAP8 | 3 | `a, ..., b` | `b, ..., a` | | | -| 98 | SWAP9 | 3 | `a, ..., b` | `b, ..., a` | | | -| 99 | SWAP10 | 3 | `a, ..., b` | `b, ..., a` | | | -| 9A | SWAP11 | 3 | `a, ..., b` | `b, ..., a` | | | -| 9B | SWAP12 | 3 | `a, ..., b` | `b, ..., a` | | | -| 9C | SWAP13 | 3 | `a, ..., b` | `b, ..., a` | | | -| 9D | SWAP14 | 3 | `a, ..., b` | `b, ..., a` | | | -| 9E | SWAP15 | 3 | `a, ..., b` | `b, ..., a` | | | -| 9F | SWAP16 | 3 | `a, ..., b` | `b, ..., a` | | | -| A0 | LOG0 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len` | `.` | | LOG0(memory[ost:ost+len-1]) | -| A1 | LOG1 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len, topic0` | `.` | | LOG1(memory[ost:ost+len-1], topic0) | -| A2 | LOG2 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len, topic0, topic1` | `.` | | LOG2(memory[ost:ost+len-1], topic0, topic1) | -| A3 | LOG3 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len, topic0, topic1, topic2` | `.` | | LOG3(memory[ost:ost+len-1], topic0, topic1, topic2) | -| A4 | LOG4 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len, topic0, topic1, topic2, topic3` | `.` | | LOG4(memory[ost:ost+len-1], topic0, topic1, topic2, topic3) | -| A5-EF | _invalid_ | | | | | | -| F0 | CREATE | [A9](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a9-create-operations) | `val, ost, len` | `addr` | | addr = keccak256(rlp([address(this), this.nonce])) | -| F1 | CALL | [AA](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-call-operations) | gas, addr, val, argOst, argLen, retOst, retLen | `success` | mem[retOst:retOst+retLen-1] := returndata | | -| F2 | CALLCODE | [AA](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-call-operations) | `gas, addr, val, argOst, argLen, retOst, retLen` | `success` | mem[retOst:retOst+retLen-1] = returndata | same as DELEGATECALL, but does not propagate original msg.sender and msg.value | -| F3 | 返回 | 0[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost, len` | `.` | | return mem[ost:ost+len-1] | -| F4 | DELEGATECALL | [AA](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-call-operations) | `gas, addr, argOst, argLen, retOst, retLen` | `success` | mem[retOst:retOst+retLen-1] := returndata | | -| F5 | CREATE2 | [A9](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a9-create-operations) | `val, ost, len, salt` | `addr` | | addr = keccak256(0xff ++ address(this) ++ salt ++ keccak256(mem[ost:ost+len-1]))[12:] | -| F6-F9 | _invalid_ | | | | | | -| FA | STATICCALL | [AA](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-call-operations) | `gas, addr, argOst, argLen, retOst, retLen` | `success` | mem[retOst:retOst+retLen-1] := returndata | | -| FB-FC | _invalid_ | | | | | | -| FD | 撤销 | 0[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost, len` | `.` | | revert(mem[ost:ost+len-1]) | -| FE | INVALID | [AF](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#af-invalid) | | | designated invalid opcode - [EIP-141](https://eips.ethereum.org/EIPS/eip-141) | | -| FF | SELFDESTRUCT | [AB](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#ab-selfdestruct) | `addr` | `.` | | 将所有以太币发送到 `addr`;如果在创建合约的同一交易中执行,它会销毁该合约 | +| 堆栈 | 名称 | 燃料 | 起始堆栈 | 最终堆栈 | 内存 / 存储 | 注释 | | +| :---: | :------------- | :---------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | +| 00 | STOP | 0 | | | | 中止执行 | | +| 01 | ADD | 3 | `a, b` | `a + b` | | (u)int256 加法,模 2\*\*256 | | +| 02 | MUL | 5 | `a, b` | `a * b` | | (u)int256 乘法,模 2\*\*256 | | +| 03 | SUB | 3 | `a, b` | `a - b` | | (u)int256 减法,模 2\*\*256 | | +| 04 | DIV | 5 | `a, b` | `a // b` | | uint256 除法 | | +| 05 | SDIV | 5 | `a, b` | `a // b` | | int256 除法 | | +| 06 | MOD | 5 | `a, b` | `a % b` | | uint256 模数 | | +| 07 | SMOD | 5 | `a, b` | `a % b` | | int256 模数 | | +| 08 | ADDMOD | 8 | `a, b, N` | `(a + b) % N` | | (u)int256 加法,模 N | | +| 09 | MULMOD | 8 | `a, b, N` | `(a * b) % N` | | (u)int256 乘法,模 N | | +| 0A | EXP | [A1](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a1-exp) | `a, b` | `a ** b` | | uint256 乘方,模 2\*\*256 | | +| 0B | SIGNEXTEND | 5 | `b, x` | `SIGNEXTEND(x, b)` | | 将 `x` 从 `(b+1)` 字节[符号扩展](https://wikipedia.org/wiki/Sign_extension)到 32 字节 | | +| 0C-0F | _无效_ | | | | | | | +| 10 | LT | 3 | `a, b` | `a < b` | | uint256 小于 | | +| 11 | GT | 3 | `a, b` | `a > b` | | uint256 大于 | | +| 12 | SLT | 3 | `a, b` | `a < b` | | int256 小于 | | +| 13 | SGT | 3 | `a, b` | `a > b` | | int256 大于 | | +| 14 | EQ | 3 | `a, b` | `a == b` | | (u)int256 相等 | | +| 15 | ISZERO | 3 | `a` | `a == 0` | | (u)int256 是否为零 | | +| 16 | AND | 3 | `a, b` | `a && b` | | 按位与 | | +| 17 | OR | 3 | `a, b` | `a \\|\\| b` | | 按位或 | | +| 18 | XOR | 3 | `a, b` | `a ^ b` | | 按位异或 | | +| 19 | NOT | 3 | `a` | `~a` | | 按位非 | | +| 1A | BYTE | 3 | `i, x` | `(x >> (248 - i * 8)) && 0xFF` | | 从左起,(u)int256 `x` 的第 `i` 个字节 | | +| 1B | SHL | 3 | `shift, val` | `val << shift` | | 左移 | | +| 1C | SHR | 3 | `shift, val` | `val >> shift` | | 逻辑右移 | | +| 1D | SAR | 3 | `shift, val` | `val >> shift` | | 算术右移 | | +| 1E-1F | _无效_ | | | | | | | +| 20 | KECCAK256 | [A2](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a2-sha3) | `ost, len` | `keccak256(mem[ost:ost+len-1])` | | keccak256 | | +| 21-2F | _无效_ | | | | | | | +| 30 | ADDRESS | 2 | `.` | `address(this)` | | 执行合约的地址 | | +| 31 | BALANCE | [A5](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a5-balance-extcodesize-extcodehash) | `addr` | `addr.balance` | | 余额,以 wei 为单位 | | +| 32 | ORIGIN | 2 | `.` | `tx.origin` | | 发起交易的地址 | | +| 33 | CALLER | 2 | `.` | `发送者` | | 消息发送者的地址 | | +| 34 | CALLVALUE | 2 | `.` | `msg.value` | | 消息值,以 wei 为单位 | | +| 35 | CALLDATALOAD | 3 | `idx` | `msg.data[idx:idx+32]` | | 从索引 `idx` 处的消息数据中读取字 | | +| 36 | CALLDATASIZE | 2 | `.` | `len(msg.data)` | | 消息数据的长度,以字节为单位 | | +| 37 | CALLDATACOPY | [A3](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a3-copy-operations) | `dstOst, ost, len` | `.` | mem[dstOst:dstOst+len-1] := msg.data[ost:ost+len-1] | 复制消息数据 | | +| 38 | CODESIZE | 2 | `.` | `len(this.code)` | | 执行合约代码的长度,以字节为单位 | | +| 39 | CODECOPY | [A3](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a3-copy-operations) | `dstOst, ost, len` | `.` | | mem[dstOst:dstOst+len-1] := this.code[ost:ost+len-1] | 复制执行合约的字节码 | +| 3A | GASPRICE | 2 | `.` | `tx.gasprice` | | 交易的燃料价格,以 wei/单位燃料计 [\*\*](https://eips.ethereum.org/EIPS/eip-1559#gasprice) | | +| 3B | EXTCODESIZE | [A5](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a5-balance-extcodesize-extcodehash) | `addr` | `len(addr.code)` | | 地址处代码的大小,以字节为单位 | | +| 3C | EXTCODECOPY | [A4](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a4-extcodecopy) | `addr, dstOst, ost, len` | `.` | mem[dstOst:dstOst+len-1] := addr.code[ost:ost+len-1] | 从 `addr` 复制代码 | | +| 3D | RETURNDATASIZE | 2 | `.` | `size` | | 上次外部调用的返回数据的大小,以字节为单位 | | +| 3E | RETURNDATACOPY | [A3](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a3-copy-operations) | `dstOst, ost, len` | `.` | mem[dstOst:dstOst+len-1] := returndata[ost:ost+len-1] | 复制上次外部调用的返回数据 | | +| 3F | EXTCODEHASH | [A5](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a5-balance-extcodesize-extcodehash) | `addr` | `哈希` | | 哈希 = addr.exists ? keccak256(addr.code) : 0 | | +| 40 | BLOCKHASH | 20 | `blockNum` | `blockHash(blockNum)` | | | | +| 41 | COINBASE | 2 | `.` | `block.coinbase` | | 当前区块提议者地址 | | +| 42 | TIMESTAMP | 2 | `.` | `区块时间戳` | | 当前区块的时间戳 | | +| 43 | NUMBER | 2 | `.` | `block.number` | | 当前区块的编号 | | +| 44 | PREVRANDAO | 2 | `.` | `randomness beacon` | | 随机信标 | | +| 45 | GASLIMIT | 2 | `.` | `block.gaslimit` | | 当前区块的燃料限制 | | +| 46 | CHAINID | 2 | `.` | `chain_id` | | 将当前[链 id](https://eips.ethereum.org/EIPS/eip-155) 推入堆栈 | | +| 47 | SELFBALANCE | 5 | `.` | `address(this).balance` | | 执行合约的余额,以 wei 为单位 | | +| 48 | BASEFEE | 2 | `.` | `block.basefee` | | 当前区块的基本费用 | | +| 49 | BLOBHASH | 3 | `idx` | `tx.blob_versioned_hashes[idx]` | | [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) | | +| 4A | BLOBBASEFEE | 2 | `.` | `block.blobbasefee` | | 当前区块的 blob 基本费用 ([EIP-7516](https://eips.ethereum.org/EIPS/eip-7516)) | | +| 4B-4F | _无效_ | | | | | | | +| 50 | POP | 2 | `_anon` | `.` | | 从堆栈顶部移除一项并丢弃 | | +| 51 | MLOAD | 3[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost` | `mem[ost:ost+32]` | | 从内存偏移量 `ost` 处读取字 | | +| 52 | MSTORE | 3[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost, val` | `.` | mem[ost:ost+32] := val | 向内存写入一个字 | | +| 53 | MSTORE8 | 3[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost, val` | `.` | mem[ost] := val && 0xFF | 向内存写入单个字节 | | +| 54 | SLOAD | [A6](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a6-sload) | `key` | `storage[key]` | | 从存储中读取字 | | +| 55 | SSTORE | [A7](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a7-sstore) | `key, val` | `.` | storage[key] := val | 向存储中写入字 | | +| 56 | JUMP | 8 | `dst` | `.` | | `$pc := dst` 标记 `pc` 仅在 `dst` 是一个有效的 jumpdest 时才被赋值。 | | +| 57 | JUMPI | 10 | `dst, condition` | `.` | | `$pc := condition ?` dst : $pc + 1` | | +| 58 | PC | 2 | `.` | `$pc` | | 程序计数器 | | +| 59 | MSIZE | 2 | `.` | `len(mem)` | | 当前执行上下文中内存的大小,以字节为单位 | | +| 5A | GAS | 2 | `.` | `gasRemaining` | | | | +| 5B | JUMPDEST | 1 | | | 标记有效的跳转目标 | 一个有效的跳转目标,例如一个不在推送数据内的跳转目标 | | +| 5C | TLOAD | 100 | `key` | `tstorage[key]` | | 从瞬时存储中读取字 ([EIP-1153](https://eips.ethereum.org/EIPS/eip-1153)) | | +| 5D | TSTORE | 100 | `key, val` | `.` | tstorage[key] := val | 向瞬时存储中写入字 ([EIP-1153](https://eips.ethereum.org/EIPS/eip-1153)) | | +| 5E | MCOPY | 3+3\*words+[A0](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `dstOst, ost, len` | `.` | mem[dstOst] := mem[ost:ost+len] | 将内存从一个区域复制到另一个区域 ([EIP-5656](https://eips.ethereum.org/EIPS/eip-5656)) | | +| 5F | PUSH0 | 2 | `.` | `uint8` | | push the constant value 0 onto stack | | +| 60 | PUSH1 | 3 | `.` | `uint8` | | 将 1 字节值推入堆栈 | | +| 61 | PUSH2 | 3 | `.` | `uint16` | | 将 2 字节值推入堆栈 | | +| 62 | PUSH3 | 3 | `.` | `uint24` | | 将 3 字节值推入堆栈 | | +| 63 | PUSH4 | 3 | `.` | `uint32` | | 将 4 字节值推入堆栈 | | +| 64 | PUSH5 | 3 | `.` | `uint40` | | 将 5 字节值推入堆栈 | | +| 65 | PUSH6 | 3 | `.` | `uint48` | | 将 6 字节值推入堆栈 | | +| 66 | PUSH7 | 3 | `.` | `uint56` | | 将 7 字节值推入堆栈 | | +| 67 | PUSH8 | 3 | `.` | `uint64` | | 将 8 字节值推入堆栈 | | +| 68 | PUSH9 | 3 | `.` | `uint72` | | 将 9 字节值推入堆栈 | | +| 69 | PUSH10 | 3 | `.` | `uint80` | | 将 10 字节值推入堆栈 | | +| 6A | PUSH11 | 3 | `.` | `uint88` | | 将 11 字节值推入堆栈 | | +| 6B | PUSH12 | 3 | `.` | `uint96` | | 将 12 字节值推入堆栈 | | +| 6C | PUSH13 | 3 | `.` | `uint104` | | 将 13 字节值推入堆栈 | | +| 6D | PUSH14 | 3 | `.` | `uint112` | | 将 14 字节值推入堆栈 | | +| 6E | PUSH15 | 3 | `.` | `uint120` | | 将 15 字节值推入堆栈 | | +| 6F | PUSH16 | 3 | `.` | `uint128` | | 将 16 字节值推入堆栈 | | +| 70 | PUSH17 | 3 | `.` | `uint136` | | 将 17 字节值推入堆栈 | | +| 71 | PUSH18 | 3 | `.` | `uint144` | | 将 18 字节值推入堆栈 | | +| 72 | PUSH19 | 3 | `.` | `uint152` | | 将 19 字节值推入堆栈 | | +| 73 | PUSH20 | 3 | `.` | `uint160` | | 将 20 字节值推入堆栈 | | +| 74 | PUSH21 | 3 | `.` | `uint168` | | 将 21 字节值推入堆栈 | | +| 75 | PUSH22 | 3 | `.` | `uint176` | | 将 22 字节值推入堆栈 | | +| 76 | PUSH23 | 3 | `.` | `uint184` | | 将 23 字节值推入堆栈 | | +| 77 | PUSH24 | 3 | `.` | `uint192` | | 将 24 字节值推入堆栈 | | +| 78 | PUSH25 | 3 | `.` | `uint200` | | 将 25 字节值推入堆栈 | | +| 79 | PUSH26 | 3 | `.` | `uint208` | | 将 26 字节值推入堆栈 | | +| 7A | PUSH27 | 3 | `.` | `uint216` | | 将 27 字节值推入堆栈 | | +| 7B | PUSH28 | 3 | `.` | `uint224` | | 将 28 字节值推入堆栈 | | +| 7C | PUSH29 | 3 | `.` | `uint232` | | 将 29 字节值推入堆栈 | | +| 7D | PUSH30 | 3 | `.` | `uint240` | | 将 30 字节值推入堆栈 | | +| 7E | PUSH31 | 3 | `.` | `uint248` | | 将 31 字节值推入堆栈 | | +| 7F | PUSH32 | 3 | `.` | `uint256` | | 将 32 字节值推入堆栈 | | +| 80 | DUP1 | 3 | `a` | `a, a` | | 克隆堆栈上的第 1 个值 | | +| 81 | DUP2 | 3 | `_, a` | `a, _, a` | | 克隆堆栈上的第 2 个值 | | +| 82 | DUP3 | 3 | `_, _, a` | `a, _, _, a` | | 克隆堆栈上的第 3 个值 | | +| 83 | DUP4 | 3 | `_, _, _, a` | `a, _, _, _, a` | | 克隆堆栈上的第 4 个值 | | +| 84 | DUP5 | 3 | `..., a` | `a, ..., a` | | 克隆堆栈上的第 5 个值 | | +| 85 | DUP6 | 3 | `..., a` | `a, ..., a` | | 克隆堆栈上的第 6 个值 | | +| 86 | DUP7 | 3 | `..., a` | `a, ..., a` | | 克隆堆栈上的第 7 个值 | | +| 87 | DUP8 | 3 | `..., a` | `a, ..., a` | | 克隆堆栈上的第 8 个值 | | +| 88 | DUP9 | 3 | `..., a` | `a, ..., a` | | 克隆堆栈上的第 9 个值 | | +| 89 | DUP10 | 3 | `..., a` | `a, ..., a` | | 克隆堆栈上的第 10 个值 | | +| 8A | DUP11 | 3 | `..., a` | `a, ..., a` | | 克隆堆栈上的第 11 个值 | | +| 8B | DUP12 | 3 | `..., a` | `a, ..., a` | | 克隆堆栈上的第 12 个值 | | +| 8C | DUP13 | 3 | `..., a` | `a, ..., a` | | 克隆堆栈上的第 13 个值 | | +| 8D | DUP14 | 3 | `..., a` | `a, ..., a` | | 克隆堆栈上的第 14 个值 | | +| 8E | DUP15 | 3 | `..., a` | `a, ..., a` | | 克隆堆栈上的第 15 个值 | | +| 8F | DUP16 | 3 | `..., a` | `a, ..., a` | | 克隆堆栈上的第 16 个值 | | +| 90 | SWAP1 | 3 | `a, b` | `b, a` | | | | +| 91 | SWAP2 | 3 | `a, _, b` | `b, _, a` | | | | +| 92 | SWAP3 | 3 | `a, _, _, b` | `b, _, _, a` | | | | +| 93 | SWAP4 | 3 | `a, _, _, _, b` | `b, _, _, _, a` | | | | +| 94 | SWAP5 | 3 | `a, ..., b` | `b, ..., a` | | | | +| 95 | SWAP6 | 3 | `a, ..., b` | `b, ..., a` | | | | +| 96 | SWAP7 | 3 | `a, ..., b` | `b, ..., a` | | | | +| 97 | SWAP8 | 3 | `a, ..., b` | `b, ..., a` | | | | +| 98 | SWAP9 | 3 | `a, ..., b` | `b, ..., a` | | | | +| 99 | SWAP10 | 3 | `a, ..., b` | `b, ..., a` | | | | +| 9A | SWAP11 | 3 | `a, ..., b` | `b, ..., a` | | | | +| 9B | SWAP12 | 3 | `a, ..., b` | `b, ..., a` | | | | +| 9C | SWAP13 | 3 | `a, ..., b` | `b, ..., a` | | | | +| 9D | SWAP14 | 3 | `a, ..., b` | `b, ..., a` | | | | +| 9E | SWAP15 | 3 | `a, ..., b` | `b, ..., a` | | | | +| 9F | SWAP16 | 3 | `a, ..., b` | `b, ..., a` | | | | +| A0 | LOG0 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len` | `.` | | LOG0(memory[ost:ost+len-1]) | | +| A1 | LOG1 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len, topic0` | `.` | | LOG1(memory[ost:ost+len-1], topic0) | | +| A2 | LOG2 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len, topic0, topic1` | `.` | | LOG2(memory[ost:ost+len-1], topic0, topic1) | | +| A3 | LOG3 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len, topic0, topic1, topic2` | `.` | | LOG3(memory[ost:ost+len-1], topic0, topic1, topic2) | | +| A4 | LOG4 | [A8](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations) | `ost, len, topic0, topic1, topic2, topic3` | `.` | | LOG4(memory[ost:ost+len-1], topic0, topic1, topic2, topic3) | | +| A5-EF | _无效_ | | | | | | | +| F0 | CREATE | [A9](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a9-create-operations) | `val, ost, len` | `addr` | | addr = keccak256(rlp([address(this), this.nonce])) | | +| F1 | CALL | [AA](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-call-operations) | 燃料, addr, val, argOst, argLen, retOst, retLen | `success` | mem[retOst:retOst+retLen-1] := returndata | | | +| F2 | CALLCODE | [AA](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-call-operations) | `燃料, addr, val, argOst, argLen, retOst, retLen` | `success` | mem[retOst:retOst+retLen-1] = returndata | 与 DELEGATECALL 相同,但不传播原始的 msg.sender 和 msg.value | | +| F3 | RETURN | 0[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost, len` | `.` | | return mem[ost:ost+len-1] | | +| F4 | DELEGATECALL | [AA](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-call-operations) | `燃料, addr, argOst, argLen, retOst, retLen` | `success` | mem[retOst:retOst+retLen-1] := returndata | | | +| F5 | CREATE2 | [A9](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a9-create-operations) | `val, ost, len, salt` | `addr` | | addr = keccak256(0xff ++ address(this) ++ salt ++ keccak256(mem[ost:ost+len-1]))[12:] | | +| F6-F9 | _无效_ | | | | | | | +| FA | STATICCALL | [AA](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-call-operations) | `燃料, addr, argOst, argLen, retOst, retLen` | `success` | mem[retOst:retOst+retLen-1] := returndata | | | +| FB-FC | _无效_ | | | | | | | +| FD | REVERT | 0[\*](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion) | `ost, len` | `.` | | revert(mem[ost:ost+len-1]) | | +| FE | INVALID | [AF](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#af-invalid) | | | 指定的无效操作码 - [EIP-141](https://eips.ethereum.org/EIPS/eip-141) | | | +| FF | SELFDESTRUCT | [AB](https://github.com/wolflo/evm-opcodes/blob/main/gas.md#ab-selfdestruct) | `addr` | `.` | | 将所有 ETH 发送到 `addr`;如果在创建合约的同一交易中执行,它会销毁该合约 | | diff --git a/public/content/translations/zh/developers/docs/frameworks/index.md b/public/content/translations/zh/developers/docs/frameworks/index.md index f30fefc21f1..65d4a324fef 100644 --- a/public/content/translations/zh/developers/docs/frameworks/index.md +++ b/public/content/translations/zh/developers/docs/frameworks/index.md @@ -1,76 +1,76 @@ --- -title: 去中心化应用程序开发框架 -description: 探索框架的优势并比较现有的选项。 +title: "去中心化应用程序开发框架" +description: "探索框架的优势并比较现有的选项。" lang: zh --- -## 框架介绍 {#introduction-to-frameworks} +## 框架简介 {#introduction-to-frameworks} 构建一个完整的去中心化应用程序需要不同的技术。 软件框架包括许多需要的功能,或提供简单的插件系统来选择你需要的工具。 这些框架带有很多非常规的功能,比如: -- 编一个本地区块链的程序功能。 +- 编写一个本地区块链程序的功能。 - 编辑和测试你智能合约的实用工具。 -- 客户端开发附加组件,以在同一项目/仓库中构建你的面向用户的应用。 -- 无论是在本地运行的实例,还是在以太坊的公共网络之一,可以连接到以太网并且部署合约的配置。 -- 去中心化的应用分发 - 与诸如 IPFS 之类的存储选项集成。 +- 客户端开发附加组件,用于在同一项目/代码库中构建面向用户的应用程序。 +- 用于连接以太坊网络和部署合约的配置,无论是连接到本地运行的实例,还是以太坊的某个公共网络。 +- 去中心化应用程序分发——与 IPFS 等存储方案集成。 -## 前置要求 {#prerequisites} +## 前提条件 {#prerequisites} -在更深入介绍这个框架之前,我们推荐你先阅读下面对于[去中心化应用程序](/developers/docs/dapps/)的简介以及[以太坊堆栈](/developers/docs/ethereum-stack/)。 +在深入了解框架之前,我们建议你先阅读我们对[去中心化应用程序](/developers/docs/dapps/)和[以太坊堆栈](/developers/docs/ethereum-stack/)的介绍。 -## 可用的框架 {#available-frameworks} +## 可用框架 {#available-frameworks} -**Foundry** - **_Foundry 是一款快速、便携、模块化的以太坊应用程序开发工具包_** +**Foundry** - **_Foundry 是一款极其快速、可移植的模块化工具包,用于以太坊应用程序开发_** - [安装 Foundry](https://book.getfoundry.sh/) -- [Foundry 手册](https://book.getfoundry.sh/) +- [Foundry 指南](https://book.getfoundry.sh/) - [Telegram 上的 Foundry 社区聊天](https://t.me/foundry_support) -- [强大的 Foundry](https://github.com/crisgarner/awesome-foundry) +- [Awesome Foundry](https://github.com/crisgarner/awesome-foundry) -**安全帽 -** **_ 面向专业人员的以太坊开发环境。_** +**Hardhat -** **_面向专业人士的以太坊开发环境。_** - [hardhat.org](https://hardhat.org) - [GitHub](https://github.com/nomiclabs/hardhat) -**Ape -** **_ 面向 Pythonista、数据科学家和安全专业人员的智能合约开发工具。_** +**Ape -** **_面向 Python 爱好者、数据科学家和安全专业人士的智能合约开发工具。_** -- [相关文档](https://docs.apeworx.io/ape/stable/) +- [文档](https://docs.apeworx.io/ape/stable/) - [GitHub](https://github.com/ApeWorX/ape) -**Web3j -** **_ Java 虚拟机上的区块链应用程序开发平台。_ ** +**Web3j -** **_一个用于在 JVM 上开发区块链应用程序的平台。_** - [主页](https://www.web3labs.com/web3j-sdk) -- [相关文档](https://docs.web3j.io) +- [文档](https://docs.web3j.io) - [GitHub](https://github.com/web3j/web3j) -**Ethers-kt - ****_ 面向基于以太坊虚拟机区块链的高性能异步 Kotlin/Java/Android 库。_** +**ethers-kt -** **_用于基于 EVM 的区块链的异步、高性能 Kotlin/Java/Android 库。_** - [GitHub](https://github.com/Kr1ptal/ethers-kt) - [示例](https://github.com/Kr1ptal/ethers-kt/tree/master/examples) - [Discord](https://discord.gg/rx35NzQGSb) -**Create Eth App -** **_ 使用一个命令创建以太坊支持的应用程序。 提供众多 UI 框架和去中心化金融模板供选择。_** +**Create Eth App -** **_通过一个命令创建以太坊赋能的应用程序。 提供多种 UI 框架和 DeFi 模板供您选择。_** - [GitHub](https://github.com/paulrberg/create-eth-app) - [模板](https://github.com/PaulRBerg/create-eth-app/tree/develop/templates) -**Scaffold-Eth -** **_Ethers.js + 安全帽 + React 组件和 web3 钩子函数:构建智能合约支持的去中心化应用程序所需的一切资源,这里都有。_** +**Scaffold-Eth -** **_Ethers.js + Hardhat + 用于 web3 的 React 组件和钩子:开始构建由智能合约驱动的去中心化应用程序所需的一切。_** - [GitHub](https://github.com/scaffold-eth/scaffold-eth-2) -**Tenderly -** **_Web3 开发平台,可帮助区块链开发者构建、测试、调试、监测和操作智能合约并改善去中心化应用程序的用户体验。_** +**Tenderly -** **_Web3 开发平台,区块链开发者能够用它来构建、测试、调试、监控和运营智能合约,并改善去中心化应用程序的用户体验。_** - [网站](https://tenderly.co/) -- [相关文档](https://docs.tenderly.co/) +- [文档](https://docs.tenderly.co/) -**The Graph -** **_ 用于高效查询区块链数据的图表。_** +**The Graph -** **_用于高效查询区块链数据的 The Graph。_** - [网站](https://thegraph.com/) - [教程](/developers/tutorials/the-graph-fixing-web3-data-querying/) -**Alchemy -** **_以太坊开发平台_** +**Alchemy -** **_以太坊开发平台。_** - [alchemy.com](https://www.alchemy.com/) - [GitHub](https://github.com/alchemyplatform) @@ -82,68 +82,68 @@ lang: zh - [GitHub](https://github.com/node-real) - [Discord](https://discord.gg/V5k5gsuE) -**thirdweb SDK -** **_使用我们强大的软件开发工具包和命令行接口,构建能够与你的智能合约交互的 web3 应用程序。_** +**thirdweb SDK -** **_使用我们强大的软件开发工具包和命令行界面,构建能够与你的智能合约交互的 web3 应用程序。_** -- [相关文档](https://portal.thirdweb.com/sdk/) +- [文档](https://portal.thirdweb.com/sdk/) - [GitHub](https://github.com/thirdweb-dev/) -**Chainstack -** **_Web3(以太坊和其他区块链)开发平台。_** +**Chainstack -** **_Web3(以太坊及其他)开发平台。_** - [chainstack.com](https://www.chainstack.com/) - [GitHub](https://github.com/chainstack) - [Discord](https://discord.gg/BSb5zfp9AT) -**Crossmint -** **_企业级 Web3 开发平台,允许你在各大链以太坊虚拟机链(及其他链)上构建非同质化代币应用程序。_** +**Crossmint -** **_企业级 web3 开发平台,允许你在所有主流 EVM 链(及其他链)上构建 NFT 应用程序。_** - [网站](https://www.crossmint.com) -- [相关文档](https://docs.crossmint.com) +- [文档](https://docs.crossmint.com) - [Discord](https://discord.com/invite/crossmint) -**Brownie -** **_ 基于 Python 的开发环境和测试框架。_** +**Brownie -** **_基于 Python 的开发环境和测试框架。_** -- [相关文档](https://eth-brownie.readthedocs.io/en/latest/) +- [文档](https://eth-brownie.readthedocs.io/en/latest/) - [GitHub](https://github.com/eth-brownie/brownie) - **Brownie 当前未维护** -**OpenZeppelin SDK -** **_终极智能合约工具包:一套帮助你开发、编译、升级、部署智能合约并与之交互的工具。_** +**OpenZeppelin SDK -** **_终极智能合约工具包:一套可帮助你开发、编译、升级、部署智能合约并与之交互的工具。_** -- [OpenZeppelin SDK](https://openzeppelin.com/sdk/) +- [OpenZeppelin Defender SDK](https://docs.openzeppelin.com/defender/sdk) - [GitHub](https://github.com/OpenZeppelin/openzeppelin-sdk) - [社区论坛](https://forum.openzeppelin.com/c/support/17) - **OpenZeppelin SDK 开发已结束** -**Catapulta -** **_多链智能合约部署工具,在区块浏览器中自动执行验证,追踪已部署的智能合约并分享部署报告,使 Foundry 和 Hardhat 项目即插即用。_** +**Catapulta -** **_多链智能合约部署工具,可在区块浏览器中自动验证,跟踪已部署的智能合约并共享部署报告,为 Foundry 和 Hardhat 项目提供即插即用功能。_** - [网站](https://catapulta.sh/) -- [相关文档](https://catapulta.sh/docs) +- [文档](https://catapulta.sh/docs) - [Github](https://github.com/catapulta-sh) -**Covalent - ****_适用于 200 多条链的丰富区块链应用程序接口。_** +**GoldRush (由 Covalent 提供支持) -** **_GoldRush 为开发者、分析师和企业提供最全面的区块链数据 API 套件。 无论你是在构建 DeFi 看板、钱包、交易机器人、人工智能代理还是合规平台,数据 API 都能让你快速、准确且对开发者友好地访问所需的基本链上数据_** -- [covalenthq.com](https://www.covalenthq.com/) -- [相关文档](https://www.covalenthq.com/docs/api/) +- [网站](https://goldrush.dev/) +- [文档](https://goldrush.dev/docs/chains/ethereum) - [GitHub](https://github.com/covalenthq) - [Discord](https://www.covalenthq.com/discord/) -**Wake -** **_用于合约测试、模糊测试、部署、漏洞扫描和代码导航的一体化 Python 框架。_** +**Wake -** **_集合约测试、模糊测试、部署、漏洞扫描和代码导航于一体的 Python 框架。_** - [主页](https://getwake.io/) -- [相关文档](https://ackeeblockchain.com/wake/docs/latest/) +- [文档](https://ackeeblockchain.com/wake/docs/latest/) - [GitHub](https://github.com/Ackee-Blockchain/wake) -- [VS Code 扩展程序](https://marketplace.visualstudio.com/items?itemName=AckeeBlockchain.tools-for-solidity) +- [VS Code 扩展](https://marketplace.visualstudio.com/items?itemName=AckeeBlockchain.tools-for-solidity) -**Veramo -** **_开源、模块化且不受限的框架,使去中心化应用程序开发者能够轻松在其应用程序内构建去中心化身份和可验证凭证。_** +**Veramo -** **_一个开源、模块化、不限平台的框架,可让去中心化应用程序的开发者轻松地在其应用程序中构建去中心化身份和可验证凭证。_** - [主页](https://veramo.io/) -- [相关文档](https://veramo.io/docs/basics/introduction) +- [文档](https://veramo.io/docs/basics/introduction) - [GitHub](https://github.com/uport-project/veramo) - [Discord](https://discord.com/invite/FRRBdjemHV) -- [NPM 软件包](https://www.npmjs.com/package/@veramo/core) +- [NPM 包](https://www.npmjs.com/package/@veramo/core) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [设置本地开发环境](/developers/local-environment/) diff --git a/public/content/translations/zh/developers/docs/gas/index.md b/public/content/translations/zh/developers/docs/gas/index.md index 8e2cf056a6b..49cb35281f0 100644 --- a/public/content/translations/zh/developers/docs/gas/index.md +++ b/public/content/translations/zh/developers/docs/gas/index.md @@ -1,7 +1,7 @@ --- -title: 燃料和费用 +title: "燃料和费用" metaTitle: "以太坊燃料和费用:技术概览" -description: +description: "了解以太坊燃料费用,包括它们的计算方式,以及它们在网络安全和交易处理中所扮演的角色。" lang: zh --- @@ -9,7 +9,7 @@ Gas 对以太坊网络至关重要。 正是这种燃料使它能够运行,正 ## 前提条件 {#prerequisites} -为了更好地理解此页面,推荐先阅读[交易](/developers/docs/transactions/)和 [EVM](/developers/docs/evm/)。 +为了更好地理解本页内容,建议您先阅读有关[交易](/developers/docs/transactions/)和 [EVM](/developers/docs/evm/) 的内容。 ## 什么是燃料? {#what-is-gas} @@ -17,80 +17,85 @@ Gas 对以太坊网络至关重要。 正是这种燃料使它能够运行,正 由于每笔以太坊交易都需要使用计算资源来执行,因此必须为这些资源付费,以确保以太坊不容易受到垃圾信息的攻击,并且不会陷入无限的计算循环。 计算费用以燃料费的形式支付。 -燃料费是**用于执行某些操作的燃料数量,乘以每单位燃料的成本**。 无论交易成功与否,都要支付燃料费。 +燃料费是**指执行某项操作所用的燃料量,乘以每单位燃料的成本**。 无论交易成功与否,都要支付燃料费。 -![显示以太坊虚拟机操作所需燃料的图表](./gas.png) _示意图节选自[以太坊虚拟机图解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![一张图表,显示 EVM 操作中哪里需要燃料](./gas.png) +_图表改编自 [《图解以太坊虚拟机》](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ 燃料费必须用以太坊的本币支付,即以太币 (ETH)。 燃料通常以 gwei 计价,gwei 是以太币的一种计量单位。 一个 gwei 等于一个以太币的十亿分之一(0.000000001 个以太币,或 10-9 个以太币)。 比如,你可以说你的燃料费是 1 gwei,而不说 0.000000001 个以太币。 -"Gwei" 是 "giga-wei" 的缩写,意思是 “十亿个 wei”。 一个 gwei 等于十亿个 wei。 Wei 本身(以 [b-money](https://www.investopedia.com/terms/b/bmoney.asp) 的发明者 [Wei Dai](https://wikipedia.org/wiki/Wei_Dai) 的名字命名)是以太币的最小单位。 +"Gwei" 是 "giga-wei" 的缩写,意思是 “十亿个 wei”。 一个 gwei 等于十亿个 wei。 Wei(得名于 [b-money](https://www.investopedia.com/terms/b/bmoney.asp) 的创建者[戴伟](https://wikipedia.org/wiki/Wei_Dai))是以太币 (ETH) 的最小单位。 ## 如何计算燃料费? {#how-are-gas-fees-calculated} 当提交交易时,你可以设置你愿意支付的燃料数量。 通过提供一定数量的燃料,你出价将你的交易添加到下一个区块中。 如果你提供的燃料太少,验证者就不太可能选择添加你的交易,这意味着你的交易可能会延迟执行或不会被执行。 如果提供太多,你可能浪费一些以太币。 那么,怎么知道你应该支付多少燃料费呢? -你支付的总燃料费分为两部分:`base fee` 和 `priority fee`(小费)。 +你支付的总燃料费分为两个部分:`基本费用`和`优先费`(小费)。 -`Base fee` 由协议设定——你必须至少支付这些金额,然后你的交易才会被视为有效。 `Priority fee` 是基础费以外的小费,它可以吸引验证者选择将你的交易添加到下一个区块。 +`基本费用`由协议设置——你必须至少支付这笔费用,你的交易才会被视为有效。 `优先费`是你添加到基本费用中的小费,用于激励验证者,以便他们将你的交易打包到下一个区块中。 -只支付 `base fee` 的交易从技术上讲是有效的,但不太可能被添加到区块,因为它没有激励验证者优先选择它而不是其他交易。 “合适的” `priority` 费由发送交易时的网络使用情况决定——如果有大量需求,那么你可能不得不将你的 `priority` 费设置得更高;但当需求较少时,你也可以减少该费用。 +只支付`基本费用`的交易在技术上是有效的,但不太可能被打包,因为它没有激励验证者优先选择它,而不是其他任何交易。 “正确的”`优先`费由你发送交易时的网络使用情况决定——如果需求量大,你可能需要设置更高的`优先`费,但当需求量较少时,你可以支付更少的费用。 例如,假设 Jordan 要向 Taylor 支付 1 个以太币。 一笔以太币转账需要 21,000 单位的燃料,基础费是10 gwei。 Jordan 支付了 2 gwei 作为小费。 总费用等于: -`使用的燃料单位数 *(基础费 + 优先费)` +`使用的燃料单位 * (基本费用 + 优先费)` -其中 `base fee` 由协议设置,`priority fee` 是用户设置的支付给验证者的小费。 +其中 `基本费用` 是协议设定的值,`优先费`是用户设定给验证者的小费。 -即 `21,000 * (10 + 2) = 252,000 gwei`(0.000252 个以太币)。 +例如,`21,000 * (10 + 2) = 252,000 gwei` (0.000252 ETH)。 -当 Jordan 转账时,将从 Jordan 帐户中扣除 1.000252 个以太币。 Taylor 的帐户增加 1.0000 个以太币。 验证者收到价值 0.000042 个以太币的小费。 0.00021 个以太币的 `base fee` 被销毁。 +当 Jordan 转账时,将从 Jordan 帐户中扣除 1.000252 个以太币。 Taylor 的帐户增加 1.0000 个以太币。 验证者收到价值 0.000042 个以太币的小费。 0.00021 ETH 的`基本费用`被销毁。 -### 基础费 {#base-fee} +### 基本费用 {#base-fee} -每个区块都有一个基础费作为底价。 要想有资格添加到区块中,燃料费出价必须至少等于基础费。 基础费独立于当前区块计算,是由当前区块之前的区块决定的,这使得用户更容易预测交易费。 在创建区块时,它的**基础费将被“销毁”**并退出流通。 +每个区块都有一个基础费作为底价。 要想有资格添加到区块中,燃料费出价必须至少等于基础费。 基本费用的计算独立于当前区块,而是由它之前的区块决定,这使得用户更容易预测交易费。 创建区块时,这笔**基本费用将被“销毁”**,并退出流通。 -基础费由一个公式计算得出,该公式将上一个区块的大小(所有交易中使用的燃料数量)与目标大小进行比较。 如果超过目标区块大小,每个区块的基础费将最多增加 12.5%。 这种指数级增长使得区块大小无限期保持高位在经济上不可行。 +`基本费用`由一个公式计算得出,该公式将上一个区块的大小(所有交易使用的燃料总量)与目标大小(燃料限制的一半)进行比较。 如果区块大小分别高于或低于目标区块大小,则每个区块的基本费用将最多增加或减少 12.5%。 这种指数级增长使得区块大小无限期保持高位在经济上不可行。 -| 区块编号 | 已包含燃料 | 费用增加 | 当前基本费用 | -| ---- | -----:| -----:| ----------:| -| 1 | 15M | 0% | 100 gwei | -| 2 | 30M | 0% | 100 gwei | -| 3 | 30M | 12.5% | 112.5 gwei | -| 4 | 30M | 12.5% | 126.6 gwei | -| 5 | 30M | 12.5% | 142.4 gwei | -| 6 | 30M | 12.5% | 160.2 gwei | -| 7 | 30M | 12.5% | 180.2 gwei | -| 8 | 30M | 12.5% | 202.7 gwei | +| 区块编号 | 已包含燃料 | 费用增加 | 当前基本费用 | +| ---- | ----: | --------------------: | -------------------------: | +| 1 | 18M | 0% | 100 gwei | +| 2 | 36M | 0% | 100 gwei | +| 3 | 36M | 12.5% | 112.5 gwei | +| 4 | 36M | 12.5% | 126.6 gwei | +| 5 | 36M | 12.5% | 142.4 gwei | +| 6 | 36M | 12.5% | 160.2 gwei | +| 7 | 36M | 12.5% | 180.2 gwei | +| 8 | 36M | 12.5% | 202.7 gwei | -根据以上表格,要在 9 号区块创建交易,钱包会让用户明确知晓:要将交易添加到下一个区块的**最高基础费**等于 `current base fee * 112.5%` 或 `202.7 gwei * 112.5% = 228.1 gwei`。 +上表中使用 3600 万作为燃料限制来举例说明。 根据这个例子,要在第 9 号区块上创建交易,钱包会明确告知用户,要添加到下一个区块的**最高基本费用**是`当前基本费用 * 112.5%` 或 `202.7 gwei * 112.5% = 228.1 gwei`。 还请注意,考虑到完整区块前的基础费增加速度很快,我们不大可能看到它长时间处于峰值状态。 -| 区块编号 | 已包含燃料 | 费用增加 | 当前基本费用 | -| ---- | -----:| -----:| ---------------:| -| 30 | 30M | 12.5% | 2705.6 gwei | -| ... | ... | 12.5% | ... | -| 50 | 30M | 12.5% | 28531.3 gwei | -| ... | ... | 12.5% | ... | -| 100 | 30M | 12.5% | 10302608.6 gwei | +| 区块编号 | 已包含燃料 | 费用增加 | 当前基本费用 | +| --------------------------------------------------- | --------------------------------------------------: | --------------------: | --------------------------------------------------: | +| 30 | 36M | 12.5% | 2705.6 gwei | +| ... | ... | 12.5% | ... | +| 50 | 36M | 12.5% | 28531.3 gwei | +| ... | ... | 12.5% | ... | +| 100 | 36M | 12.5% | 10302608.6 gwei | -### 优先费(小费) {#priority-fee} +### 优先费(小费){#priority-fee} -优先费(小费)激励验证者将交易添加到区块中。 如果没有小费,验证者会发现开采空区块在经济上可行,因为它们会获得相同的区块奖励。 小额小费是对验证者将交易添加到区块的最小激励。 在相同区块中,对于要优先于其他交易执行的交易,可以添加更高的小费来尝试使出价高于竞争性交易。 +优先费(小费)激励验证者在区块燃料限制的约束下,将一个区块中的交易数量最大化。 如果没有小费,理性的验证者可能会打包更少甚至零交易,而不会受到任何直接的执行层或共识层惩罚,因为质押奖励与区块中的交易数量无关。 此外,小费允许用户通过出价高于他人来获得同一区块内的优先处理权,从而有效地表明其紧迫性。 ### 最高费用 {#maxfee} -要在网络上执行交易,用户可以为他们愿意支付的交易执行费用指定最高限额。 此可选参数称为 `maxFeePerGas`。 为了执行交易,最高费用必须超过基础费和小费的总和。 交易完成后,会将最高费用与基础费和小费总和之间的差额退还给交易发送人。 +要在网络上执行交易,用户可以为他们愿意支付的交易执行费用指定最高限额。 这个可选参数被称为 `maxFeePerGas`。 为了执行交易,最高费用必须超过基础费和小费的总和。 交易完成后,会将最高费用与基础费和小费总和之间的差额退还给交易发送人。 ### 区块大小 {#block-size} -每个区块的目标大小为 3000 万单位燃料,但区块的大小将根据网络需求增减,最大不得超过 6000 万单位燃料的区块大小上限(目标区块大小的 2 倍)。 协议通过 _tâtonnement_ 过程使均衡区块大小平均达到 1,500 万单位燃料。 这意味着如果区块大小超出目标区块大小,协议将增加下一个区块的基础费。 同样,如果区块大小小于目标区块大小,协议将减少基础费。 基础费的调整金额与当前区块大小和目标区块大小的差距成比例。 [关于区块的更多信息](/developers/docs/blocks/)。 +每个区块都有一个目标大小,即当前燃料限制的一半,但区块的大小会根据网络需求增减,直至达到区块上限(目标区块大小的 2 倍)。 协议通过_试探_过程在目标处实现均衡的平均区块大小。 这意味着如果区块大小超出目标区块大小,协议将增加下一个区块的基础费。 同样,如果区块大小小于目标区块大小,协议将减少基础费。 -### 实践中的燃料费计算 {#calculating-fees-in-practice} +基础费的调整金额与当前区块大小和目标区块大小的差距成比例。 这是一个线性计算:空区块为 -12.5%,达到目标大小时为 0%,达到燃料限制的区块为 +12.5%。 燃料限制会随着时间的推移,根据验证者信号以及网络升级而波动。 你可以在[此处查看燃料限制随时间的变化](https://eth.blockscout.com/stats/averageGasLimit?interval=threeMonths)。 + +[关于区块的更多信息](/developers/docs/blocks/) + +### 在实践中计算燃料费 {#calculating-fees-in-practice} 你可以明确说明自己愿意支付多少交易执行费。 然而,大多数钱包提供商会自动设置推荐的交易费(基础费 + 推荐的优先费)来降低用户操作的复杂程度。 @@ -98,43 +103,49 @@ Gas 对以太坊网络至关重要。 正是这种燃料使它能够运行,正 简而言之,燃料费有助于确保以太坊网络的安全。 在网络上执行的每次计算都需要收费,这样可以防止不良行为者给网络带来垃圾信息。 为了防止代码中出现无意或恶意的无限循环或其他计算浪费,要求每笔交易对可以采用的代码执行计算步骤设置一个限制。 基本计算单位是“燃料”。 -尽管交易中包含费用限制,但交易中未使用的所有燃料将退还给用户(即退还 `max fee - (base fee + tip)`)。 +尽管交易包含限制,但交易中任何未使用的燃料都会返还给用户(例如,返还`最高费用 - (基本费用 + 小费)`)。 -![未使用燃料退还示意图](../transactions/gas-tx.png) _示意图节选自[以太坊虚拟机图解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![显示未使用的燃料如何退款的图表](../transactions/gas-tx.png) +_图表改编自 [《图解以太坊虚拟机》](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ ## 什么是燃料限额? {#what-is-gas-limit} -燃料限额是指你愿意在交易中消耗的最大燃料数量。 涉及[智能合约](/developers/docs/smart-contracts/)的更复杂交易需要进行更多的计算工作,因此相比简单的支付,它们需要更高的燃料限额。 标准以太币转账要求燃料限额为 21,000 单位燃料。 +燃料限额是指你愿意在交易中消耗的最大燃料数量。 涉及[智能合约](/developers/docs/smart-contracts/)的更复杂交易需要更多的计算工作,因此它们比简单的支付需要更高的燃料限制。 标准以太币转账要求燃料限额为 21,000 单位燃料。 -例如,如果你对简单的以太币转账设置 50,000 单位燃料限额,以太坊虚拟机将消耗 21,000 单位,你将收到剩余的 29,000 单位。 然而,如果你设置的燃料太少,比如说,对于简单的以太币转账,设置燃料限额为 20,000 单位,以太坊虚拟机将消耗 20,000 单位燃料并尝试执行交易,但最后不会完成。 然后,以太坊虚拟机回滚所有变化,但由于验证者已经完成了价值 20k 单位燃料的工作,这些燃料就被消耗了。 +例如,如果你对简单的以太币转账设置 50,000 单位燃料限额,以太坊虚拟机将消耗 21,000 单位,你将收到剩余的 29,000 单位。 然而,如果你指定的燃料量过少,例如,对于一个简单的 ETH 转账,燃料限制设置为 20,000,则交易将在验证阶段失败。 该交易在被打包进区块之前会被拒绝,且不会消耗任何燃料。 反之,如果交易在执行过程中耗尽了燃料(例如,智能合约执行到一半时,耗尽了所有燃料),EVM 将回滚所有更改,但为执行该交易已完成的计算工作,仍会消耗提供的全部燃料。 ## 为什么燃料费会变得如此高? {#why-can-gas-fees-get-so-high} 燃料费高是由于以太坊广受欢迎。 如果需求量太大,用户必须提供更高的小费,力争使出价高于其他用户的交易。 小费越高,交易进入下一个区块的可能性就越大。 此外,更复杂的智能合约应用可能会执行许多操作来支持其功能,使它们消耗大量的燃料。 -## 减少燃料成本的举措 {#initiatives-to-reduce-gas-costs} +## 降低燃料成本的举措 {#initiatives-to-reduce-gas-costs} + +以太坊[可扩展性升级](/roadmap/)最终应能解决一些燃料费问题,从而使该平台能够每秒处理数千笔交易并实现全球扩展。 -以太坊[可扩展性升级](/roadmap/)最终应该可以解决部分燃料费问题,并让以太坊平台有能力每秒处理数千笔交易,从而实现全面扩容。 +二层网络扩容是一项主要举措,可大大优化燃料成本、用户体验和可扩展性。 -二层网络扩容是一项主要举措,可大大优化燃料成本、用户体验和可扩展性。 [关于二层网络扩容的更多信息](/developers/docs/scaling/#layer-2-scaling)。 +[关于二层网络扩容的更多信息](/developers/docs/scaling/#layer-2-scaling) ## 监控燃料费 {#monitoring-gas-fees} 如果想要监控燃料价格,用较少的费用发送以太币,你可以使用多种不同的工具,例如: -- [Etherscan 区块浏览器](https://etherscan.io/gastracker)_交易燃料价格估算器。_ -- [ETH Gas Tracker](https://www.ethgastracker.com/) _监控与追踪以太坊和二层网络燃料价格,降低交易费用并节省开支_ -- [Blocknative ETH Gas Estimator](https://chrome.google.com/webstore/detail/blocknative-eth-gas-estim/ablbagjepecncofimgjmdpnhnfjiecfm) _支持类型 0 传统交易和类型 2 EIP-1559 交易的燃料估算 Chrome 插件。_ -- [Cryptoneur Gas Fees Calculator](https://www.cryptoneur.xyz/gas-fees-calculator) _按照你的当地货币计算主网、Arbitrum 和 Polygon 上进行的各类交易的燃料费。_ +- [Etherscan](https://etherscan.io/gastracker) _交易燃料价格估算工具_ +- [Blockscout](https://eth.blockscout.com/gas-tracker) _开源交易燃料价格估算工具_ +- [ETH Gas Tracker](https://www.ethgastracker.com/) _监控和跟踪以太坊和 L2 的燃料价格,以降低交易费用并节省资金_ +- [Blocknative ETH Gas Estimator](https://chrome.google.com/webstore/detail/blocknative-eth-gas-estim/ablbagjepecncofimgjmdpnhnfjiecfm) _一款燃料估算 Chrome 扩展程序,支持 0 类传统交易和 2 类 EIP-1559 交易。_ +- [Cryptoneur Gas Fees Calculator](https://www.cryptoneur.xyz/gas-fees-calculator) _在主网、Arbitrum 和 Polygon 上,以你的本地货币计算不同交易类型的燃料费。_ ## 相关工具 {#related-tools} -- [Blocknative 的燃料平台](https://www.blocknative.com/gas)_由 Blocknative 的全局内存池数据平台提供支持的燃料估算应用程序接口_ +- [Blocknative's Gas Platform](https://www.blocknative.com/gas) _由 Blocknative 的全球内存池数据平台提供支持的燃料估算 API_ +- [Gas Network](https://gas.network) 链上燃料预言机。 支持超过 35 条链。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [以太坊 Gas 详解](https://defiprime.com/gas) -- [减少智能合约的燃料消耗](https://medium.com/coinmonks/8-ways-of-reducing-the-gas-consumption-of-your-smart-contracts-9a506b339c0a) -- [面向开发者的燃料优化策略](https://www.alchemy.com/overviews/solidity-gas-optimization) -- [EIP-1559 文档](https://eips.ethereum.org/EIPS/eip-1559) -- [Tim Beiko 的 EIP-1559 资源](https://hackmd.io/@timbeiko/1559-resources)。 +- [以太坊燃料详解](https://defiprime.com/gas) +- [降低智能合约的燃料消耗](https://medium.com/coinmonks/8-ways-of-reducing-the-gas-consumption-of-your-smart-contracts-9a506b339c0a) +- [开发人员的燃料优化策略](https://www.alchemy.com/overviews/solidity-gas-optimization) +- [EIP-1559 文档](https://eips.ethereum.org/EIPS/eip-1559)。 +- [Tim Beiko 的 EIP-1559 资源](https://hackmd.io/@timbeiko/1559-resources) +- [EIP-1559:机制与模因分离](https://web.archive.org/web/20241126205908/https://research.2077.xyz/eip-1559-separating-mechanisms-from-memes) diff --git a/public/content/translations/zh/developers/docs/ides/index.md b/public/content/translations/zh/developers/docs/ides/index.md index 6ce4572d03b..3397e00af03 100644 --- a/public/content/translations/zh/developers/docs/ides/index.md +++ b/public/content/translations/zh/developers/docs/ides/index.md @@ -1,64 +1,64 @@ --- -title: 集成开发环境 -description: +title: "集成开发环境" +description: "了解更多用于以太坊开发的网页和桌面 IDE,包括 Remix、VS Code 和流行的插件。" lang: zh --- -当建立一个[集成开发环境](https://wikipedia.org/wiki/Integrated_development_environment)时,以太坊上的应用编程类似于任何其他软件项目编程。 这里有许多选项可供选择,最后,请选择一个最适合你偏好的集成开发环境或代码编辑器。 对你的以太坊开发来说,最好的集成开发环境很可能就是你在传统软件开发中使用过的集成开发环境。 +在设置[集成开发环境 (IDE)](https://wikipedia.org/wiki/Integrated_development_environment) 方面,在以太坊上进行应用编程与任何其他软件项目的编程类似。 这里有许多选项可供选择,最后,请选择一个最适合你偏好的集成开发环境或代码编辑器。 对你的以太坊开发来说,最好的集成开发环境很可能就是你在传统软件开发中使用过的集成开发环境。 -## 基于网络的集成开发环境 {#web-based-ides} +## 基于 Web 的 IDE {#web-based-ides} -如果你想在[设置本地开发环境](/developers/local-environment/)之前摆弄一下代码,这些网络应用是为以太坊智能合约开发定制的。 +如果您想在[设置本地开发环境](/developers/local-environment/)之前摆弄一下代码,这些网络应用是专为以太坊智能合约开发而定制的。 -**[Remix](https://remix.ethereum.org/)** - **_基于 Web 的集成开发环境,内置静态分析和区块链测试虚拟机_** +**[Remix](https://remix.ethereum.org/)** - **_基于 Web 的 IDE,内置静态分析功能和测试区块链虚拟机_** -- [相关文档](https://remix-ide.readthedocs.io/en/latest/#) +- [文档](https://remix-ide.readthedocs.io/en/latest/#) - [Gitter](https://gitter.im/ethereum/remix) -**[ChainIDE](https://chainide.com/)** - **_一个支持多链的云端集成开发环境_** +**[ChainIDE](https://chainide.com/)** - **_基于云的多链 IDE_** -- [相关文档](https://chainide.gitbook.io/chainide-english-1/) +- [文档](https://chainide.gitbook.io/chainide-english-1/) - [帮助论坛](https://forum.chainide.com/) -**[Replit(Solidity 新手教程 - Beta)](https://replit.com/@replit/Solidity-starter-beta)** - **_一种可定制的以太坊开发环境,提供热重载、错误检查和一流的测试网支持_** +**[Replit (Solidity 入门 - Beta 版)](https://replit.com/@replit/Solidity-starter-beta)** - **_一个可自定义的以太坊开发环境,具有热重载、错误检查和一流的测试网支持_** -- [相关文档](https://docs.replit.com/) +- [文档](https://docs.replit.com/) -**[Tenderly Sandbox](https://sandbox.tenderly.co/)** - **_一种快捷的原型构建环境,让你可以使用 Solidity 和 JavaScript 在浏览器中编写、执行并调试智能合约_** +**[Tenderly Sandbox](https://sandbox.tenderly.co/)** - **_一种快速的原型设计环境,您可以在浏览器中使用 Solidity 和 JavaScript 编写、执行和调试智能合约_** -**[EthFiddle](https://ethfiddle.com/)** - **_基于 Web 的集成开发环境 ( IDE ),可让你编写、编译和调试智能合约_** +**[EthFiddle](https://ethfiddle.com/)** - **_一个基于 Web 的 IDE,可让您编写、编译和调试您的智能合约_** - [Gitter](https://gitter.im/loomnetwork/ethfiddle) ## 桌面 IDE {#desktop-ides} -大多数成熟的集成开发环境都包含增强以太坊开发体验的插件。 至少,它们能为[智能合约语言](/developers/docs/smart-contracts/languages/)提供语法突出显示。 +大多数成熟的集成开发环境都包含增强以太坊开发体验的插件。 它们至少为[智能合约语言](/developers/docs/smart-contracts/languages/)提供语法高亮。 -**Visual Studio Code -** **_专业跨平台集成开发环境,获得以太坊官方支持_** +**Visual Studio Code -** **_具有官方以太坊支持的专业跨平台 IDE_** - [Visual Studio Code](https://code.visualstudio.com/) - [代码示例](https://github.com/Azure-Samples/blockchain/blob/master/blockchain-workbench/application-and-smart-contract-samples/readme.md) - [GitHub](https://github.com/microsoft/vscode) -**JetBrains 集成开发环境(IntelliJ IDEA 等) -** **_面向软件开发者和团队的基本工具_** +**JetBrains IDE(IntelliJ IDEA 等) -** **_面向软件开发者和团队的基本工具_** - [JetBrains](https://www.jetbrains.com/) - [GitHub](https://github.com/JetBrains) - [IntelliJ Solidity](https://github.com/intellij-solidity/intellij-solidity/) -**Remix Desktop -** **_在本地计算机上体验 Remix 集成开发环境_** +**Remix Desktop -** **_在您的本地计算机上体验 Remix IDE_** - [下载](https://github.com/ethereum/remix-desktop/releases) - [GitHub](https://github.com/ethereum/remix-desktop) -## 插件与扩展 {#plugins-extensions} +## 插件和扩展 {#plugins-extensions} -- [solidity](https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity) - 面向 Visual Studio Code 的以太坊 Solidity 语言 -- [面向 VS Code 的 Solidity + 安全帽](https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity) - 安全帽团队提供 Solidity 和安全帽支持 -- [Prettier Solidity](https://github.com/prettier-solidity/prettier-plugin-solidity) - 使用 Prettier 的代码格式化工具 +- [solidity](https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity) - 适用于 Visual Studio Code 的以太坊 Solidity 语言 +- [Solidity + Hardhat for VS Code](https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity) - 由 Hardhat 团队提供的 Solidity 和 Hardhat 支持 +- [Prettier Solidity](https://github.com/prettier-solidity/prettier-plugin-solidity) - 使用 prettier 的代码格式化工具 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [以太坊集成开发环境 (IDE)](https://www.alchemy.com/list-of/web3-ides-on-ethereum) _- Alchemy 提供的以太坊集成开发环境列表_ +- [Ethereum IDEs](https://www.alchemy.com/list-of/web3-ides-on-ethereum) _- Alchemy 整理的以太坊 IDE 列表_ -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ diff --git a/public/content/translations/zh/developers/docs/index.md b/public/content/translations/zh/developers/docs/index.md index 47c7c2e0023..2141a651e43 100644 --- a/public/content/translations/zh/developers/docs/index.md +++ b/public/content/translations/zh/developers/docs/index.md @@ -1,14 +1,14 @@ --- -title: 以太坊开发文档 -description: ethereum.org 开发者相关文档简介。 +title: "以太坊开发文档" +description: "ethereum.org 开发者相关文档简介。" lang: zh --- 本文档旨在帮助你构建以太坊。 它介绍了以太坊概念,解释了以太坊技术栈,并记录了以太坊更复杂的应用和使用案例的高级主题。 -基于开源社区的努力,你可以随时提出新的主题,添加新内容,并在认为可能有用的地方提供示例。 所有文档都可以通过 GitHub 编辑 — 如果不确定如何操作,[请遵循这些说明](https://github.com/ethereum/ethereum-org-website/blob/dev/docs/editing-markdown.md)。 +基于开源社区的努力,你可以随时提出新的主题,添加新内容,并在认为可能有用的地方提供示例。 所有相关文档均可通过 GitHub 进行编辑 – 如果您不确定如何操作,[请遵循这些说明](https://github.com/ethereum/ethereum-org-website/blob/dev/docs/editing-markdown.md)。 -## 开发单元 {#development-modules} +## 开发模块 {#development-modules} 如果这是你首次尝试以太坊开发,我们建议从头开始,有始有终,从头到尾。 diff --git a/public/content/translations/zh/developers/docs/intro-to-ether/index.md b/public/content/translations/zh/developers/docs/intro-to-ether/index.md index c1854ac145d..d64503aa3d9 100644 --- a/public/content/translations/zh/developers/docs/intro-to-ether/index.md +++ b/public/content/translations/zh/developers/docs/intro-to-ether/index.md @@ -1,12 +1,12 @@ --- -title: 以太币简介 -description: 开发者讲解以太币加密货币 +title: "以太币技术介绍" +description: "开发者讲解以太币加密货币" lang: zh --- ## 前提条件 {#prerequisites} -为了更好地理解此页面,推荐先阅读:[以太坊简介](/developers/docs/intro-to-ethereum/)。 +为了帮助你更好地理解本页面,我们建议你先阅读[以太坊简介](/developers/docs/intro-to-ethereum/)。 ## 什么是加密货币? {#what-is-a-cryptocurrency} @@ -16,37 +16,37 @@ lang: zh 第一个加密货币是由 Satoshi Nakamoto 创建的比特币。 自 2009 年比特币发行以来,人们已经在许多不同的区块链上制作了数以千计的加密货币。 -## 什么是以太币 (ETH)? {#what-is-ether} +## 什么是以太币? {#what-is-ether} -**以太币 (ETH)** 是用于以太坊网络上许多事物的加密货币。 从根本上讲,以太币是唯一可接受的交易费支付方式,并且在[合并](/roadmap/merge)之后,在主网上验证和提出区块需要以太币。 以太币还被用作 [去中心化金融](/defi) 借贷市场的主要抵押形式,非同质化代币市场的主要记账单位以及提供服务、销售实体商品赚取的付款等。 +**以太币 (ETH)** 是用于以太坊网络上许多事物的加密货币。 从根本上讲,它是唯一可接受的交易费支付方式,并且在[合并](/roadmap/merge)之后,在主网上验证和提出区块需要以太币。 以太币也被用作 [DeFi](/defi) 借贷市场的主要抵押品、NFT 市场的记账单位、因提供服务或销售实体商品而获得的报酬等等。 -以太坊允许开发者创建 [**去中心化应用程序 (dapp)**](/developers/docs/dapps),它们共享算力池。 这个共享池是有限的,因此以太坊需要一种机制来确定谁可以使用它。 否则,某个 dapp 可能会意外或恶意地消耗所有网络资源,从而导致其他应用程序无法访问算力池。 +以太坊允许开发者创建[**去中心化应用程序 (dapps)**](/developers/docs/dapps),它们都共享一个算力池。 这个共享池是有限的,因此以太坊需要一种机制来确定谁可以使用它。 否则,某个 dapp 可能会意外或恶意地消耗所有网络资源,从而导致其他应用程序无法访问算力池。 -ETH 加密货币支持以太坊算力的定价机制。 当用户想要完成一笔交易时,他们必须支付以太币,使他们的交易被区块链识别。 这些使用成本被称为 [gas 费用](/developers/docs/gas/),gas 费用的多少取决于执行交易所需的算力和全网当时的算力需求。 +ETH 加密货币支持以太坊算力的定价机制。 当用户想要完成一笔交易时,他们必须支付以太币,使他们的交易被区块链识别。 这些使用成本被称为[燃料费](/developers/docs/gas/),燃料费的多少取决于执行交易所需的算力以及当时全网对算力的需求。 因此,即使某恶意 dapp 无限循环提交,交易最终也会耗尽 ETH 并终止,从而使网络恢复正常。 -人们[经常会混淆](https://abcnews.go.com/Business/bitcoin-slumps-week-low-amid-renewed-worries-chinese/story?id=78399845)以太坊和以太币 — 当人们谈及“以太坊的价格”时,他们指的是以太币的价格。 +人们[常常混淆](https://abcnews.go.com/Business/bitcoin-slumps-week-low-amid-renewed-worries-chinese/story?id=78399845)以太坊和以太币——当人们提到“以太坊的价格”时,他们描述的是以太币的价格。 -## 铸造 ETH {#minting-ether} +## 铸造以太币 {#minting-ether} 铸造是指在以太坊分类账上创造新以太币的过程。 底层以太坊协议创造出新以太币,单一用户不可能创造。 以太币铸造出来,用来奖励提议的每个区块,以及在每个时段的检查点奖励验证者执行的和达成共识有关的其他活动。 总发行量取决于验证者的数量和它们质押的以太币数量。 在所有验证者都诚实且在线的理想情况下,以太币总发行量会在所有验证者中等分,但现实中分配情况会因验证者的表现而异。 总发行量的大约 1/8 会奖励给区块提议者,剩余部分在其它验证者中分配。 区块提议者还会获得交易费小费和矿工可提取价值,但这些都来自流通中的以太币,而非新发行的以太币。 -## 燃烧 ETH {#burning-ether} +## 销毁以太币 {#burning-ether} 除了通过区块奖励创建以太币,以太币也能通过“燃烧”过程销毁。 当 ETH 被燃烧掉,它也就永久退出流通。 -以太坊上的每一笔交易都会发生以太币销毁。 当用户为他们的交易支付费用时,网络根据交易需求设置的基础燃料费会被销毁。 以太币销毁再加上可变区块大小和最高燃料费,简化了以太坊上的交易费估算。 网络需求量高时,[区块](https://etherscan.io/block/12965263)燃烧的以太币数量可以多于铸造的以太币数量,有效地抵消了以太币的发行。 +以太坊上的每一笔交易都会发生以太币销毁。 当用户为他们的交易支付费用时,网络根据交易需求设置的基础燃料费会被销毁。 以太币销毁再加上可变区块大小和最高燃料费,简化了以太坊上的交易费估算。 当网络需求高时,[区块](https://eth.blockscout.com/block/22580057)销毁的以太币可以多于铸造的以太币,从而有效地抵消以太币发行。 -销毁基础费抑制区块生产者操纵交易的能力。 例如,如果区块生产者获得了基础费,他们可以免费添加自己的交易,并提高其他所有人的基础费。 或者,矿工可以将基础费退还给一些链下用户,造成交易费市场更加不透明和复杂。 +销毁基本费用会妨碍区块生产者操纵交易的能力。 例如,如果区块生产者获得了基础费,他们可以免费添加自己的交易,并提高其他所有人的基础费。 反之,他们也可以通过链下方式向部分用户退还基础费用,但这会导致交易费市场更加不透明和复杂。 -## ETH 面额 {#denominations} +## 以太币的面额 {#denominations} 由于以太坊上很多交易数额都比较小,因此以太币有几种面额,可以作为较小的记账单位。 在这些面额中,Wei 与 Gwei 特别重要。 -Wei 是最小的以太币面额,因此在[以太坊黄皮书](https://ethereum.github.io/yellowpaper/paper.pdf)等众多技术实现中,都以 Wei 为单位进行计算。 +Wei 是以太币的最小单位,因此,许多技术实现(例如[《以太坊黄皮书》](https://ethereum.github.io/yellowpaper/paper.pdf))都会以 Wei 为单位进行所有计算。 Gwei(giga-wei 的缩写),常用于描述以太坊上的燃料费用。 @@ -55,24 +55,24 @@ Gwei(giga-wei 的缩写),常用于描述以太坊上的燃料费用。 | Wei | 10-18 | 技术实施 | | Gwei | 10-9 | 可读燃料费用 | -## 传输 ETH {#transferring-ether} +## 转账以太币 {#transferring-ether} -以太坊上的每笔交易都包含一个 `value` 字段,指定从发送者地址发送到接收者地址的以太币转账金额(以 Wei 为单位)。 +以太坊上的每笔交易都包含一个 `value` 字段,该字段指定了从发送者地址发送到接收者地址的以太币转账金额(以 wei 为单位)。 -当接收者地址是[智能合约](/developers/docs/smart-contracts/)时,在智能合约执行其代码后,这些转账的以太币可用于支付燃料费用。 +当接收者地址是[智能合约](/developers/docs/smart-contracts/)时,当智能合约执行其代码时,这笔转账的以太币可用于支付燃料费。 -[有关交易的更多信息](/developers/docs/transactions/) +[关于交易的更多信息](/developers/docs/transactions/) -## 查询 ETH {#querying-ether} +## 查询以太币 {#querying-ether} -用户可以通过检查帐户的 `balance` 字段来查询任何[帐户](/developers/docs/accounts/)的以太币余额,该字段显示以太币持有数量(以 Wei 为单位)。 +用户可通过检查[帐户](/developers/docs/accounts/)的 `balance` 字段,查询任意帐户的以太币余额。该字段以 wei 为单位显示以太币持有量。 -[Etherscan](https://etherscan.io) 是一种常用工具,用于通过基于 Web 的应用程序检查地址余额。 例如,[此 Etherscan 页面](https://etherscan.io/address/0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae)显示以太坊基金会的余额。 也可以通过使用钱包或直接向节点提出请求来查询帐户余额。 +[Etherscan](https://etherscan.io) 和 [Blockscout](https://eth.blockscout.com) 是常用的工具,用于通过网页应用程序检查地址余额。 例如,[此 Blockscout 页面](https://eth.blockscout.com/address/0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe)显示了以太坊基金会的余额。 也可以通过使用钱包或直接向节点提出请求来查询帐户余额。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [定义 ETH 和以太坊](https://www.cmegroup.com/education/courses/introduction-to-ether/defining-ether-and-ethereum.html) – _CME Group_ -- [以太坊白皮书](/whitepaper/):以太坊原始提案 这份资料包括了对 ETH 及其创建动机的整体描述。 -- [Gwei 计算器](https://www.alchemy.com/gwei-calculator):使用这个 Gwei 计算器可以轻松地换算 wei、Gwei 和 ETH。 只需输入任何数量的 wei、Gwei 或 ETH,就能够自动换算。 +- [定义以太币和以太坊](https://www.cmegroup.com/education/courses/introduction-to-ether/defining-ether-and-ethereum.html) – _CME Group_ +- [以太坊白皮书](/whitepaper/):以太坊原始提案。 这份资料包括了对 ETH 及其创建动机的整体描述。 +- [Gwei 计算器](https://www.alchemy.com/gwei-calculator):使用此 Gwei 计算器可轻松换算 wei、Gwei 和 ETH。 只需输入任何数量的 wei、Gwei 或 ETH,就能够自动换算。 -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ diff --git a/public/content/translations/zh/developers/docs/intro-to-ethereum/index.md b/public/content/translations/zh/developers/docs/intro-to-ethereum/index.md index 5a85a4e2768..514fde47851 100644 --- a/public/content/translations/zh/developers/docs/intro-to-ethereum/index.md +++ b/public/content/translations/zh/developers/docs/intro-to-ethereum/index.md @@ -1,28 +1,28 @@ --- -title: 以太坊简介 -description: 面向 dapp 开发者介绍以太坊的核心概念。 +title: "以太币技术介绍" +description: "面向 dapp 开发者介绍以太坊的核心概念。" lang: zh --- ## 什么是区块链? {#what-is-a-blockchain} -对区块链最好的描述是将其描述为一个公共数据库,它由网络中的许多计算机更新和共享。 +区块链是一个公共数据库,由网络中的多台计算机进行更新和共享。 -"区块"指的是数据和状态是按顺序批量或"区块"存储的。 如果你向别人发送 ETH,需要将交易数据添加到一个区块中才算成功。 +“区块”指的是数据和状态存储在称为“区块”的连续群组中。 如果你向别人发送 ETH,需要将交易数据添加到一个区块中才算成功。 "链"指的是每个区块加密引用其父块。 换句话说,区块被链接在一起。 在不改变所有后续区块的情况下,区块内数据是无法改变,但改变后续区块需要整个网络的共识。 网络中的每台计算机都必须就每个新区块和链达成一致。 这些计算机被称为“节点”。 节点保证所有与区块链交互的人都有相同的数据。 要完成此分布式协议,区块链需要一个共识机制。 -以太坊采用[权益证明共识机制](/developers/docs/consensus-mechanisms/pos/)。 任何想在链上添加新区块的人都必须质押以太币(以太坊原生货币)做为抵押品并运行验证者软件。 接着,可以随机选择这些“验证者”来提出区块,再由其他验证者检查并添加到区块链中。 存在一种奖励和惩罚体系,有力地激励参与者尽可能地诚实和保持在线。 +以太坊使用一种[基于权益证明的共识机制](/developers/docs/consensus-mechanisms/pos/)。 任何想在链上添加新区块的人都必须质押以太币(以太坊原生货币)做为抵押品并运行验证者软件。 接着,可以随机选择这些“验证者”来提出区块,再由其他验证者检查并添加到区块链中。 存在一种奖励和惩罚体系,有力地激励参与者尽可能地诚实和保持在线。 -如果你想了解如何对区块链数据进行哈希运算并随后附加到区块引用的历史记录中,请务必查看Anders Brownworth 进行的[这个演示](https://andersbrownworth.com/blockchain/blockchain)并观看下方的相关视频。 +如果你想了解如何对区块链数据进行哈希运算并随后附加到区块引用的历史记录中,请务必查看 Anders Brownworth 制作的[这个演示](https://andersbrownworth.com/blockchain/blockchain)并观看下方的相关视频。 观看 Anders 介绍区块链中的哈希: -## 以太坊简介 {#what-is-ethereum} +## 什么是以太坊? {#what-is-ethereum} 以太坊是一条区块链,其中嵌入了计算机。 它是以去中心化、无需许可、抗审查的方式构建应用程序和组织的基础。 @@ -34,17 +34,16 @@ lang: zh ## 什么是以太币? {#what-is-ether} -**以太币 (ETH)** 是以太坊上的原生加密货币。 以太币的目的是允许计算市场化。 这种市场为参与者提供了一种经济激励,以验证并执行交易请求,为网络提供计算资源。 +\*\*以太币 (ETH)\*\*是以太坊的原生加密货币。 以太币的目的是允许计算市场化。 这种市场为参与者提供了一种经济激励,以验证并执行交易请求,为网络提供计算资源。 任何广播交易请求的参与者还必须向网络提供一定数量的以太币作为奖金。 网络将燃烧部分奖金,并将剩余部分奖励给最终验证、执行交易,将其提交到区块链并广播到网络的任何人。 支付的以太币数量对应于进行计算所需的资源。 这类奖励也可以阻止恶意参与者通过请求执行无穷计算或其他资源密集型脚本来故意堵塞网络,因为这些参与者必须为计算资源付费。 -以太币还用于通过以下三种主要方式为网络提供加密经济安全性:1) 作为一种奖励方式,奖励提议区块或指出其他验证者不诚实行为的验证者;2) 由验证者抵押,作为遏制不诚实行为的抵押品 — 如果验证者试图行为不端,它们的以太币可能会被销毁;3) 用于对新提议的区块的“投票”进行加权,并影响共识机制的分叉选择部分。 +ETH 还用于通过以下三种主要方式为网络提供加密经济安全性:1) 作为一种奖励方式,奖励提议区块或指出其他验证者不诚实行为的验证者;2) 由验证者质押,作为遏制不诚实行为的抵押品——如果验证者试图行为不端,他们的 ETH 可能会被销毁;3) 用于对新提议的区块的“投票”进行加权,并影响共识机制的分叉选择部分。 ## 什么是智能合约? {#what-are-smart-contracts} - -实际上,参与者不会每次在以太坊虚拟机上请求计算时都编写新代码。 相反,应用程序开发者将程序(可重用的代码片段)上传到以太坊虚拟机状态,用户发出请求以使用不同参数执行这些代码片段。 我们将这些上传至网络并由网络执行的程序称为智能合约。 +实际上,参与者不会每次在以太坊虚拟机上请求计算时都编写新代码。 相反,应用程序开发者将程序(可重用的代码片段)上传到以太坊虚拟机状态,用户发出请求以使用不同参数执行这些代码片段。 我们将上传至网络并由网络执行的程序称为“智能合约”。 简单来说,你可以把智能合约想象成一种自动售货机:通过特定参数调用脚本后,如果满足某些特定条件,就会执行一些操作或计算。 例如,如果调用者将以太币发送给特定的接收者,简单的卖方智能合约就可以创建和分配数字资产所有权。 @@ -58,29 +57,29 @@ lang: zh 所有在以太坊网络历史上提交给以太坊网络的区块的序列。 如此命名,是因为每个区块都包含对前一个区块的引用,这有助于保持所有区块的顺序,因而维持了精确历史记录的顺序。 -### ETH 以太币 {#eth} +### ETH {#eth} -**以太币 (ETH)** 是以太坊上的原生加密货币。 用户向其他用户支付以太币,让他们完成自己的代码执行请求。 +\*\*以太币 (ETH)\*\*是以太坊的原生加密货币。 用户向其他用户支付以太币,让他们完成自己的代码执行请求。 -[有关以太币的更多信息](/developers/docs/intro-to-ether/) +[关于 ETH 的更多信息](/developers/docs/intro-to-ether/) -### EVM 以太坊虚拟机 {#evm} +### EVM {#evm} 以太坊虚拟机是一个全局虚拟计算机,以太坊网络中的每个参与者都会存储并一致同意其状态。 任何参与者都可以请求在以太坊虚拟机上执行任意代码;代码执行会改变以太坊虚拟机的状态。 -[有关以太坊虚拟机的更多信息](/developers/docs/evm/) +[关于 EVM 的更多信息](/developers/docs/evm/) -### Nodes 节点 {#nodes} +### 节点 {#nodes} 存储以太坊虚拟机状态的实体计算机。 节点间相互通信,传播关于以太坊状态的信息及其新的状态变化。 任何用户还可以通过广播来自节点的代码执行请求来请求代码执行。 以太坊网络本身就是所有以太坊节点及其通信的集合。 -[有关节点的更多信息](/developers/docs/nodes-and-clients/) +[关于节点的更多信息](/developers/docs/nodes-and-clients/) ### 帐户 {#accounts} 帐户是存储以太币之处。 用户可以初始化帐户,将以太币存入帐户,并将自己帐户中的以太币转账给其他用户。 帐户和帐户余额存储在以太坊虚拟机中的一个大表格中,是以太坊虚拟机总体状态的一部分。 -[有关帐户的更多信息](/developers/docs/accounts/) +[关于帐户的更多信息](/developers/docs/accounts/) ### 交易 {#transactions} @@ -90,27 +89,35 @@ lang: zh - 将一些智能合约代码发布到以太坊虚拟机状态中。 - 使用 Y 参数执行 EVM 中 X 地址的智能合约代码。 -[有关交易的更多信息](/developers/docs/transactions/) +[关于交易的更多信息](/developers/docs/transactions/) ### 区块 {#blocks} 交易量巨大,因此交易分批或分区块“提交”。 区块通常包含数十至数百笔交易。 -[有关区块的更多信息](/developers/docs/blocks/) +[关于区块的更多信息](/developers/docs/blocks/) ### 智能合约 {#smart-contracts} -是指开发者发布到以太坊虚拟机状态中的可重用代码片段(程序)。 任何人都可以通过提出交易请求来请求执行智能合约代码。 因为开发者可以通过发布智能合约将任意可执行应用程序(游戏,市场,金融工具等)写入以太坊虚拟机,所以这些通常也称为 [dapp 或去中心化应用程序](/developers/docs/dapps/)。 +是指开发者发布到以太坊虚拟机状态中的可重用代码片段(程序)。 任何人都可以通过提出交易请求来请求执行智能合约代码。 因为开发者可以在 EVM 中编写任意的可执行应用程序(游戏、市场、金融工具等) 通过发布智能合约,这些程序通常也被称为[dapps(即去中心化应用程序)](/developers/docs/dapps/)。 -[有关智能合约的更多信息](/developers/docs/smart-contracts/) +[关于智能合约的更多信息](/developers/docs/smart-contracts/) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [以太坊白皮书](/whitepaper/) -- [那么,以太坊究竟是如何工作的?](https://medium.com/@preethikasireddy/how-does-ethereum-work-anyway-22d1df506369) - _Preethi Kasireddy_(**注意**此资源仍然有价值,但请注意它早于[合并](/roadmap/merge),因此仍然引用以太坊的工作量证明机制 - 实际上以太坊现在使用的是[权益证明](/developers/docs/consensus-mechanisms/pos)来保障安全) +- [以太坊究竟是如何工作的?](https://medium.com/@preethikasireddy/how-does-ethereum-work-anyway-22d1df506369) - _Preethi Kasireddy_ (**注意**:此资源仍然有价值,但请注意它早于[“合并”](/roadmap/merge),因此仍然引用以太坊的工作量证明机制——实际上以太坊现在使用的是[权益证明](/developers/docs/consensus-mechanisms/pos)来保障安全) + +### 更愿意通过视频学习? {#visual-learner} + +本系列视频对基本主题进行了深入探索: + + + +[以太坊基础知识播放列表](https://youtube.com/playlist?list=PLqgutSGloqiJyyoL0zvLVFPS-GMD2wKa5&si=kZTf5I7PKGTXDsOZ) -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ ## 相关教程 {#related-tutorials} -- [以太坊开发者指南,第 1 部分](/developers/tutorials/a-developers-guide-to-ethereum-part-one/) _ – 探索以太坊(非常适合使用 Python 和 web3.py 的初学者)_ +- [以太坊开发者指南,第 1 部分](/developers/tutorials/a-developers-guide-to-ethereum-part-one/)_– 使用 Python 和 web3.py 探索以太坊,对初学者非常友好_ diff --git a/public/content/translations/zh/developers/docs/mev/index.md b/public/content/translations/zh/developers/docs/mev/index.md index c9476caf180..bc605e64202 100644 --- a/public/content/translations/zh/developers/docs/mev/index.md +++ b/public/content/translations/zh/developers/docs/mev/index.md @@ -1,6 +1,6 @@ --- -title: 最大可提取价值 (MEV) -description: 最大可提取价值 (MEV) 简介 +title: "最大可提取价值 (MEV)" +description: "最大可提取价值 (MEV) 简介" lang: zh --- @@ -8,27 +8,27 @@ lang: zh ## 最大可提取价值 {#maximal-extractable-value} -最大可提取价值首先应用于[工作量证明](/developers/docs/consensus-mechanisms/pow/)背景下,最初称为“矿工可提取价值”。 这是因为在工作量证明中,矿工掌握了交易的包含、排除和顺序。 然而,自从通过[合并](/roadmap/merge)过渡到权益证明以来,验证者一直承担着这些角色的职责,并且挖矿不再是以太坊协议的一部分。 但是,价值提取方法仍然存在,因此现在使用的是术语“最大可提取价值”。 +最大可提取价值最初应用于[工作量证明](/developers/docs/consensus-mechanisms/pow/)的背景下,最初被称为“矿工可提取价值”。 这是因为在工作量证明中,矿工掌握了交易的包含、排除和顺序。 然而,自从通过[合并](/roadmap/merge)过渡到权益证明以来,验证者一直承担着这些角色的职责,并且挖矿不再是以太坊协议的一部分。 但是,价值提取方法仍然存在,因此现在使用的是术语“最大可提取价值”。 ## 前提条件 {#prerequisites} -确保你已熟悉[交易](/developers/docs/transactions/)、[区块](/developers/docs/blocks/)、[权益证明](/developers/docs/consensus-mechanisms/pos)和[燃料](/developers/docs/gas/)。 熟悉 [dapps](/apps/) 和 [DeFi](/defi/) 也很有帮助。 +请确保您熟悉[交易](/developers/docs/transactions/)、[区块](/developers/docs/blocks/)、[权益证明](/developers/docs/consensus-mechanisms/pos)和[燃料](/developers/docs/gas/)。 熟悉[去中心化应用程序](/apps/)和 [DeFi](/defi/) 也很有帮助。 -## 最大可提取价值提取 {#mev-extraction} +## MEV 提取 {#mev-extraction} 从理论上讲,最大可提取价值完全属于验证者,因为他们是唯一可以保证执行有利可图的最大可提取价值机会的一方。 但实际上,大部分 MEV 是由称为“搜索人”的独立网络参与者提取的。 搜索人在区块链数据上运行复杂的算法来检测盈利的 MEV 机会,并且有机器人自动将这些盈利交易提交到网络。 无论如何,验证者确实会获得全部最大可提取价值金额的一部分,因为搜索者愿意支付高昂的燃料费用(这些费用将归验证者所有),以换取将其有利可图的交易纳入一个区块的更高可能性。 假定搜索人在经济上是合理的。搜索人愿意支付的燃料费将是 MEV 的 100% 的金额(因为如果燃料费更高,搜索人将亏钱)。 -这样一来,对于一些竞争激烈的最大可提取价值机会,例如[去中心化交易所套利](#mev-examples-dex-arbitrage),搜索者可能不得不将其最大可提取价值总收入的 90% 甚至更多作为燃料费用支付向验证者,因为很多人都想进行同样有利可图的套利交易。 这是因为,确保套利交易运行的唯一方法是提交最高燃料费用的交易。 +这样一来,对于一些竞争激烈的 MEV 机会,例如 [DEX 套利](#mev-examples-dex-arbitrage),搜索者可能不得不将其 MEV 总收入的 90% 甚至更多作为燃料费支付给验证者,因为很多人都想进行同样有利可图的套利交易。 这是因为,确保套利交易运行的唯一方法是提交最高燃料费用的交易。 ### 燃料高尔夫 {#mev-extraction-gas-golfing} 这种动态使得“燃料高尔夫”——编程交易——能够使用最少数量的燃料——这成为一种竞争优势。因为它允许搜索人设置较高的燃料价格,同时保持总燃料费不变(因为使用燃料费 = 燃料价格\* 燃料用量)。 -一些著名的燃料高尔夫技术包括:使用用长串零开头的地址(如:[0x0000000000C521824EaFf97Eac7B73B084ef9306](https://etherscan.io/address/0x0000000000c521824eaff97eac7b73b084ef9306)),因为他们的需要的存储空间较少(因而燃料也减少);并留下很小 [ERC-20](/developers/docs/standards/tokens/erc-20/) 令牌余额在合约中,因为相比于更新储存插槽,初始化存储插槽需要更多的燃料(余额为 0 时)。 寻找如何更多的减少燃料使用是搜索人在积极研究的一个领域。 +一些众所周知的燃料高尔夫技巧包括:使用以一长串零开头的地址(例如 [0x0000000000C521824EaFf97Eac7B73B084ef9306](https://eth.blockscout.com/address/0x0000000000C521824EaFf97Eac7B73B084ef9306)),因为它们占用的存储空间更小(因此燃料也更少);在合约中留下少量 [ERC-20](/developers/docs/standards/tokens/erc-20/) 代币余额,因为初始化存储插槽(余额为 0 的情况)比更新存储插槽需要更多燃料。 寻找如何更多的减少燃料使用是搜索人在积极研究的一个领域。 -### 通用领跑者 {#mev-extraction-generalized-frontrunners} +### 通用抢先交易者 {#mev-extraction-generalized-frontrunners} 一些搜索人并没有编写复杂的算法来检测盈利的 MEV 机会,而是运行通用的领跑者。 通用的领跑者是监控内存池以检测盈利交易的机器人。 领跑者将复制潜在的盈利交易代码,用领跑者的地址替换其地址。然后在本地执行交易,重复检查修改后的交易是否给领跑者地址带来利润。 如果交易确实有利可图,领跑者将以更替地址和更高的燃料价格提交修改后的交易。“领跑”原始交易并获取原始搜索人的 MEV。 @@ -36,95 +36,95 @@ lang: zh Flashbots 是一个独立项目,它通过一项服务扩展执行客户端,该服务允许搜索者将最大可提取价值交易提交给验证者,而无需将它们透露给公共内存池。 这就防止了交易被通用领跑者领跑。 -## 最大可提取价值相关示例 {#mev-examples} +## MEV 示例 {#mev-examples} 最大可提取价值以几种方式出现在区块链上。 -### 去中心化交易所套利 {#mev-examples-dex-arbitrage} +### DEX 套利 {#mev-examples-dex-arbitrage} -[去中心化交易所](/glossary/#dex) (DEX) 套利是最简单和最著名的最大可提取价值机会。 因此,它也是竞争最激烈的。 +[去中心化交易所](/glossary/#dex) (DEX) 套利是最简单、最著名的 MEV 机会。 因此,它也是竞争最激烈的。 它的作用原理就像这样:如果有两个去中心化交易所以两种不同的价格提供一种代币,有人可以通过一笔原子交易,在价格较低的去中心化交易所购买此代币,并在价格较高的去中心化交易所将其出售。 得益于区块链的机制,这是真实的无风险套利。 -[这是一个有利可图的套利交易示例](https://etherscan.io/tx/0x5e1657ef0e9be9bc72efefe59a2528d0d730d478cfc9e6cdd09af9f997bb3ef4),在此交易中,一名搜索者利用以太币/DAI 对在 Uniswap 和 Sushiswap 的不同价格,将 1, 000 个以太币变成了 1,045 个以太币。 +[这是一个有利可图的套利交易示例](https://eth.blockscout.com/tx/0x5e1657ef0e9be9bc72efefe59a2528d0d730d478cfc9e6cdd09af9f997bb3ef4),在此交易中,一名搜索者利用 ETH/DAI 对在 Uniswap 与 Sushiswap 上的不同定价,将 1,000 ETH 变成了 1,045 ETH。 ### 清算 {#mev-examples-liquidations} 借贷协议清算提供了另一个众所周知的最大可提取价值机会。 -Maker 和 Aave 等借贷协议要求用户存入一些抵押品(例如以太币)。 这些存入的抵押品之后会借出给其他用户。 +Maker 和 Aave 等借贷协议要求用户存入一些抵押品(例如,ETH)。 这些存入的抵押品之后会借出给其他用户。 -然后,用户可以根据他们的需要从其他人那里借入资产和代币(例如,如果你想在 MakerDAO 治理提案中投票,你可以借用 MKR),最高可达他们所存抵押品的一定比例。 例如,如果借款金额不超过 30%,则将 100 DAI 存入协议的用户最多可以借入价值 30 DAI 的另一种资产。 该协议确定了确切的借款能力百分比。 +然后,用户可以根据他们的需要从其他人那里借入资产和代币(例如,如果你想在 MakerDAO 治理提案中投票,你可以借入 MKR),最高可达他们所存抵押品的一定比例。 例如,如果借款金额不超过 30%,则将 100 DAI 存入协议的用户最多可以借入价值 30 DAI 的另一种资产。 该协议确定了确切的借款能力百分比。 -随着借款人抵押品价值的波动,他们的借款能力也会波动。 如果由于市场波动,借入资产的价值超过其抵押品价值的 30%(同样,准确的百分比由协议确定,协议通常允许任何人清算抵押品,立即偿还贷款人(这类似于传统金融中的 [追加保证金通知](https://www.investopedia.com/terms/m/margincall.asp))。 如果清算,借款人通常必须支付大笔清算费,其中有些是流向变现人的——这是多 MEV 机会出现的地方。 +随着借款人抵押品价值的波动,他们的借款能力也会波动。 如果由于市场波动,借入资产的价值超过其抵押品价值的(比方说)30%(同样,确切的百分比由协议确定),协议通常允许任何人清算抵押品,立即偿还出借人(这类似于传统金融中[追加保证金通知](https://www.investopedia.com/terms/m/margincall.asp)的运作方式)。 如果清算,借款人通常必须支付大笔清算费,其中有些是流向变现人的——这是多 MEV 机会出现的地方。 搜索人竞相以最快的速度解析区块链数据,以确定哪些借款人可以被清算,并成为第一个提交清算交易并自行收取清算费的人。 -### 夹心交易 {#mev-examples-sandwich-trading} +### 三明治攻击 {#mev-examples-sandwich-trading} 夹心交易是另外一种 MEV 提取的常用方法。 为了实现夹心交易,搜索人会监视内存池内 DEX 的大额交易。 例如,有人想要在 Uniswap 上使用 DAI 购买 10,000 UNI。 这类大额交易会对 UNI/DAI 对产生重大的影响,可能会显着提高 UNI 相对于 DAI 的价格。 -搜索人可以计算该大额交易对 UNI/DAI 对的大致价格影响,并在大额交易_之前_立即执行最优买单,低价买入 UNI,然后在大额交易_之后_立即执行卖单,以大额订单造成的更高价格卖出。 +搜索者可以计算出这笔大额交易对 UNI/DAI 交易对的大致价格影响,并在大额交易发生_前_立即执行最优买单,低价买入 UNI,然后在大额交易发生_后_立即执行卖单,以大额订单造成的更高价格卖出。 -然而,夹心交易风险很高,因为它不是原子交易(不像上文所述的 DEX 套利),而且容易受到 [salmonella 攻击](https://github.com/Defi-Cartel/salmonella)。 +然而,三明治攻击风险更高,因为它不是原子性的(不像上文所述的 DEX 套利),而且容易受到[沙门氏菌攻击](https://github.com/Defi-Cartel/salmonella)。 -### 非同质化代币最大可提取价值 {#mev-examples-nfts} +### NFT MEV {#mev-examples-nfts} NFT 领域的 MEV 是一种新兴现象,而且不一定能赚钱。 然而,由于 NFT 交易发生在所有其他以太坊交易共享的同一个区块链上,搜寻者也可以在 NFT 市场上使用与传统 MEV 机会类似的技术。 -例如,如果有一个流行的 NFT 下降,并且搜索者想要某个 NFT 或一组NFT,他们可以写一个交易,使他们成为第一个排队购买 NFT 的人,或者他们可以在一个交易中购买整个 NFT 组合。 或者,如果一个 NFT 被[错误地以低价挂出](https://www.theblockcrypto.com/post/113546/mistake-sees-69000-cryptopunk-sold-for-less-than-a-cent),搜寻者就可以抢在其他购买者前面,低价抢购。 +例如,如果有一个流行的 NFT 下降,并且搜索者想要某个 NFT 或一组NFT,他们可以写一个交易,使他们成为第一个排队购买 NFT 的人,或者他们可以在一个交易中购买整个 NFT 组合。 或者,如果一个 NFT [被错误地以低价挂出](https://www.theblockcrypto.com/post/113546/mistake-sees-69000-cryptopunk-sold-for-less-than-a-cent),搜索者可以抢在其他购买者前面,以低价抢购。 -NFT MEV的一个显著例子发生在一个搜寻者花费 700 万美元来[购买](https://etherscan.io/address/0x650dCdEB6ecF05aE3CAF30A70966E2F395d5E9E5)价格底线的每一个 Cryptopunk。 一位区块链研究员[在Twitter](https://twitter.com/IvanBogatyy/status/1422232184493121538)上解释了买家是如何与 MEV 供应商合作以保持其购买的秘密。 +NFT MEV 的一个著名例子是,一名搜索者花了 700 万美元[买下](https://eth.blockscout.com/address/0x650dCdEB6ecF05aE3CAF30A70966E2F395d5E9E5?tab=txs)地板价的所有 Cryptopunk。 一位区块链研究员[在 Twitter 上解释了](https://twitter.com/IvanBogatyy/status/1422232184493121538)买家是如何与 MEV 提供商合作以对其购买保密的。 -### 长尾 {#mev-examples-long-tail} +### 长尾效应 {#mev-examples-long-tail} DEX 套利、清算和三明治交易都是非常知名的 MEV 机会,对于新的搜寻者来说不太可能获利。 然而,还有一长串鲜为人知的 MEV 机会(NFT MEV 可以说是这样一个机会)。 -刚刚起步的搜索者可能会通过在这个长尾搜索 MEV 而找到更多的成功。 Flashbots 的[MEV 招聘板](https://github.com/flashbots/mev-job-board)列出了一些新兴的机会。 +刚刚起步的搜索者可能会通过在这个长尾搜索 MEV 而找到更多的成功。 Flashbot 的 [MEV 职位公告板](https://github.com/flashbots/mev-job-board)列出了一些新兴机会。 -## 最大可提取价值的影响 {#effects-of-mev} +## MEV 的影响 {#effects-of-mev} MEV 并不都是坏事 - 以太坊的 MEV 既有积极的作用,也有消极的影响。 -### 有利影响 {#effects-of-mev-the-good} +### 优点 {#effects-of-mev-the-good} 许多 DeFi 项目依靠经济上的理性行为者,来确保其协议的有用性和稳定性。 例如,DEX 套利确保用户为他们的代币获得最好、最正确的价格,而借贷协议在借款人低于抵押率时依靠快速清算来确保贷款人得到回报。 如果没有理性的搜索者寻求和修复经济上的低效率,并利用协议的经济激励,DeFi 协议和一般的 dapps 可能不会像今天这样强大。 -### 不利影响 {#effects-of-mev-the-bad} +### 缺点 {#effects-of-mev-the-bad} 在应用层,某些形式的 MEV,如夹心交易,会导致用户的体验明显变差。 被夹在中间的用户面临更高的滑点和更差的交易执行。 在网络层,一般的抢跑者和他们经常参与的矿工费拍卖(当两个或更多的先行者通过逐步提高自己交易的矿工费,从而使他们的交易被打包到下一个区块),导致网络拥堵和试图运行正常交易的其他人的高矿工费。 -除了区块_内_发生的,MEV 也可能会在区块_间_产生有害的影响。 如果区块中可用的最大可提取价值大幅超过标准区块奖励,验证者可能会被激励重组区块并为自己捕获最大可提取价值,从而导致区块链重组和共识不稳定。 +除了区块_内部_发生的情况,MEV 还可能在区块_之间_产生有害影响。 如果区块中可用的最大可提取价值大幅超过标准区块奖励,验证者可能会被激励重组区块并为自己捕获最大可提取价值,从而导致区块链重组和共识不稳定。 -这种区块链重新组织的可能性已经[在以前的比特币区块链上探索过](https://dl.acm.org/doi/10.1145/2976749.2978408)。 随着比特币的区块奖励减半,交易费用占区块奖励的比例越来越大,于是出现了这样的情况:矿工放弃下一个区块的奖励,而用更高的费用重新开采过去的区块,这在经济上变得很合理。 随着 MEV 的发展,以太坊也可能出现同样的情况,威胁到区块链的完整性。 +区块链重组的可能性[先前已在比特币区块链上进行过探讨](https://dl.acm.org/doi/10.1145/2976749.2978408)。 随着比特币的区块奖励减半,交易费用占区块奖励的比例越来越大,于是出现了这样的情况:矿工放弃下一个区块的奖励,而用更高的费用重新开采过去的区块,这在经济上变得很合理。 随着 MEV 的发展,以太坊也可能出现同样的情况,威胁到区块链的完整性。 -## 最大可提取价值的状况 {#state-of-mev} +## MEV 现状 {#state-of-mev} -2021 年初,MEV 开采量剧增,导致今年前几个月的矿工费价格极高。 Flashbots 的 MEV 中继的出现,降低了普通抢跑者的效力,并将矿工费价格拍卖带出链外,降低了普通用户的矿工费。 +2021 年初,MEV 开采量剧增,导致今年前几个月的矿工费价格极高。 Flashbots 的 MEV 中继的出现降低了普通抢跑者的效力,并将燃料费定价带到链下解决。这降低了普通用户的燃料费。 虽然许多搜索者仍然从最大可提取价值赚到了很多钱,但随着机会变得越来越广为人知,越来越多的搜索者争夺相同的机会,验证者将获得越来越多的最大可提取价值总收入(因为如最初描述的相同类型的燃料拍卖也在 Flashbots 中发生,尽管是私下进行的,验证者将获得由此产生的燃料收入)。 MEV 也不是以太坊独有的,随着以太坊上的机会变得越来越有竞争力,搜索者正在转移到其他区块链,如 Binance Smart Chain,那里存在与以太坊上类似的 MEV 机会,但竞争更少。 -另一方面,从工作量证明过渡到权益证明以及持续不断使用卷叠来拓展以太坊,这些都以某种还不太清楚的方式改变着最大可提取价值的格局。 与工作量证明中的概率模型相比,有保障的区块提议者提前一点儿知晓会如何改变最大可提取价值提取的最新格局,以及当[秘密单一领导人选举](https://ethresear.ch/t/secret-non-single-leader-election/11789)和[分布式验证者技术](/staking/dvt/)实现后会如何颠覆当前格局,目前尚未可知。 同样,当大多数用户活动迁离以太坊并转移至其二层网络卷叠和分片时,存在哪些最大可提取价值机会还有待观察。 +另一方面,从工作量证明过渡到权益证明以及持续不断使用卷叠来拓展以太坊,这些都以某种还不太清楚的方式改变着最大可提取价值的格局。 与工作量证明中的概率模型相比,有保障的区块提议者稍稍提前揭晓会如何改变 MEV 提取的动态,以及当[秘密单一领导人选举](https://ethresear.ch/t/secret-non-single-leader-election/11789)和[分布式验证者技术](/staking/dvt/)实现后会如何颠覆当前格局,目前尚未可知。 同样,当大多数用户活动迁离以太坊并转移至其二层网络卷叠和分片时,存在哪些最大可提取价值机会还有待观察。 -## 以太坊权益证明 (PoS) 机制下的最大可提取价值 {#mev-in-ethereum-proof-of-stake} +## 以太坊权益证明 (PoS) 中的 MEV {#mev-in-ethereum-proof-of-stake} 如上所述,最大可提取价值对用户综合体验和共识层安全性产生了不利影响。 但以太坊向权益证明共识的过渡(称为“合并”)还可能带来与最大可提取价值有关的新风险: ### 验证者中心化 {#validator-centralization} -在合并后的以太坊中,验证者(已经存入 32 个以太币作为保证金)就添加到信标链的区块的有效性达成共识。 由于 32 个以太币可能超出了许多人的能力范围,[加入质押池](/staking/pools/)也许是一种更可行的选择。 然而,[单独质押人](/staking/solo/)合理分布才是一种理想状态,因为它削弱了验证者的中心化并且提升了以太坊的安全性。 +在合并后的以太坊中,验证者(已经存入 32 个以太币作为保证金)就添加到信标链的区块的有效性达成共识。 由于 32 ETH 对许多人来说可能遥不可及,[加入质押池](/staking/pools/)或许是更可行的选择。 然而,[独立质押者](/staking/solo/)的健康分布是理想状态,因为它能减轻验证者的中心化程度并提升以太坊的安全性。 -不过,最大可提取价值提取被认为能够加速验证者中心化。 一部分原因是,自从合并以来,由于验证者[提议区块的收益要低于](/roadmap/merge/issuance/#how-the-merge-impacts-ETH-supply)曾经矿工提议区块的收益,[合并](/roadmap/merge/)后最大可提取价值 (MEV) 的提取可能会显著[影响验证者的收益](https://github.com/flashbots/eth2-research/blob/main/notebooks/mev-in-eth2/eth2-mev-calc.ipynb)。 +不过,最大可提取价值提取被认为能够加速验证者中心化。 这部分是由于,自[合并](/roadmap/merge/)以来,验证者[提议区块的收益](/roadmap/merge/issuance/#how-the-merge-impacts-ETH-supply)比以前的矿工少,而 MEV 提取已极大地[影响了验证者的收益](https://github.com/flashbots/eth2-research/blob/main/notebooks/mev-in-eth2/eth2-mev-calc.ipynb)。 -更大的质押池可能会有更多的资源投资进行必要的优化,以抓住最大可提取价值机会。 这些质押池提取的最大可提取价值越多,它们用来提升最大可提取价值提取能力(并增加总收入)的资源就越多,这在本质上形成了[规模经济](https://www.investopedia.com/terms/e/economiesofscale.asp#)。 +更大的质押池可能会有更多的资源投资进行必要的优化,以抓住最大可提取价值机会。 这些质押池提取的 MEV 越多,它们用来提升 MEV 提取能力(并增加总收入)的资源就越多,这在本质上形成了[规模经济](https://www.investopedia.com/terms/e/economiesofscale.asp#)。 由于可支配的资源较少,单独质押人可能无法从最大可提取价值机会中获利。 这种情况可能会增加独立验证者加入强大的质押池以提高收益的压力,从而削弱以太坊的去中心化。 @@ -136,19 +136,19 @@ MEV 并不都是坏事 - 以太坊的 MEV 既有积极的作用,也有消极 许可内存池还会增加上一节中描述的中心化风险。 运行多个验证者的大型池可能会受益于为交易者和用户提供交易隐私,增加其最大可提取价值收入。 -在合并后的以太坊中解决这些与最大可提取价值相关的问题是一个核心研究领域。 迄今为止,为了减少最大可提取价值 (MEV) 在合并后对以太坊的去中心化和安全造成的负面影响,提出了两种解决方案:[**提议者—构建者分离 (PBS) **](/roadmap/pbs/)和[**构建者应用程序接口 (API)**](https://github.com/ethereum/builder-specs)。 +在合并后的以太坊中解决这些与最大可提取价值相关的问题是一个核心研究领域。 迄今为止,为了减少合并后 MEV 对以太坊去中心化和安全性的负面影响,提出了两种解决方案:[**提议者-构建者分离 (PBS)**](/roadmap/pbs/) 和[**构建者应用程序接口**](https://github.com/ethereum/builder-specs)。 ### 提议者-构建者分离 {#proposer-builder-separation} 在工作量证明和权益证明机制中,构建区块的节点面向参与共识的其他节点提出区块以将其添加到链中。 新区块在另一位矿工在其上构建区块(在工作量证明中)后,或从大多数验证者那里获得认证(在权益证明中)后,成为规范链的一部分。 -区块生产者和区块提议者角色的合并造成了大多数前面描述的与最大可提取价值相关的问题。 例如,在[时间强盗攻击中](https://www.mev.wiki/attack-examples/time-bandit-attack),共识节点会被激励触发链重组来最大限度增加最大可提取价值 (MEV)。 +区块生产者和区块提议者角色的合并造成了大多数前面描述的与最大可提取价值相关的问题。 例如,在[时间盗贼攻击](https://www.mev.wiki/attack-examples/time-bandit-attack)中,共识节点会受到激励以触发链重组,从而最大化 MEV 收入。 -[提议者-构建者分离](https://ethresear.ch/t/proposer-block-builder-separation-friendly-fee-market-designs/9725) (PBS) 旨在减轻最大可提取价值的影响,尤其是对共识层的影响。 提议者-构建者分离的主要特点是区块生产者和区块提议者规则的分离。 验证者仍然负责提出区块并投票,但有一类新的特别实体(称为**区块构建者**),其任务是对交易排序和构建区块。 +[提议者-构建者分离](https://ethresear.ch/t/proposer-block-builder-separation-friendly-fee-market-designs/9725) (PBS) 旨在减轻 MEV 的影响,尤其是在共识层。 提议者-构建者分离的主要特点是区块生产者和区块提议者规则的分离。 验证者仍然负责提议区块并对区块进行投票,但一类新的专门实体(称为**区块构建者**)将负责对交易进行排序和构建区块。 在提议者-构建者分离解决方案下,区块构建者创建一个交易包并出价将其包含在信标链区块中(作为“执行有效负载”)。 选中提出下一个区块的验证者随后查看不同的出价,并选择费用最高的交易包。 提议者-构建者分离实际上创建了一个拍卖市场,让构建者和出售区块空间的验证者谈判。 -当前,提议者-构建者分离设计采用一种[提交-披露方案](https://gitcoin.co/blog/commit-reveal-scheme-on-ethereum/),即构建者仅发布对区块内容(区块头)的加密承诺及他们的出价。 在接受成交出价后,提议者创建一个包括区块头的签名区块提案。 区块构建者在看到签名区块提案后可能会发布整个区块体,并且它必须还要从验证者那里获得足够多的[认证](/glossary/#attestation)后才能最终确定区块。 +当前的 PBS 设计采用[承诺-揭示方案](https://gitcoin.co/blog/commit-reveal-scheme-on-ethereum/),构建者仅发布对区块内容(区块头)的加密承诺及其出价。 在接受成交出价后,提议者创建一个包括区块头的签名区块提案。 区块构建者应在看到已签名的区块提议后发布完整的区块主体,并且在最终确定之前,它必须从验证者那里获得足够的[证明](/glossary/#attestation)。 #### 提议者-构建者分离如何减弱最大可提取价值的影响? {#how-does-pbs-curb-mev-impact} @@ -156,15 +156,15 @@ MEV 并不都是坏事 - 以太坊的 MEV 既有积极的作用,也有消极 不过,这并没有完全杜绝验证者与最大可提取价值有关的收入,因为构建者必须出高价才能让验证者接受他们的区块。 然而,由于验证者不再直接关注如何尽可能提高最大可提取价值收入,时间盗贼攻击的威胁降低了。 -提议者-构建者分离也降低了最大可提取价值中心化的风险。 例如,使用提交-披露方案,构建者就去信任验证者不会窃取最大可提取价值机会或将其暴露给其他构建者。 这就降低了单独质押人从最大可提取价值获益的门槛,否则,构建者将倾向于支持有着链下声誉的大型池并与它们进行链下交易。 +提议者-构建者分离也降低了最大可提取价值中心化的风险。 例如,使用提交-披露方案,构建者就去信任验证者不会窃取最大可提取价值机会或将其暴露给其他构建者。 这就降低了单独质押人从最大可提取价值获益的门槛,否则,构建者将倾向于支持有着足够好的链下声誉的大型池并与它们进行链下交易。 同样,验证者不必信任构建者不会隐藏区块体或者发布无效区块,因为付款是无条件的。 即使提出的区块不可用或被其他验证者宣称无效,验证者的费用依然会支付。 在后一种情况下,区块被直接丢弃,迫使区块构建者失去所有交易费和最大可提取价值收入。 ### 构建者应用程序接口 {#builder-api} -虽然提议者-构建者分离有望减弱最大可提取价值提取的影响,但实现它需要对共识协议进行更改。 具体而言,需要更新信标链的[分叉选择](/developers/docs/consensus-mechanisms/pos/#fork-choice)规则。 [构建者应用程序接口](https://github.com/ethereum/builder-specs)是一种临时解决方案,旨在有效实现提议者-构建者分离,然而信任假设更高。 +虽然提议者-构建者分离有望减弱最大可提取价值提取的影响,但实现它需要对共识协议进行更改。 具体来说,信标链上的[分叉选择](/developers/docs/consensus-mechanisms/pos/#fork-choice)规则将需要更新。 [构建者应用程序接口](https://github.com/ethereum/builder-specs)是一种临时解决方案,旨在提供一种可行的提议者-构建者分离实现,尽管其信任假设更高。 -构建者应用程序接口是一种改良版的[引擎应用程序接口](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md),共识层客户端使用它向执行层客户端请求执行有效负载。 正如[诚实验证者规范](https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/validator.md)中所述,选中承担区块提出职责的验证者向连接的执行客户端请求交易包,并将交易包添加到提出的信标链区块中。 +构建者应用程序接口是[引擎应用程序接口](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md)的修改版本,共识层客户端使用它向执行层客户端请求执行有效负载。 正如[诚实验证者规范](https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/validator.md)中所概述的,被选中承担区块提议职责的验证者会向已连接的执行客户端请求一个交易捆绑包,并将其包含在提议的信标链区块中。 构建者应用程序接口还充当验证者和执行层客户端之间的中间件;不同之处是,它允许信标链上的验证者从外部实体获取区块(而不是使用执行客户端在本地构建区块)。 @@ -178,15 +178,16 @@ MEV 并不都是坏事 - 以太坊的 MEV 既有积极的作用,也有消极 4. 在看到盲区块提案时,运行构建者应用程序接口的构建者可能会用完整的执行有效负载响应。 这样,验证者可以创建一个“已签名”信标区块并在整个网络中传播。 -5. 如果区块构建者未能及时响应,使用构建者应用程序接口的验证者仍有可能在本地构建区块,这样他们就不会错过区块提出奖励。 然而,验证者不能使用当前披露的交易或另一个集合创建另一个区块,因为这相当于_模棱两可_(对同一时隙内的两个区块签名),这是一种可受到惩罚的恶行。 +5. 如果区块构建者未能及时响应,使用构建者应用程序接口的验证者仍有可能在本地构建区块,这样他们就不会错过区块提出奖励。 但是,验证者不能使用当前已披露的交易或另一组交易创建另一个区块,因为这相当于_模棱两可_(在同一时隙内签署两个区块),这是一种可被罚没的违规行为。 -构建者应用程序接口的一个示例实现是 [MEV Boost](https://github.com/flashbots/mev-boost),它是对 [Flashbots 拍卖机制](https://docs.flashbots.net/Flashbots-auction/overview/)的改进,旨在抑制最大可提取价值在以太坊上的负面外部性。 Flashbots 拍卖允许权益证明下的验证者将构建可获利区块的工作外包给专门的参与方,称为**搜索者**。 ![详细展示最大可提取价值 (MEV) 流程的图表](./mev.png) +[MEV-Boost](https://github.com/flashbots/mev-boost) 是构建者应用程序接口的一个示例实现,它是对 [Flashbots 拍卖机制](https://docs.flashbots.net/Flashbots-auction/overview)的改进,旨在抑制 MEV 对以太坊的负面外部性。 Flashbots 拍卖允许权益证明中的验证者将构建有利可图区块的工作外包给称为**搜索者**的专门参与方。 +![详细展示 MEV 流程的图表](./mev.png) -搜索者寻找利润丰厚的最大可提取价值机会,并向区块提议者发送交易包以及[价格密封出价](https://en.wikipedia.org/wiki/First-price_sealed-bid_auction),以将交易包纳入到区块中。 运行 mev-geth(go-ethereum (Geth) 客户端的分叉版本)的验证者只需要选择利润最高的交易包,并将其纳为新区块的一部分。 为了避免区块提议者(验证者)收到垃圾交易和无效交易,交易包先通过**中继者**验证然后再到达提议者处。 +搜索者寻找利润丰厚的 MEV 机会,并将交易捆绑包连同[密封价格出价](https://en.wikipedia.org/wiki/First-price_sealed-bid_auction)一起发送给区块提议者,以将其包含在区块中。 运行 mev-geth(go-ethereum (Geth) 客户端的分叉版本)的验证者只需要选择利润最高的交易包,并将其纳为新区块的一部分。 为了保护区块提议者(验证者)免受垃圾信息和无效交易的干扰,交易捆绑包在到达提议者之前会通过**中继者**进行验证。 -MEV Boost 运行机制与原来的 Flashbots 拍卖相同,但增加了一些针对以太坊向权益证明过渡的新功能。 搜索者仍然寻找有利润的交易以便添加到区块中,但一类新的名为**构建者**的专门参与方负责将交易聚合并打包到区块中。 构建者接受搜索者提供的价格密封出价,并进行优化以找到利润最大的排序。 +MEV Boost 运行机制与原来的 Flashbots 拍卖相同,但增加了一些针对以太坊向权益证明过渡的新功能。 搜索者仍然寻找有利可图的 MEV 交易以便加入区块,但一类称为**构建者**的新的专门参与方负责将交易和捆绑包聚合到区块中。 构建者接受搜索者提供的价格密封出价,并进行优化以找到利润最大的排序。 -中继者仍然负责验证交易包并将它们传送给提议者。 然而,MEV Boost 通过存储构建者发送的区块体和验证者发送的区块头,引入了负责提供[数据可用性](/developers/docs/data-availability/)的**托管**。 对于托管,连接到中继的验证者请求可用的执行有效负载,并使用 MEV Boost 的排序算法选择出价 + 最大可提取价值小费最高的有效负载标头。 +中继者仍然负责验证交易包并将它们传送给提议者。 但是,MEV-Boost 引入了**托管**,负责通过存储构建者发送的区块主体和验证者发送的区块头来提供[数据可用性](/developers/docs/data-availability/)。 对于托管,连接到中继的验证者请求可用的执行有效负载,并使用 MEV Boost 的排序算法选择出价 + 最大可提取价值小费最高的有效负载标头。 #### 构建者应用程序接口如何减弱最大可提取价值的影响? {#how-does-builder-api-curb-mev-impact} @@ -204,17 +205,17 @@ MEV Boost 运行机制与原来的 Flashbots 拍卖相同,但增加了一些 - [Flashbots 文档](https://docs.flashbots.net/) - [Flashbots GitHub](https://github.com/flashbots/pm) -- [mevnot.org](https://www.mevboost.org/) - _可提供 MEV-Boost 中继和区块构建者实时统计数据的追踪器_ +- [mevboost.org](https://www.mevboost.org/) - _提供 MEV-Boost 中继和区块构建者实时统计数据的追踪器_ -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [什么是 MEV?](https://blog.chain.link/what-is-miner-extractable-value-mev/) -- [MEV 和我](https://www.paradigm.xyz/2021/02/mev-and-me) -- [以太坊黑暗森林](https://www.paradigm.xyz/2020/08/ethereum-is-a-dark-forest/) +- [什么是矿工可提取价值 (MEV)?](https://blog.chain.link/what-is-miner-extractable-value-mev/) +- [MEV and Me](https://www.paradigm.xyz/2021/02/mev-and-me) +- [以太坊是一座黑暗森林](https://www.paradigm.xyz/2020/08/ethereum-is-a-dark-forest/) - [逃离黑暗森林](https://samczsun.com/escaping-the-dark-forest/) -- [Flashbos:在 MEV 危机中抢跑](https://medium.com/flashbots/frontrunning-the-mev-crisis-40629a613752) -- [@bertcmiller's MEV 评论](https://twitter.com/bertcmiller/status/1402665992422047747) -- [MEV-Boost:直接适用于合并的 Flashbots 架构](https://ethresear.ch/t/mev-boost-merge-ready-flashbots-architecture/11177) +- [Flashbots:抢先应对 MEV 危机](https://medium.com/flashbots/frontrunning-the-mev-crisis-40629a613752) +- [@bertcmiller 的 MEV 系列推文](https://twitter.com/bertcmiller/status/1402665992422047747) +- [MEV-Boost:为合并准备就绪的 Flashbots 架构](https://ethresear.ch/t/mev-boost-merge-ready-flashbots-architecture/11177) - [什么是 MEV Boost](https://www.alchemy.com/overviews/mev-boost) -- [为什么运行 mev-boost?](https://writings.flashbots.net/writings/why-run-mevboost/) +- [为何运行 mev-boost?](https://writings.flashbots.net/writings/why-run-mevboost/) - [以太坊漫游指南](https://members.delphidigital.io/reports/the-hitchhikers-guide-to-ethereum) diff --git a/public/content/translations/zh/developers/docs/networking-layer/index.md b/public/content/translations/zh/developers/docs/networking-layer/index.md index 6fe7ac80655..47df328d01b 100644 --- a/public/content/translations/zh/developers/docs/networking-layer/index.md +++ b/public/content/translations/zh/developers/docs/networking-layer/index.md @@ -1,6 +1,6 @@ --- -title: 网络层 -description: 以太坊网络层简介。 +title: "网络层" +description: "以太坊网络层简介。" lang: zh sidebarDepth: 2 --- @@ -13,7 +13,7 @@ sidebarDepth: 2 ## 前提条件 {#prerequisites} -对以太坊[节点和客户端](/developers/docs/nodes-and-clients/)略有了解将有助于理解本文。 +对以太坊 [节点和客户端](/developers/docs/nodes-and-clients/) 略有了解将有助于理解本文。 ## 执行层 {#execution-layer} @@ -29,23 +29,23 @@ sidebarDepth: 2 发现是在网络中寻找其他节点的过程。 该过程使用一小组引导节点(即地址[硬编码](https://github.com/ethereum/go-ethereum/blob/master/params/bootnodes.go)为客户端的节点,以便它们能被立即找到,并将客户端连接至对等点)进行引导。 这些引导节点旨在将新节点引入一组对等点,这是它们唯一的目的。它们不参与普通的客户端任务,例如同步链,仅在第一次使用客户端时使用。 -节点与引导节点交互所使用的协议是 [Kademlia](https://medium.com/coinmonks/a-brief-overview-of-kademlia-and-its-use-in-various-decentralized-platforms-da08a7f72b8f) 的修改版,它使用[分布式散列表](https://en.wikipedia.org/wiki/Distributed_hash_table)共享节点列表。 每个节点都有一版此表格,其中包含连接到最近节点所需的信息。 这个“最近”不是指地理距离,而是由节点 ID 的相似性来界定的。 每个节点的表格都会定期刷新,作为一种安全特性。 例如,在 [Discv5](https://github.com/ethereum/devp2p/tree/master/discv5) 中,发现协议节点也可以发送显示客户端支持的子协议的聚合发现服务,以便对等点协调通信所用的协议。 +用于节点与引导节点交互的协议是 [Kademlia](https://medium.com/coinmonks/a-brief-overview-of-kademlia-and-its-use-in-various-decentralized-platforms-da08a7f72b8f) 的一种改良形式,它使用[分布式哈希表](https://en.wikipedia.org/wiki/Distributed_hash_table)来共享节点列表。 每个节点都有一版此表格,其中包含连接到最近节点所需的信息。 这个“最近”不是指地理距离,而是由节点 ID 的相似性来界定的。 每个节点的表格都会定期刷新,作为一种安全特性。 例如,在 [Discv5](https://github.com/ethereum/devp2p/tree/master/discv5) 发现协议中,节点也能够发送“广告”,显示客户端支持的子协议,从而允许对等点协商双方都可以用来通信的协议。 -发现过程从 PING-PONG 游戏开始。 一个成功的 PING-PONG 将新节点“连接”到一个启动节点。 提醒引导节点有新节点进入网络的初始消息为 `PING`。 此 `PING` 包括关于新节点、引导节点和过期时间戳的哈希信息。 引导节点接收到 `PING` 返回 `PONG`,其中包含 `PING` 哈希值。 如果 `PING` 和 `PONG` 的哈希值相匹配,新节点和引导节点之间的连接就会得到验证,然后就认为它们已经“绑定”。 +发现过程从 PING-PONG 游戏开始。 一个成功的 PING-PONG 将新节点“连接”到一个启动节点。 提醒引导节点有新节点进入网络的初始消息为 `PING`。 此 `PING` 包括关于新节点、引导节点和过期时间戳的哈希信息。 引导节点接收到 `PING` 并返回一个 `PONG`,其中包含 `PING` 哈希。 如果 `PING` 和 `PONG` 的哈希匹配,那么新节点和引导节点之间的连接就会得到验证,此时它们被称为已“绑定”。 绑定之后,新节点即可向引导节点发送 `FIND-NEIGHBOURS` 请求。 引导节点返回的数据包含一个新节点可以连接的节点列表。 如果这两个节点没有绑定,`FIND-NEIGHBOURS` 请求将失败,新节点将无法进入网络。 新节点从引导节点收到邻居节点列表后,就会开始与每个邻居节点交换 PING-PONG。 成功的 PING-PONG 将新节点与邻居节点绑定在一起,以实现消息交换。 ``` -启动客户端 --> 连接到 bootnode --> 绑定到 bootnode --> 寻找邻居--> 绑定到邻居。 +启动客户端 --> 连接到引导节点 --> 与引导节点绑定 --> 查找邻居节点 --> 与邻居节点绑定 ``` -执行客户端目前使用 [Discv4](https://github.com/ethereum/devp2p/blob/master/discv4.md) 发现协议,并且正在积极迁移到 [Discv5](https://github.com/ethereum/devp2p/tree/master/discv5) 协议。 +执行客户端目前正在使用 [Discv4](https://github.com/ethereum/devp2p/blob/master/discv4.md) 发现协议,并且正在积极地迁移到 [Discv5](https://github.com/ethereum/devp2p/tree/master/discv5) 协议。 #### ENR:以太坊节点记录 {#enr} -[以太坊节点记录 (ENR)](/developers/docs/networking-layer/network-addresses/) 是一个包含三个基本元素的对象:签名(根据某种商定的身份识别方案创建的记录内容的散列)、跟踪记录更改的序号和键:值对的任意列表。 这种格式不会过时,使新对等点之间身份识别信息的交换更加容易,并且是以太坊节点的首选[网络地址](/developers/docs/networking-layer/network-addresses)格式。 +[以太坊节点记录 (ENR)](/developers/docs/networking-layer/network-addresses/) 是一个包含三个基本元素的对象:一个签名(根据某个商定的身份方案生成的记录内容的哈希)、一个跟踪记录变更的序列号,以及一个任意的键值对列表。 这是一种面向未来的格式,能够让新对等点之间更轻松地交换身份识别信息,也是以太坊节点首选的[网络地址](/developers/docs/networking-layer/network-addresses)格式。 #### 发现为什么建立在UDP协议上? {#why-udp} @@ -53,7 +53,7 @@ UDP协议不支持任何错误检查、重新发送失败的数据包,或者 ### DevP2P {#devp2p} -DevP2P 本身就是以太坊为建立和维护对等网络而实施的一整套协议。 新节点进入网络后,它们的交互由 [DevP2P](https://github.com/ethereum/devp2p) 堆栈中的协议管控。 这些操作均基于传输控制协议,包括 RLPx 传输协议、线路协议和若干子协议。 [RLPx](https://github.com/ethereum/devp2p/blob/master/rlpx.md) 是管理启动、验证和维护节点之间会话的协议。 使用 RLP(递归长前缀)的 RLPx 对消息进行编码。递归长度前缀是一种非常节省空间的编码方法,可将数据编码成最小结构,以便在节点之间发送。 +DevP2P 本身就是以太坊为建立和维护对等网络而实施的一整套协议。 新节点进入网络后,它们的交互受 [DevP2P](https://github.com/ethereum/devp2p) 堆栈中的协议管控。 这些操作均基于传输控制协议,包括 RLPx 传输协议、线路协议和若干子协议。 [RLPx](https://github.com/ethereum/devp2p/blob/master/rlpx.md) 是管控节点间会话的发起、验证和维护的协议。 使用 RLP(递归长前缀)的 RLPx 对消息进行编码。递归长度前缀是一种非常节省空间的编码方法,可将数据编码成最小结构,以便在节点之间发送。 两个节点之间的 RLPx 会话始于初始的加密握手。 这需要节点发送身份验证消息,然后等待对方进行验证。 成功验证后,对方会生成身份确认信息,并将信息返回初始节点。 这是一个密钥交换过程,使节点能够私下安全地进行沟通。 成功的加密握手会触发两个节点“在线”互相发送“hello”消息。 线路协议则通过成功地交换“hello”信息发起。 @@ -73,23 +73,23 @@ Hello 消息包含: #### 线路协议 {#wire-protocol} -连接对等点并启动 RLPx 会话后,线路协议定义了对等点间的通信方式。 起初,线路协议定义了三项主要任务:链同步、区块传播和交易交换。 但是当以太坊切换至权益证明之后,区块传播和链同步变为共识层的一部分。 交易交换仍由执行客户端负责。 交易交换所是指在节点之间交换待处理的交易,以便区块构建者能够选择其中一些交易放到下一区块中。 有关这些任务的详细信息可从[这里](https://github.com/ethereum/devp2p/blob/master/caps/eth.md)获取。 支持这些子协议的客户端通过 [JSON-RPC](/developers/docs/apis/json-rpc/) 将自己公开给网络中的其它部分。 +连接对等点并启动 RLPx 会话后,线路协议定义了对等点间的通信方式。 起初,线路协议定义了三项主要任务:链同步、区块传播和交易交换。 但是当以太坊切换至权益证明之后,区块传播和链同步变为共识层的一部分。 交易交换仍由执行客户端负责。 交易交换所是指在节点之间交换待处理的交易,以便区块构建者能够选择其中一些交易放到下一区块中。 关于这些任务的详细信息,请参见[此处](https://github.com/ethereum/devp2p/blob/master/caps/eth.md)。 支持这些子协议的客户端通过 [JSON-RPC](/developers/docs/apis/json-rpc/) 公开它们。 -#### les(以太坊轻客户端子协议) {#les} +#### les (以太坊轻客户端子协议) {#les} -这是用于同步轻量级客户端的最小协议。 传统上很少使用这一协议,因为全部节点都要求在没有任何奖励的情况下向轻量级客户端提供数据。 执行客户端的默认行为不是通过以太坊轻客户端子协议为轻量级客户端数据提供服务。 更多信息请见以太坊轻客户端子协议[规范](https://github.com/ethereum/devp2p/blob/master/caps/les.md)。 +这是用于同步轻量级客户端的最小协议。 传统上很少使用这一协议,因为全部节点都要求在没有任何奖励的情况下向轻量级客户端提供数据。 执行客户端的默认行为不是通过 les 为轻客户端数据提供服务。 更多信息请参阅 les [规范](https://github.com/ethereum/devp2p/blob/master/caps/les.md)。 -#### 快照 {#snap} +#### Snap {#snap} -[快照协议](https://github.com/ethereum/devp2p/blob/master/caps/snap.md#ethereum-snapshot-protocol-snap)是一种可选扩展,该扩展使对等点能够交换最近状态的快照,从而无需下载默克尔前缀树的内部节点就能验证帐户信息和存储的数据。 +[snap 协议](https://github.com/ethereum/devp2p/blob/master/caps/snap.md#ethereum-snapshot-protocol-snap)是一个可选扩展,它允许对等点交换近期状态的快照,从而无需下载中间的默克尔前缀树节点即可验证账户和存储数据。 -#### Wit(见证协议) {#wit} +#### Wit (见证协议) {#wit} -[见证协议](https://github.com/ethereum/devp2p/blob/master/caps/wit.md#ethereum-witness-protocol-wit)也是一种可选扩展,可以使对等点交换彼此的状态见证,从而帮助客户端与链端同步。 +[见证协议](https://github.com/ethereum/devp2p/blob/master/caps/wit.md#ethereum-witness-protocol-wit)是一种可选扩展,支持对等点之间交换状态见证,帮助客户端同步到链的顶端。 -#### 耳语 {#whisper} +#### Whisper {#whisper} -耳语协议旨在实现对等节点之间的安全消息传输,无需向区块链写入任何信息。 它曾是 DevP2P 线路协议的一部分,但现在已经弃用。 其他[相关项目](https://wakunetwork.com/)也存在类似目标。 +耳语协议旨在实现对等节点之间的安全消息传输,无需向区块链写入任何信息。 它曾是 DevP2P 线路协议的一部分,但现在已经弃用。 还有其他具有类似目标的[相关项目](https://wakunetwork.com/)。 ## 共识层 {#consensus-layer} @@ -97,19 +97,19 @@ Hello 消息包含: ### 发现 {#consensus-discovery} -与执行客户端类似,共识客户端使用基于用户数据报协议的 [discv5](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#the-discovery-domain-discv5) 寻找对等点。 Discv5 的共识层实现与执行客户端的不同之处仅在于它包含一个将 discv5 连接到 [libP2P](https://libp2p.io/) 堆栈的适配器,而且弃用了 DevP2P。 执行层的 RLPx 会话已被弃用,取而代之的是 libP2P 的噪声安全信道握手。 +与执行客户端类似,共识客户端也通过 UDP 使用 [discv5](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#the-discovery-domain-discv5) 来查找对等点。 discv5 的共识层实现与执行客户端的实现不同,它包含一个将 discv5 连接到 [libP2P](https://libp2p.io/) 堆栈的适配器,并弃用了 DevP2P。 执行层的 RLPx 会话已被弃用,取而代之的是 libP2P 的噪声安全信道握手。 -### 以太坊节点记录 {#consensus-enr} +### ENR {#consensus-enr} -共识节点的以太坊节点记录包括节点的公钥、IP 地址、用户数据报协议和传输控制协议端口,以及两个共识特定字段:证明子网位字段和 `eth2` 密钥。 前者使节点更容易找到参与特定证明广播子网络的对等点。 `eth2` 密钥包含有关节点正在使用的以太坊分叉的版本信息,以确保对等点连接到正确的以太坊。 +共识节点的 ENR 包括节点的公钥、IP 地址、UDP 和 TCP 端口以及两个共识特定字段:见证子网位域和 `eth2` 密钥。 前者使节点更容易找到参与特定证明广播子网络的对等点。 `eth2` 密钥包含节点正在使用的以太坊分叉版本信息,以确保对等点连接到正确的以太坊。 ### libP2P {#libp2p} LibP2P 堆栈支持发现后的所有通信。 根据其以太坊节点记录的定义,客户端可以在 IPv4 和/或 IPv6 上拨号和收听。 LibP2P 层上的协议可以细分为广播和请求-响应域。 -### 广播 {#gossip} +### Gossip {#gossip} -广播域包括必须在整个网络中快速传播的所有信息。 这包括信标块、证明、认证、退出和罚没。 这是使用 libP2P gossipsub v1 传输的,并且依赖于在每个节点本地存储的各种元数据,包括要接收和传输的广播有效载荷的上限。 有关广播域的详细信息可在[此处](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#the-gossip-domain-gossipsub)找到。 +广播域包括必须在整个网络中快速传播的所有信息。 这包括信标块、证明、认证、退出和罚没。 这是使用 libP2P gossipsub v1 传输的,并且依赖于在每个节点本地存储的各种元数据,包括要接收和传输的广播有效载荷的上限。 关于 gossip 域的详细信息,请参见[此处](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#the-gossip-domain-gossipsub)。 ### 请求-响应 {#request-response} @@ -121,16 +121,16 @@ SSZ 代表简单序列化。 它使用固定偏移量,可以轻松解码编码 ## 连接执行客户端和共识客户端 {#connecting-clients} -共识客户端和执行客户端同时运行。 它们需要彼此连接,这样共识客户端才能向执行客户端提供指令,后者也才能向前者传送需要纳入信标区块的交易捆绑包。 两个客户端之间的通信可通过本地远程过程调用连接实现。 名为[“引擎-API”](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md)的应用程序接口定义两个客户端之间发送的指令。 由于两个客户端共用同一个网络身份,因此它们也共享同一个以太坊节点记录 (ENR),其中包含了每个客户端单独的密钥(eth1 密钥和 eth2 密钥)。 +共识客户端和执行客户端同时运行。 它们需要彼此连接,这样共识客户端才能向执行客户端提供指令,后者也才能向前者传送需要纳入信标区块的交易捆绑包。 两个客户端之间的通信可通过本地远程过程调用连接实现。 一个被称为 ['Engine-API'](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md) 的应用程序接口 (API) 定义了在这两个客户端之间发送的指令。 由于两个客户端共用同一个网络身份,因此它们也共享同一个以太坊节点记录 (ENR),其中包含了每个客户端单独的密钥(eth1 密钥和 eth2 密钥)。 下面显示了控制流摘要,括号中是相关的网络堆栈。 ### 当共识客户端不是区块生产者时: {#when-consensus-client-is-not-block-producer} - 共识客户端通过区块广播协议接收区块(共识对等网络) -- 共识客户端预先验证区块,即确保它来自具有正确元数据的有效发送人 +- 共识客户端预验证区块,即确保区块来自有效的发送者且元数据正确 - 区块中的交易作为执行有效载荷发送到执行层(本地远程过程调用连接) -- 执行层执行交易并验证区块头中的状态(即检查哈希匹配度) +- 执行层执行交易并验证区块头中的状态(即检查哈希是否匹配) - 执行层将验证数据传回共识层,现认为区块已验证(本地远程过程调用连接) - 共识层将区块添加到自己的区块链头并对其进行证明,通过网络广播认证(共识对等网络) @@ -146,10 +146,18 @@ SSZ 代表简单序列化。 它使用固定偏移量,可以轻松解码编码 区块被足够多的验证者认证后,就会被添加到链头,经过合理化并最终确定。 -![](cons_client_net_layer.png) ![](exe_client_net_layer.png) +![](cons_client_net_layer.png) +![](exe_client_net_layer.png) -共识客户端和执行客户端的网络层示意图,取自 [ethresear.ch](https://ethresear.ch/t/eth1-eth2-client-relationship/7248) +共识客户端和执行客户端的网络层示意图,来源:[ethresear.ch](https://ethresear.ch/t/eth1-eth2-client-relationship/7248) -## 延伸阅读 {#further-reading} +## 扩展阅读 {#further-reading} -[DevP2P](https://github.com/ethereum/devp2p) [LibP2p](https://github.com/libp2p/specs) [共识层网络规范](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#enr-structure) [kademlia 至 discv5](https://vac.dev/kademlia-to-discv5) [kademlia 论文](https://pdos.csail.mit.edu/~petar/papers/maymounkov-kademlia-lncs.pdf) [以太坊对等网络简介](https://p2p.paris/en/talks/intro-ethereum-networking/) [以太坊 1/以太坊 2 的关系](http://ethresear.ch/t/eth1-eth2-client-relationship/7248) [合并和以太坊 2 客户端详情视频](https://www.youtube.com/watch?v=zNIrIninMgg) +[DevP2P](https://github.com/ethereum/devp2p) +[LibP2p](https://github.com/libp2p/specs) +[共识层网络规范](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#enr-structure) +[从 kademlia 到 discv5](https://vac.dev/kademlia-to-discv5) +[kademlia 论文](https://pdos.csail.mit.edu/~petar/papers/maymounkov-kademlia-lncs.pdf) +[以太坊点对点 (p2p) 简介](https://p2p.paris/en/talks/intro-ethereum-networking/) +[eth1/eth2 关系](http://ethresear.ch/t/eth1-eth2-client-relationship/7248) +[合并与 eth2 客户端详情视频](https://www.youtube.com/watch?v=zNIrIninMgg) diff --git a/public/content/translations/zh/developers/docs/networking-layer/network-addresses/index.md b/public/content/translations/zh/developers/docs/networking-layer/network-addresses/index.md index ab852225371..d8336984883 100644 --- a/public/content/translations/zh/developers/docs/networking-layer/network-addresses/index.md +++ b/public/content/translations/zh/developers/docs/networking-layer/network-addresses/index.md @@ -1,6 +1,6 @@ --- -title: 网络地址 -description: 网络地址简介 +title: "网络地址" +description: "网络地址简介" lang: zh sidebarDepth: 2 --- @@ -9,11 +9,11 @@ sidebarDepth: 2 ## 前提条件 {#prerequisites} -要理解此页,建议首先了解以太坊的[网络层](/developers/docs/networking-layer/)。 +要理解本页内容,需要对以太坊的[网络层](/developers/docs/networking-layer/)有一定了解。 ## Multiaddr {#multiaddr} -原始以太坊节点地址格式为“multiaddr”(“多地址”的缩写)。 Multiaddr 是一种通用格式,用于对等网络。 地址以键值对表示,键与值之间用正斜杠隔开。 例如,使用 IPv4 地址 `192.168.22.27` 监听 TCP 端口 `33000` 的节点可能具有以下类似的 multiaddr: +原始以太坊节点地址格式为“multiaddr”(“多地址”的缩写)。 Multiaddr 是一种通用格式,用于对等网络。 地址以键值对表示,键与值之间用正斜杠隔开。 例如,一个节点的 IPv4 地址为 `192.168.22.27`,监听 TCP 端口 `33000`,其 multiaddr 如下所示: `/ip4/192.168.22.27/tcp/33000` @@ -31,9 +31,9 @@ Enode 使用 URL 地址格式来识别以太坊节点。 十六进制节点 ID ## 以太坊节点记录 (ENR) {#enr} -以太坊节点记录 (ENR) 是以太坊网络地址的标准格式。 这种地址取代了 multiaddr 和 enode。 由于它们使节点之间能够进行更多的信息交流,因而尤其实用。 以太坊节点记录包含一个签名、序列号和字段,详细说明了用于生成和验证签名的身份识别方案。 以太坊节点记录还可以填充为采用键值对格式的任意数据。 这些键值对包含节点的 IP 地址和节点能够使用的子协议的信息。 共识客户端使用[特定的以太坊节点记录结构](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#enr-structure)来识别引导节点,并包括一个 `eth2` 字段,其中包含有关当前以太坊分叉和认证信息传播子网的信息。上述子网将节点连接至证明被整合在一起的特定对等点集。 +以太坊节点记录 (ENR) 是以太坊网络地址的标准格式。 它们取代了 multiaddr 和 enode。 由于它们使节点之间能够进行更多的信息交流,因而尤其实用。 以太坊节点记录包含一个签名、序列号和字段,详细说明了用于生成和验证签名的身份识别方案。 以太坊节点记录还可以填充为采用键值对格式的任意数据。 这些键值对包含节点的 IP 地址和节点能够使用的子协议的信息。 共识客户端使用[特定的 ENR 结构](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#enr-structure)来识别引导节点,并且还包含一个 `eth2` 字段,其中含有关于当前以太坊分叉和认证信息传播子网的信息(此子网将节点连接到一组特定的对等节点,这些节点的认证被聚合在一起)。 -## 延伸阅读 {#further-reading} +## 扩展阅读 {#further-reading} - [EIP-778:以太坊节点记录 (ENR)](https://eips.ethereum.org/EIPS/eip-778) -- [LibP2P:Multiaddr-Enode-ENR?!](https://consensys.net/diligence/blog/2020/09/libp2p-multiaddr-enode-enr/) +- [LibP2P: Multiaddr-Enode-ENR?!](https://consensys.net/diligence/blog/2020/09/libp2p-multiaddr-enode-enr/) diff --git a/public/content/translations/zh/developers/docs/networking-layer/portal-network/index.md b/public/content/translations/zh/developers/docs/networking-layer/portal-network/index.md index 530c8a5edd5..96bc8597ff5 100644 --- a/public/content/translations/zh/developers/docs/networking-layer/portal-network/index.md +++ b/public/content/translations/zh/developers/docs/networking-layer/portal-network/index.md @@ -1,6 +1,6 @@ --- -title: 门户网络 -description: 门户网络概览 - 旨在为低资源客户端提供支持的开发中网络。 +title: "门户网络" +description: "门户网络概览 - 旨在为低资源客户端提供支持的开发中网络。" lang: zh --- @@ -10,25 +10,25 @@ lang: zh 门户网络是一种针对以太坊的新型网络设计,旨在通过在整个网络以小数据块的形式分享必要的数据,解决“轻”节点的数据可用性问题,让轻节点无需信任全节点或者向其增加额外压力。 -关于[节点和客户端](/developers/docs/nodes-and-clients/)的更多信息 +有关[节点和客户端](/developers/docs/nodes-and-clients/)的更多信息 -## 为什么需要门户网络 {#why-do-we-need-portal-network} +## 我们为什么需要门户网络 {#why-do-we-need-portal-network} 以太坊节点在本地存储以太坊区块链的全部或部分副本。 这个本地副本用来验证交易并确保节点追随正确的链。 这些本地存储的数据让节点能够独立验证传入的数据是否正确有效,而无需信任任何其他实体。 区块链以及相关状态和收据数据的本地副本占用节点硬盘中的大量空间。 例如,要运行使用 [Geth](https://geth.ethereum.org) 搭配一种共识客户端的节点,推荐 2TB 硬盘。 快照同步只存储近期一组区块的链数据,采用这种同步时,Geth 一般占用约 650 GB的磁盘空间但是所需空间以每周大概 14GB 的速度增长(你可以定期将节点删除到 650 GB)。 -这意味着运行节点的成本相当昂贵,因为大量的磁盘空间必须专门给以太坊使用。 以太坊路线图上针对这个问题有几种解决方案,包括[历史数据到期](/roadmap/statelessness/#history-expiry)、[状态数据到期](/roadmap/statelessness/#state-expiry)和[无状态性](/roadmap/statelessness/)。 但是,这些方案很可能要好几年才能实现。 还有不自己保存链数据副本的[轻节点](/developers/docs/nodes-and-clients/light-clients/),它们从全节点请求需要的数据。 然而,这意味着轻节点必须信任全节点会提供诚实的数据,并会给全节点带来压力,它们不得不提供轻节点所需的数据。 +这意味着运行节点的成本相当昂贵,因为大量的磁盘空间必须专门给以太坊使用。 以太坊路线图上有几种解决此问题的方案,包括[历史记录过期](/roadmap/statelessness/#history-expiry)、[状态过期](/roadmap/statelessness/#state-expiry)和[无状态性](/roadmap/statelessness/)。 但是,这些方案很可能要好几年才能实现。 此外还有[轻节点](/developers/docs/nodes-and-clients/light-clients/),它们不保存自己的链数据副本,而是从全节点请求所需的数据。 然而,这意味着轻节点必须信任全节点会提供诚实的数据,并会给全节点带来压力,它们不得不提供轻节点所需的数据。 门户网络旨在提供一种可选方案,让轻节点无需信任全节点或者不会让全节点显著增加工作量,就可以获得需要的数据。 其运作原理是为以太坊节点引入了一种在整个网络中分享数据的新方式。 ## 门户网络如何运作? {#how-does-portal-network-work} -以太坊节点有着严格的协议,协议定义节点如何相互通信。 执行客户端使用一组子协议 [DevP2P](/developers/docs/networking-layer/#devp2p) 通信,而共识客户端使用一组不同的子协议 [libP2P](/developers/docs/networking-layer/#libp2p)。 这些子协议定义了可以在节点间传送的数据类型。 +以太坊节点有着严格的协议,协议定义节点如何相互通信。 执行客户端使用一组名为 [DevP2P](/developers/docs/networking-layer/#devp2p) 的子协议进行通信,而共识客户端则使用一个名为 [libP2P](/developers/docs/networking-layer/#libp2p) 的不同子协议栈。 这些子协议定义了可以在节点间传送的数据类型。 ![devP2P 和 libP2P](portal-network-devp2p-libp2p.png) -节点还能通过 [JSON-RPC 应用程序接口](/developers/docs/apis/json-rpc/)提供特定数据,这就是应用程序和钱包与以太坊节点交换信息的方式。 但是,这些都不是为轻客户端提供数据的理想协议。 +节点还能通过 [JSON-RPC API](/developers/docs/apis/json-rpc/) 提供特定数据,这也是应用和钱包与以太坊节点交换信息的方式。 但是,这些都不是为轻客户端提供数据的理想协议。 轻客户端目前不能通过 DevP2P 或 libP2p 请求特定的链数据,因为这些协议只用于支持链同步和区块与交易的传播。 轻客户端不想要下载这类信息,因为那将无法让它们保持“轻量”。 @@ -36,7 +36,7 @@ JSON-RPC 也不是轻客户端请求数据的理想选择,因为它必须要 门户网络的关键是重新思考整个设计,为轻量化专门设计,摆脱现有以太坊客户端的设计限制。 -门户网络的核心理念是采用目前网络堆栈的精华部分,它利用[分布式哈希表](https://en.wikipedia.org/wiki/Distributed_hash_table),通过轻量级 DevP2P 风格的对等去中心化网络提供轻客户端所需的信息,比如历史数据和当前链头的身份(与 Bittorrent 类似)。 +门户网络的核心思想是借鉴当前网络堆栈的精华,通过一个轻量级 DevP2P 风格的点对点去中心化网络,使用 [DHT](https://en.wikipedia.org/wiki/Distributed_hash_table)(类似于 Bittorrent)来提供轻客户端所需的信息,例如历史数据和当前链头的身份。 这种想法是将以太坊全部历史数据的一小部分和一些特定节点职责添加给每个节点。 然后,通过搜索所请求的特定数据的存储节点,从中检索数据完成请求。 @@ -48,14 +48,14 @@ JSON-RPC 也不是轻客户端请求数据的理想选择,因为它必须要 - 同步最近的和历史链数据 - 检索状态数据 - 广播交易 -- 使用[以太坊虚拟机](/developers/docs/evm/)执行交易 +- 使用 [EVM](/developers/docs/evm/) 执行交易 这种网络设计的优势在于: - 减少对中心化提供者的依赖 - 减少网络带宽使用 - 最小化或零同步 -- 可供资源有限的设备访问(\<1 GB 内存、\<100 MB 磁盘、1 个 CPU) +- 可供资源受限的设备访问(\<1 GB 内存、\<100 MB 磁盘空间、1 个 CPU) 下表展示了门户网络可提供的现有客户端的功能,让用户可在极低资源设备上访问它们。 @@ -67,23 +67,23 @@ JSON-RPC 也不是轻客户端请求数据的理想选择,因为它必须要 | 协议数据 | | | 区块体 | | | | | 收据 | -## 默认支持客户端多样性 {#client-diversity-as-default} +## 默认实现客户端多样性 {#client-diversity-as-default} -门户网络开发者一开始还做出了设计选择:构建三种不同的门户网络客户端。 +门户网络开发者还从一开始就做出了设计选择:构建四个独立的门户网络客户端。 这些门户网络客户端如下: - [Trin](https://github.com/ethereum/trin):用 Rust 编写 -- [Fluffy](https://nimbus.team/docs/fluffy.html):用 Nim 编写 +- [Fluffy](https://fluffy.guide):用 Nim 编写 - [Ultralight](https://github.com/ethereumjs/ultralight):用 Typescript 编写 -- [Shisui](https://github.com/optimism-java/shisui):用 Go 编写 +- [Shisui](https://github.com/zen-eth/shisui):用 Go 编写 多种独立客户端实现提升了以太坊网络的弹性和去中心化。 如果一种客户端遇到问题或者出现漏洞,其他客户端能继续平稳运行,防止单点故障。 另外,多样化的客户端实现促进了创新和竞争,推动改进并降低生态系统内的单一作物风险。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [门户网络(Piper Merriam 在 Devcon Bogota 上的讲解)](https://www.youtube.com/watch?v=0stc9jnQLXA)。 -- [门户网络 discord](https://discord.gg/CFFnmE7Hbs) +- [门户网络(Piper Merriam 在波哥大 Devcon 大会的演讲)](https://www.youtube.com/watch?v=0stc9jnQLXA)。 +- [门户网络 Discord](https://discord.gg/CFFnmE7Hbs) - [门户网络网站](https://www.ethportal.net/) diff --git a/public/content/translations/zh/developers/docs/networks/index.md b/public/content/translations/zh/developers/docs/networks/index.md index 5875cf1cb9b..3cba14ae6e9 100644 --- a/public/content/translations/zh/developers/docs/networks/index.md +++ b/public/content/translations/zh/developers/docs/networks/index.md @@ -1,6 +1,6 @@ --- -title: 网络 -description: 概述以太坊网络以及在何处获得测试网络的以太币来测试你的应用程序。 +title: "网络" +description: "概述以太坊网络以及在何处获得测试网络的以太币来测试你的应用程序。" lang: zh --- @@ -10,7 +10,7 @@ lang: zh ## 前提条件 {#prerequisites} -你应该先了解[以太坊基础知识](/developers/docs/intro-to-ethereum/),然后再深入研究不同的网络,因为测试网络将提供一种低廉、安全的以太坊供你试用。 +你应该先了解[以太坊基础知识](/developers/docs/intro-to-ethereum/),然后再深入研究不同的网络,因为测试网将为你提供一个廉价、安全的以太坊版本来试用。 ## 公共网络 {#public-networks} @@ -20,11 +20,11 @@ lang: zh 主网是指主要的以太坊生态区块链,所有具有实际价值的交易都发生在该链的分散账本中。 -大众和交易所涉及的 ETH 价格是主网的 ETH。 +当人们和交易所讨论 ETH 价格时,他们谈论的是主网 ETH。 ### 以太坊测试网 {#ethereum-testnets} -除了主网外,还有公开的测试网。 这是一种模拟生态环境的网络,协议开发者或智能合约开发者可以使用它们测试尚未部署在主网上的协议升级和智能合约。 你可以把它看作生产与装配服务器的模拟。 +除了主网之外,还有公共测试网。 这些是协议开发者或智能合约开发者用来在部署到主网前,于类似生产的环境中测试协议升级以及潜在智能合约的网络。 你可以把它看作生产与装配服务器的模拟。 在部署到主网之前,你应该在测试网测试编写的任何合约代码。 在与现有智能合约集成的去中心化应用程序中,大多数项目将副本部署到测试网。 @@ -34,57 +34,87 @@ lang: zh #### 我应该使用哪个测试网? -客户端开发者目前还在维护的两个公共测试网是 Sepolia 和 Hoodi。 Sepolia 是一个供合约和应用程序开发者测试其应用程序的网络。 Hoodi 网络是让协议开发者测试网络升级,并让质押人测试运行验证者。 +客户端开发者目前维护的两个公共测试网是 Sepolia 和 Hoodi。 Sepolia 是一个供合约和应用程序开发者测试其应用程序的网络。 Hoodi 网络允许协议开发者测试网络升级,同时让质押者测试运行验证节点。 #### Sepolia {#sepolia} -**Sepolia 是应用程序开发时推荐使用的默认测试网**。 Sepolia 网络使用一种需要许可的验证者设置。 它相对较新,即它的状态和历史记录都非常小。 这意味着网络可以快速同步,并且在其上运行节点需要的存储空间更少。 这对于希望快速启动节点并直接与网络交互的用户来讲,是非常有用的。 - -- 封闭式验证者设置,由客户端和测试团队控制 -- 与其他测试网相比,新测试网部署的应用程序较少 -- 同步速度快,运行节点需要的磁盘空间最小 +**Sepolia 是应用程序开发时推荐使用的默认测试网**。 Sepolia 网络使用一个许可式验证者集,由客户端与测试团队控制。 ##### 资源 - [网站](https://sepolia.dev/) - [GitHub](https://github.com/eth-clients/sepolia) - [Otterscan](https://sepolia.otterscan.io/) -- [Etherscan 区块浏览器](https://sepolia.etherscan.io) +- [Etherscan](https://sepolia.etherscan.io) - [Blockscout](https://eth-sepolia.blockscout.com/) ##### 水龙头 -- [QuickNode Sepolia 水龙头](https://faucet.quicknode.com/drip) -- [Grabteeth](https://grabteeth.xyz/) -- [PoW 水龙头](https://sepolia-faucet.pk910.de/) -- [Coinbase Wallet 水龙头 | Sepolia](https://coinbase.com/faucets/ethereum-sepolia-faucet) -- [Alchemy Sepolia 水龙头](https://sepoliafaucet.com/) -- [Infura Sepolia 水龙头](https://www.infura.io/faucet) +- [Alchemy Sepolia 水龙头](https://www.alchemy.com/faucets/ethereum-sepolia) +- [Chain Platform Sepolia 水龙头](https://faucet.chainplatform.co/faucets/ethereum-sepolia/) - [Chainstack Sepolia 水龙头](https://faucet.chainstack.com/sepolia-testnet-faucet) - [以太坊生态系统水龙头](https://www.ethereum-ecosystem.com/faucets/ethereum-sepolia) +- [ethfaucet.com Sepolia 水龙头](https://ethfaucet.com/networks/ethereum) +- [Google Cloud Web3 Sepolia 水龙头](https://cloud.google.com/application/web3/faucet/ethereum/sepolia) +- [Grabteeth](https://grabteeth.xyz/) +- [Infura Sepolia 水龙头](https://www.infura.io/faucet) +- [PoW 水龙头](https://sepolia-faucet.pk910.de/) +- [QuickNode Sepolia 水龙头](https://faucet.quicknode.com/ethereum/sepolia) #### Hoodi {#hoodi} -_注意:[Goerli 测试网已弃用](https://ethereum-magicians.org/t/proposal-predictable-ethereum-testnet-lifecycle/11575/17),它已被 Hoodi 取代。 请考虑把你的应用程序迁移至 Sepolia。_ - -Hoodi 是用于测试验证和质押的测试网。 Hoodi 网络对想要运行测试网验证者的用户开放。 因此,希望在部署到主网之前测试协议升级的质押人应该使用 Hoodi。 +Hoodi 是用于测试验证和质押的测试网。 Hoodi 网络对想要运行测试网验证者的用户开放。 因此,想在主网部署前测试协议升级的质押者应该使用 Hoodi网络。 -- 开放式验证者设置,质押者可以测试网络升级 -- 状态比较大,用于测试复杂的智能合约交互 +- 开放式验证者组,质押者可以测试网络升级 +- 大规模状态,用于测试复杂的智能合约交互 - 同步时间更长,运行节点需要更多存储空间 ##### 资源 - [网站](https://hoodi.ethpandaops.io/) - [GitHub](https://github.com/eth-clients/hoodi) -- [Explorer](https://explorer.hoodi.ethpandaops.io/) -- [Checkpoint Sync](https://checkpoint-sync.hoodi.ethpandaops.io/) +- [浏览器](https://explorer.hoodi.ethpandaops.io/) +- [检查点同步](https://checkpoint-sync.hoodi.ethpandaops.io/) +- [Otterscan](https://hoodi.otterscan.io/) +- [Etherscan](https://hoodi.etherscan.io/) ##### 水龙头 +- [Chain Platform Hoodi 水龙头](https://faucet.chainplatform.co/faucets/ethereum-hoodi/) - [Hoodi 水龙头](https://hoodi.ethpandaops.io/) +- [PoW 水龙头](https://hoodi-faucet.pk910.de/) + +#### Ephemery {#ephemery} + +Ephemery 是一种独特的测试网,每个月都会彻底重置。 执行和共识状态每 28 天回滚至创世状态,这意味着在测试网上发生的任何事情都是临时的。 这使其非常适合短期测试,节点快速启动以及开发无需数据持久性的 "hello world"((入门级)应用程序。 -要在 Hoodi 测试网上启动验证者,请使用 [Hoodi 启动板](https://hoodi.launchpad.ethereum.org/en/)。 +- 始终新鲜的状态,适用于验证者和应用程序的短期测试 +- 仅包含基本的合约集 +- 开放验证者集,能够轻松访问大量资金 +- 最低的节点要求和最快的同步速度,平均小于 5GB + +##### 资源 + +- [网站](https://ephemery.dev/) +- [Github](https://github.com/ephemery-testnet/ephemery-resources) +- [社区聊天](https://matrix.to/#/#staker-testnet:matrix.org) +- [Blockscout](https://explorer.ephemery.dev/) +- [Otterscan](https://otter.bordel.wtf/) +- [信标浏览器](https://beaconlight.ephemery.dev/) +- [检查点同步](https://checkpoint-sync.ephemery.ethpandaops.io) +- [启动板](https://launchpad.ephemery.dev/) + +#### 水龙头 + +- [Bordel 水龙头](https://faucet.bordel.wtf/) +- [Pk910 PoW 水龙头](https://ephemery-faucet.pk910.de/) + +#### Holesky(已弃用){#holesky} + +Holesky 测试网将于 2025 年 9 月停用。 质押运营商和基础设施提供商应该使用 Hoodi 进行验证者测试。 + +- [Holesky 测试网关闭公告](https://blog.ethereum.org/2025/09/01/holesky-shutdown-announcement) - _以太坊基金会博客,2025 年 9 月 1 日_ +- [Holesky 和 Hoodi 测试网更新](https://blog.ethereum.org/en/2025/03/18/hoodi-holesky) - _以太坊基金会博客,2025 年 3 月 18 日_ ### 二层网络测试网 {#layer-2-testnets} @@ -92,39 +122,59 @@ Hoodi 是用于测试验证和质押的测试网。 Hoodi 网络对想要运行 #### Arbitrum Sepolia {#arbitrum-sepolia} -[Arbitrum](https://arbitrum.io/) 测试网。 +[Arbitrum](https://arbitrum.io/) 的测试网。 + +##### 资源 + +- [Etherscan](https://sepolia.arbiscan.io/) +- [Blockscout](https://sepolia-explorer.arbitrum.io/) ##### 水龙头 -- [Chainlink 水龙头](https://faucets.chain.link/arbitrum-sepolia) -- [Alchemy 水龙头](https://www.alchemy.com/faucets/arbitrum-sepolia) +- [Alchemy Arbitrum Sepolia 水龙头](https://www.alchemy.com/faucets/arbitrum-sepolia) +- [Chainlink Arbitrum Sepolia 水龙头](https://faucets.chain.link/arbitrum-sepolia) +- [ethfaucet.com Arbitrum Sepolia 水龙头](https://ethfaucet.com/networks/arbitrum) +- [QuickNode Arbitrum Sepolia 水龙头](https://faucet.quicknode.com/arbitrum/sepolia) #### Optimistic Sepolia {#optimistic-sepolia} -[Optimism](https://www.optimism.io/) 测试网。 +[Optimism](https://www.optimism.io/) 的测试网。 + +##### 资源 + +- [Etherscan](https://sepolia-optimistic.etherscan.io/) +- [Blockscout](https://optimism-sepolia.blockscout.com/) ##### 水龙头 -- [Chainlink 水龙头](https://faucets.chain.link/optimism-sepolia) - [Alchemy 水龙头](https://www.alchemy.com/faucets/optimism-sepolia) +- [Chainlink 水龙头](https://faucets.chain.link/optimism-sepolia) +- [ethfaucet.com Optimism Sepolia 水龙头](https://ethfaucet.com/networks/optimism) +- [测试网水龙头](https://docs.optimism.io/builders/tools/build/faucets) #### Starknet Sepolia {#starknet-sepolia} [Starknet](https://www.starknet.io) 的测试网。 +##### 资源 + +- [Starkscan](https://sepolia.starkscan.co/) + ##### 水龙头 - [Alchemy 水龙头](https://www.alchemy.com/faucets/starknet-sepolia) +- [Blast Starknet Sepolia 水龙头](https://blastapi.io/faucets/starknet-sepolia-eth) +- [Starknet 水龙头](https://starknet-faucet.vercel.app/) ## 私有网络 {#private-networks} -如果以太坊网络的节点未连接到公共网络( 主网或测试网),则以太坊网络就是私有网络。 在这种情况下,私有仅指保留或隔离,而不是保护或安全。 +如果一个以太坊网络的节点未连接到公共网络(即主网或测试网),那么它就是一个私有网络。 在这种情况下,私有仅指保留或隔离,而不是保护或安全。 ### 开发网络 {#development-networks} 要开发以太坊应用程序,你需要在私有网络上运行该应用程序以了解它的运行情况,然后再进行部署。 如同在自己的计算机上创建用于 Web 开发的本地服务器,你可以创建本地区块链实例来测试你的去中心化应用程序。 这样,迭代将比公共测试网快很多。 -有一些项目和工具专门协助这方面的工作。 进一步了解[开发网络](/developers/docs/development-networks/)。 +有一些项目和工具专门协助这方面的工作。 了解有关[开发网络](/developers/docs/development-networks/)的更多信息。 ### 联盟网络 {#consortium-networks} @@ -132,12 +182,35 @@ Hoodi 是用于测试验证和质押的测试网。 Hoodi 网络对想要运行 如果说公共以太坊网络像公共互联网,那么联盟网络就像私有内部网。 +## 为什么以太坊测试网以地铁站命名? {#why-naming} + +许多以太坊测试网以现实世界中的地铁站或火车站命名。 这一命名传统很早就开始了,它反映了贡献者们生活或工作过的全球城市。 它具有象征意义,令人难忘且实用。 就像测试网与以太坊主网隔离一样,地铁线路也与地面交通分开运行。 + +### 常用测试网和旧测试网 {#common-and-legacy-testnets} + +- **Sepolia** - 希腊雅典一个与地铁相连的社区。 目前用于智能合约和去中心化应用程序测试。 +- **Hoodi** - 以印度班加罗尔的 Hoodi 地铁站命名。 用于验证者和协议升级测试。 +- **Goerli**_(已弃用)_ - 以德国柏林的 Görlitzer Bahnhof 命名。 +- **Rinkeby**_(已弃用)_ - 以斯德哥尔摩一个有地铁站的郊区命名。 +- **Ropsten**_(已弃用)_ - 指斯德哥尔摩的一个地区和前渡轮/地铁总站。 +- **Kovan**_(已弃用)_ - 以新加坡的一个地铁站命名。 +- **Morden**_(已弃用)_ - 以伦敦的一个地铁站命名。 以太坊的第一个公共测试网。 + +### 其他专用测试网 {#other-testnets} + +一些测试网是为短期或特定升级测试而创建的,不一定是以地铁为主题: + +- **Holesky**_(已弃用)_ - 以布拉格的 Holešovice 站命名。 用于验证者测试;于 2025 年弃用。 +- **Kiln**、**Zhejiang**、**Shandong**、**Prater**、**Pyrmont**、**Olympic**_(均已弃用)_和 **Ephemery** - 为“合并”、上海升级等升级模拟或验证者实验而专门构建。 一些名称是地域性或主题性的,而不是基于地铁站。 + +使用地铁站名称有助于开发者快速识别和记住测试网,而无需依赖数字链 ID。 这也反映了以太坊的文化:实用、全球化和以人为本。 + ## 相关工具 {#related-tools} -- [Chainlist](https://chainlist.org/) _ 以太坊虚拟机网络的列表,可将钱包和提供者连接到相应的链 ID 和网络 ID_ -- [基于以太坊虚拟机的链](https://github.com/ethereum-lists/chains) _给 Chainlist 提供支持的 GitHub 链元数据存储库_ +- [Chainlist](https://chainlist.org/) _EVM 网络列表,用于将钱包和提供商连接到相应的链 ID 和网络 ID_ +- [基于 EVM 的链](https://github.com/ethereum-lists/chains) _为 Chainlist 提供支持的链元数据 GitHub 代码库_ -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [提案:可预测的以太坊测试网生命周期](https://ethereum-magicians.org/t/proposal-predictable-ethereum-testnet-lifecycle/11575/17) - [以太坊测试网的演变](https://etherworld.co/2022/08/19/the-evolution-of-ethereum-testnet/) diff --git a/public/content/translations/zh/developers/docs/nodes-and-clients/archive-nodes/index.md b/public/content/translations/zh/developers/docs/nodes-and-clients/archive-nodes/index.md index 4d4295bf8c3..f2e867b4f82 100644 --- a/public/content/translations/zh/developers/docs/nodes-and-clients/archive-nodes/index.md +++ b/public/content/translations/zh/developers/docs/nodes-and-clients/archive-nodes/index.md @@ -1,6 +1,6 @@ --- -title: 以太坊归档节点 -description: 归档节点概述 +title: "以太坊归档节点" +description: "归档节点概述" lang: zh sidebarDepth: 2 --- @@ -9,7 +9,7 @@ sidebarDepth: 2 ## 前提条件 {#prerequisites} -你应该理解[以太坊节点](/developers/docs/nodes-and-clients/)的概念、[它们的架构](/developers/docs/nodes-and-clients/node-architecture/)、[同步策略](/developers/docs/nodes-and-clients/#sync-modes),以及它们的[运行](/developers/docs/nodes-and-clients/run-a-node/)和[使用](/developers/docs/apis/json-rpc/)的实践。 +你应该了解[以太坊节点](/developers/docs/nodes-and-clients/)的概念、[其架构](/developers/docs/nodes-and-clients/node-architecture/)、[同步策略](/developers/docs/nodes-and-clients/#sync-modes)以及[运行](/developers/docs/nodes-and-clients/run-a-node/)和[使用](/developers/docs/apis/json-rpc/)它们的做法。 ## 什么是归档节点 @@ -23,7 +23,7 @@ sidebarDepth: 2 你可以把状态想象成给定区块的瞬时网络快照,而归档是历史回放。 -历史状态可被安全修剪,因为它们对网络的运行不是必要条件,而且对于客户端来说,保留所有过时的数据没有意义。 在某个最近区块之前存在的状态(例如在头部之前 128个 区块)实际上会被丢弃。 全节点只保留历史区块链数据(区块和交易)和偶尔的历史快照,它们可以用来根据请求重新生成较旧的状态。 在以太坊虚拟机中重新执行过往交易就可以做到这一点;当所需状态离最近的快照很远时,可能对计算要求很高。 +历史状态可被安全修剪,因为它们对网络的运行不是必要条件,而且对于客户端来说,保留所有过时的数据没有意义。 在某个最近区块(例如,链头前的 128 个区块)之前存在的状态实际上会被丢弃。 全节点只保留历史区块链数据(区块和交易)和偶尔的历史快照,它们可以用来根据请求重新生成较旧的状态。 在以太坊虚拟机中重新执行过往交易就可以做到这一点;当所需状态离最近的快照很远时,可能对计算要求很高。 然而,这意味着在全节点上访问历史状态会消耗大量计算资源。 客户端可能需要执行从创世块开始的所有过往交易并计算一个历史状态。 归档节点不仅会储存最近的状态,而且还会储存在创建每个区块以后的每个历史状态,进而解决这个问题。 它基本上是以更大的磁盘空间需求为代价。 @@ -35,10 +35,10 @@ sidebarDepth: 2 状态归档的主要好处是快速访问关于历史状态的查询。 例如,归档节点会立即返回以下类似结果: -- _帐户 0x1337…在区块 15537393 时的以太币余额是多少?_ -- _合约 0x 中的代币 0x 在区块 1920000 时的余额是多少?_ +- _账户 0x1337... 的 ETH 余额是多少... 在区块 15537393?_ +- _合约 0x 中的代币 0x 在区块 1920000 的余额是多少?_ -如上所述,一个全节点需要通过以太坊虚拟机执行来生成这些数据,这会消耗 CPU 并花费时间。 归档节点在磁盘上访问它们,并立即提供响应。 此功能对于基础设施的某些部分十分有用,例如: +如上所述,一个全节点需要通过以太坊虚拟机执行来生成这些数据,这会消耗 CPU 并花费时间。 归档节点在磁盘上访问它们,并立即提供响应。 对于基础设施的某些部分,这是一个有用的功能,例如: - 服务提供商,如区块浏览器 - 研究人员 @@ -46,35 +46,36 @@ sidebarDepth: 2 - 去中心化应用程序开发者 - 审计和合规 -还有一些免费[服务](/developers/docs/nodes-and-clients/nodes-as-a-service/)也允许访问历史数据。 由于运行一个归档节点的要求更高,这种访问通常是有限的,只适用于偶尔的访问。 如果你的项目需要不断地访问历史数据,你应该考虑自己运行一个。 +也有各种免费的[服务](/developers/docs/nodes-and-clients/nodes-as-a-service/)允许访问历史数据。 由于运行一个归档节点的要求更高,这种访问通常是有限的,只适用于偶尔的访问。 如果你的项目需要不断地访问历史数据,你应该考虑自己运行一个。 ## 实现和使用 在这种情况下,归档节点意味着由面向用户的执行层客户端提供数据,因为它们要处理状态数据库并提供 JSON-RPC 端点。 配置选项、同步时间和数据库大小可能因客户端而异。 详情请参考你的客户端提供的文档。 -在开始使用你自己的归档节点之前,了解一下客户端之间的差异,特别是各种[硬件要求](/developers/docs/nodes-and-clients/run-a-node/#requirements)。 大多数客户端没有针对这项特性进行优化,它们的归档需要超过 12TB 的空间。 相比之下,像 Erigon 这样的实现可以将相同的数据存储在不到 3TB 的空间内,这使它们成为运行归档节点的最有效方式。 +在启动自己的归档节点之前,请了解客户端之间的差异,特别是各种[硬件要求](/developers/docs/nodes-and-clients/run-a-node/#requirements)。 大多数客户端没有针对此功能进行优化,其归档需要超过 12TB 的空间。 相比之下,像 Erigon 这样的实现可以将相同的数据存储在不到 3TB 的空间内,这使它们成为运行归档节点的最有效方式。 ## 推荐的做法 -除了[运行节点的一般建议](/developers/docs/nodes-and-clients/run-a-node/)以外,归档节点可能对硬件和维护的要求更高。 考虑到 Erigon 的[关键特性](https://github.com/ledgerwatch/erigon#key-features),最实用的方法是使用 [Erigon](/developers/docs/nodes-and-clients/#erigon) 客户端实现。 +除了一般的[运行节点建议](/developers/docs/nodes-and-clients/run-a-node/)外,归档节点可能对硬件和维护的要求更高。 考虑到 Erigon 的[主要功能](https://github.com/ledgerwatch/erigon#key-features),最实用的方法是使用 [Erigon](/developers/docs/nodes-and-clients/#erigon) 客户端实现。 ### 硬件 -始终确保满足客户端文档中给定模式的硬件要求。 归档节点的最大要求是磁盘空间。 根据不同的客户端,此项要求从 3TB 到 12TB 不等。 虽然人们可能认为机械硬盘是更适合存储大量数据的解决方案,不过,同步数据和持续地更新链头需要使用固态硬盘。 [SATA](https://www.cleverfiles.com/help/sata-hard-drive.html) 驱动器足够好,但它应该拥有可靠的质量,至少是 [TLC](https://blog.synology.com/tlc-vs-qlc-ssds-what-are-the-differences) 类型的。 磁盘可以安装在有足够插槽的台式电脑或服务器中。 这样的专用设备是运行高正常运行时间节点的理想选择。 在笔记本上运行是完全可以实现的,代价是需要牺牲一定的便携性。 +始终确保满足客户端文档中给定模式的硬件要求。 +归档节点的最大要求是磁盘空间。 根据不同的客户端,此项要求从 3TB 到 12TB 不等。 虽然人们可能认为机械硬盘是更适合存储大量数据的解决方案,不过,同步数据和持续地更新链头需要使用固态硬盘。 [SATA](https://www.cleverfiles.com/help/sata-hard-drive.html) 硬盘就足够了,但它应该是可靠的质量,至少是 [TLC](https://blog.synology.com/tlc-vs-qlc-ssds-what-are-the-differences)。 磁盘可以安装在有足够插槽的台式电脑或服务器中。 这样的专用设备是运行高正常运行时间节点的理想选择。 在笔记本上运行是完全可以实现的,代价是需要牺牲一定的便携性。 -所有数据需要存放在一个卷中,因此必须对磁盘进行合并,例如采用 [RAID0](https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_0) 方案或 LVM。 你也可以考虑使用 [ZFS](https://en.wikipedia.org/wiki/ZFS),因为它支持“写时复制”,从而确保数据正确地写入磁盘,而不会出现任何低级错误。 +所有数据都需要放在一个卷中,因此必须连接磁盘,例如,使用 [RAID0](https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_0) 或 LVM。 使用 [ZFS](https://en.wikipedia.org/wiki/ZFS) 可能也值得考虑,因为它支持 "Copy-on-write",可确保数据正确写入磁盘,而不会出现任何低级错误。 -为了提高稳定性和安全性,防止发生意外的数据库损坏,你可以在系统支持时考虑使用 [ECC 内存](https://en.wikipedia.org/wiki/ECC_memory),尤其是在专业设置中。 内存大小通常建议与全节点相同,但更大的内存可以帮助加速同步。 +为了在防止意外数据库损坏方面获得更高的稳定性和安全性,尤其是在专业设置中,如果您的系统支持,请考虑使用 [ECC 内存](https://en.wikipedia.org/wiki/ECC_memory)。 内存大小通常建议与全节点相同,但更大的内存可以帮助加速同步。 在初始同步期间,归档模式下的客户端将执行自创世块以来的每笔交易。 执行速度主要受 CPU 限制,所以更快的 CPU 可以帮助缩短初始同步时间。 在一台普通的消费者计算机上,初始同步所需的时间可能长达一个月。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [以太坊全节点 vs 归档节点](https://www.quicknode.com/guides/infrastructure/ethereum-full-node-vs-archive-node) - _QuickNode,2022 年 9 月_ -- [构建你自己的以太坊归档节点](https://tjayrush.medium.com/building-your-own-ethereum-archive-node-72c014affc09) - _Thomas Jay Rush,2021 年 8 月_ -- [如何设置 Erigon、Erigon 的远程过程调用和 TrueBlocks(抓取和应用程序接口)即服务](https://magnushansson.xyz/blog_posts/crypto_defi/2022-01-10-Erigon-Trueblocks) _– Magnus Hansson,2022 年 9 月更新_ +- [以太坊全节点与归档节点](https://www.quicknode.com/guides/infrastructure/ethereum-full-node-vs-archive-node) - _QuickNode,2022 年 9 月_ +- [构建您自己的以太坊归档节点](https://tjayrush.medium.com/building-your-own-ethereum-archive-node-72c014affc09) - _Thomas Jay Rush,2021 年 8 月_ +- [如何将 Erigon、Erigon 的 RPC 和 TrueBlocks(抓取和 API)设置为服务](https://magnushansson.xyz/blog_posts/crypto_defi/2022-01-10-Erigon-Trueblocks) _– Magnus Hansson,2022 年 9 月更新_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [节点和客户端](/developers/docs/nodes-and-clients/) - [运行节点](/developers/docs/nodes-and-clients/run-a-node/) diff --git a/public/content/translations/zh/developers/docs/nodes-and-clients/bootnodes/index.md b/public/content/translations/zh/developers/docs/nodes-and-clients/bootnodes/index.md index 36d2bb54231..8669b6df7a8 100644 --- a/public/content/translations/zh/developers/docs/nodes-and-clients/bootnodes/index.md +++ b/public/content/translations/zh/developers/docs/nodes-and-clients/bootnodes/index.md @@ -1,12 +1,12 @@ --- -title: 以太坊的引导节点介绍 -description: 了解以太坊引导节点所需的基本信息 +title: "以太坊的引导节点介绍" +description: "了解以太坊引导节点所需的基本信息" lang: zh --- 当新节点加入以太坊网络时,它需要连接到已经在网络上的节点,以便在后期发现新的对等节点。 这些进入以太坊网络的节点被称作引导节点。 客户端通常有一个硬编码的引导节点列表。 这些引导节点通常由以太坊基金会的开发团队或客户团队自己运行。 请注意,引导节点与静态节点不同。 静态节点会被重复调用,而引导节点仅在没有足够的对等节点可以连接时被调用,并且需要有一个节点来引导一些新的连接。 -## 连接到引导节点 {#connect-to-a-bootnode} +## 连接至引导节点 {#connect-to-a-bootnode} 大多数客户端都有内置的引导节点列表,但你可能也想运行自己的引导节点,或使用不在客户端硬编码列表中的引导节点。 在这种情况下,你可以在启动客户端时指定这些节点,如下所示(示例为 Geth,请查看你的客户端文档): @@ -16,7 +16,7 @@ geth --bootnodes "enode://@:" ## 运行引导节点 {#run-a-bootnode} -引导节点是不在 NAT([网络地址转换](https://www.geeksforgeeks.org/network-address-translation-nat/))后面的全节点。 只要全节点可以公开访问,它就可以充当引导节点。 +引导节点是不位于 NAT([网络地址转换](https://www.geeksforgeeks.org/network-address-translation-nat/))之后的全节点。 只要全节点可以公开访问,它就可以充当引导节点。 在启动节点时,它应该记录你的 [enode](/developers/docs/networking-layer/network-addresses/#enode),也就是其他人用来连接该节点的公开标识符。 @@ -26,6 +26,6 @@ geth --bootnodes "enode://@:" ## 可用的引导节点 {#available-bootnodes} -请在[此处](https://github.com/ethereum/go-ethereum/blob/master/params/bootnodes.go#L23)查看 go-ethereum 中内建的引导节点列表。 这些引导节点由以太坊基金会和 go-ethereum 团队负责维护。 +go-ethereum 的内置引导节点列表可[在此处](https://github.com/ethereum/go-ethereum/blob/master/params/bootnodes.go#L23)找到。 这些引导节点由以太坊基金会和 go-ethereum 团队负责维护。 你还可以找到一些由志愿者维护的其他引导节点列表。 请务必始终包含至少一个官方引导节点,否则你可能会受到日蚀攻击。 diff --git a/public/content/translations/zh/developers/docs/nodes-and-clients/client-diversity/index.md b/public/content/translations/zh/developers/docs/nodes-and-clients/client-diversity/index.md index 899b267a6c6..f8540e1dfe4 100644 --- a/public/content/translations/zh/developers/docs/nodes-and-clients/client-diversity/index.md +++ b/public/content/translations/zh/developers/docs/nodes-and-clients/client-diversity/index.md @@ -1,6 +1,6 @@ --- -title: 客户端多样性 -description: 概括解释以太坊客户端多样性的重要性。 +title: "客户端多样性" +description: "概括解释以太坊客户端多样性的重要性。" lang: zh sidebarDepth: 2 --- @@ -9,7 +9,7 @@ sidebarDepth: 2 ## 前提条件 {#prerequisites} -如果你还不了解什么是节点和客户端,请查看[节点和客户端](/developers/docs/nodes-and-clients/)。 [执行层](/glossary/#execution-layer)和[共识层](/glossary/#consensus-layer)的定义见词汇表。 +如果您还不了解什么是节点和客户端,请查阅[节点和客户端](/developers/docs/nodes-and-clients/)。 术语表中对[执行层](/glossary/#execution-layer)和[共识层](/glossary/#consensus-layer)进行了定义。 ## 为什么会有多种客户端? {#why-multiple-clients} @@ -23,11 +23,11 @@ sidebarDepth: 2 当代表少数以太坊节点时,一种客户端中的漏洞对网络的风险较小。 由于许多客户端的节点分布大致均匀,大多数客户端出现同一问题的可能性很小,因此网络更加稳健。 -### 抵御攻击 {#resilience} +### 抗攻击能力 {#resilience} -客户端多样性还提供了抵御攻击的能力。 例如,要[欺骗特定客户端](https://twitter.com/vdWijden/status/1437712249926393858)让其接受链的某条分支,这种攻击不太可能成功,因为不大可能以相同方式利用其他客户端,并且规范链未损坏。 客户端多样性程度低增加了主要客户端受到黑客攻击的风险。 已经证实,客户端多样性是抵御网络受到恶意攻击的重要防御手段,例如,由于攻击者能够欺骗主要客户端 (Geth) 对每个区块执行数万次慢速磁盘输入/输出操作,2016 年的上海拒绝服务攻击得以实施。 由于有其他客户端在线且没有同样的漏洞,因此以太坊能够抵抗那次攻击并继续运行,同时修复了 Geth 中的漏洞。 +客户端多样性还提供了抵御攻击的能力。 例如,一种[欺骗特定客户端](https://twitter.com/vdWijden/status/1437712249926393858)使其接受链的特定分叉的攻击不太可能成功,因为其他客户端不太可能以同样的方式被利用,并且规范链仍未损坏。 客户端多样性程度低增加了主要客户端受到黑客攻击的风险。 已经证实,客户端多样性是抵御网络受到恶意攻击的重要防御手段,例如,由于攻击者能够欺骗主要客户端 (Geth) 对每个区块执行数万次慢速磁盘输入/输出操作,2016 年的上海拒绝服务攻击得以实施。 由于有其他客户端在线且没有同样的漏洞,因此以太坊能够抵抗那次攻击并继续运行,同时修复了 Geth 中的漏洞。 -### 权益证明的最终确定性 {#finality} +### 权益证明的确定性 {#finality} 超过 33% 的以太坊节点的共识客户端中有一个漏洞,它可能会阻止共识层的最终确定,这意味着用户无法相信交易不会在某些时候被回滚或更改。 对于许多建立在以太坊之上的应用程序,尤其是去中心化金融,这将是一个很大的问题。 @@ -35,19 +35,45 @@ sidebarDepth: 2 尽管这些情况不太可能发生,但为了降低这类风险,以太坊生态系统可以使客户端均衡分布在活跃节点上。 理想情况下,任何共识客户端任何时候都不会达到总节点数的 33%。 -### 共担责任 {#responsibility} +### 共同责任 {#responsibility} 采用主流客户端也需要人力成本。 这给小型开发团队带来了过多的压力和责任。 客户端多样性程度越低,维护主流客户端的开发者的责任负担就越大。 将这一责任分摊到多个团队,既有利于以太坊节点网络的健康,也有益于相关人员的健康。 -## 客户端多样性现状 {#current-client-diversity} +## 当前客户端多样性 {#current-client-diversity} -![显示客户端多样性的饼状图](./client-diversity.png) _图表数据来自 [ethernodes.org](https://ethernodes.org) 和 [ clientdiversity.org](https://clientdiversity.org/)_ +### 执行客户端 {#execution-clients-breakdown} -上面的两个饼图显示了执行层和共识层客户端多样性现状的快照(在 2022 年 1 月撰写本文时)。 在执行层,[Geth](https://geth.ethereum.org/) 占据绝对主导地位,[Open Ethereum ](https://openethereum.github.io/) 以极大的差距位居第二,[Erigon](https://github.com/ledgerwatch/erigon) 和 [Nethermind](https://nethermind.io/) 分别占据第三和第四,其他客户端加起来占网络的比例不到 1%。 共识层最常用的客户端 [Prysm](https://prysmaticlabs.com/#projects) 不像 Geth 那样占据绝对主导地位,但仍占有网络的 60% 以上。 [Lighthouse](https://lighthouse.sigmaprime.io/) 和 [Teku](https://consensys.net/knowledge-base/ethereum-2/teku/) 分别占据约 20% 和约 14%,其他客户端很少使用。 + -2022 年 1 月 23 日,从 [Ethernodes](https://ethernodes.org) 获得执行层数据。 共识客户端的数据来自 [Michael Sproul](https://github.com/sigp/blockprint)。 共识客户端数据更难获取,因为共识层客户端并不总是具有可以用来识别它们的明确痕迹。 这些数据是使用分类算法生成的,该算法有时会混淆一些非主流客户端(点击[此处](https://twitter.com/sproulM_/status/1440512518242197516)了解更多详细信息)。 在上图中,这些含糊的分类使用了“/”符号进行处理(例如 Nimbus/Teku)。 尽管如此,很明显大部分网络都在运行 Prysm。 这些数据是一组固定区块的快照(在本例中为时隙 2048001 与 2164916 之间的信标区块),Prysm 的主导地位曾经一度更高,超过 68%。 尽管只是快照,但上图中的数值可以让你清晰地了解客户端多样性现状的全局。 +### 共识客户端 {#consensus-clients-breakdown} -现在,可以在 [clientdiversity.org](https://clientdiversity.org/) 查阅最新的共识层客户端多样性数据。 + + +此图表可能已过时 — 请访问 [ethernodes.org](https://ethernodes.org) 和 [clientdiversity.org](https://clientdiversity.org) 获取最新信息。 + +以上两个饼图显示了执行层和共识层当前客户端多样性的快照(撰文时为 2025 年 10 月)。 多年来,客户端多样性已得到改善,执行层中 [Geth](https://geth.ethereum.org/) 的主导地位有所下降,[Nethermind](https://www.nethermind.io/nethermind-client) 紧随其后,[Besu](https://besu.hyperledger.org/) 位列第三,[Erigon](https://github.com/ledgerwatch/erigon) 位列第四,其他客户端占网络的不到 3%。 共识层最常用的客户端 —[Lighthouse](https://lighthouse.sigmaprime.io/)— 的使用率与第二常用的客户端非常接近。 [Prysm](https://prysmaticlabs.com/#projects) 和 [Teku](https://consensys.net/knowledge-base/ethereum-2/teku/) 分别约占 31% 和 14%,而其他客户端则很少被使用。 + +执行层数据于 2025 年 10 月 26 日获取自 [supermajority.info](https://supermajority.info/)。 共识客户端的数据来自 [Michael Sproul](https://github.com/sigp/blockprint)。 共识客户端数据更难获取,因为共识层客户端并不总是具有可以用来识别它们的明确痕迹。 这些数据是使用分类算法生成的,该算法有时会混淆一些非主流客户端(更多详细信息请见[此处](https://twitter.com/sproulM_/status/1440512518242197516))。 在上图中,这些含糊的分类使用了“/”符号进行处理(例如 Nimbus/Teku)。 尽管如此,很明显大部分网络都在运行 Prysm。 尽管只是快照,但上图中的数值可以让你清晰地了解客户端多样性现状的全局。 + +有关共识层客户端多样性的最新数据现在可在 [clientdiversity.org](https://clientdiversity.org/) 上获取。 ## 执行层 {#execution-layer} @@ -55,33 +81,26 @@ sidebarDepth: 2 ## 使用非主流客户端 {#use-minority-client} -解决客户端多样性问题不仅需要个人用户选择非主流客户端,还需要矿池/验证者池以及主要去中心应用程序和交易所等机构改用客户端。 然而,所有用户都可以尽一份力量,纠正目前的失衡状况并且实现所有可用以太坊软件的使用正常化。 合并后,所有节点运营商都需要运行执行客户端和共识客户端。 选择下面建议的客户端组合将有助于提高客户端多样性。 +解决客户端多样性问题,不仅需要个人用户选择非主流客户端——还需要验证者池以及大型去中心化应用程序和交易所这样的机构也一同切换客户端。 然而,所有用户都可以尽一份力量,纠正目前的失衡状况并且实现所有可用以太坊软件的使用正常化。 合并后,所有节点运营商都需要运行执行客户端和共识客户端。 选择下面建议的客户端组合将有助于提高客户端多样性。 ### 执行客户端 {#execution-clients} -[Besu](https://www.hyperledger.org/use/besu) - -[Nethermind](https://downloads.nethermind.io/) - -[Erigon](https://github.com/ledgerwatch/erigon) - -[Go-Ethereum](https://geth.ethereum.org/) +- [Besu](https://www.hyperledger.org/use/besu) +- [Nethermind](https://downloads.nethermind.io/) +- [Erigon](https://github.com/ledgerwatch/erigon) +- [Go-Ethereum](https://geth.ethereum.org/) +- [Reth](https://reth.rs/) ### 共识客户端 {#consensus-clients} -[Nimbus](https://nimbus.team/) +- [Nimbus](https://nimbus.team/) +- [Lighthouse](https://github.com/sigp/lighthouse) +- [Teku](https://consensys.io/teku) +- [Lodestar](https://github.com/ChainSafe/lodestar) +- [Prysm](https://prysm.offchainlabs.com/docs/) +- [Grandine](https://docs.grandine.io/) -[Lighthouse](https://github.com/sigp/lighthouse) - -[Teku](https://consensys.net/knowledge-base/ethereum-2/teku/) - -[Lodestar](https://github.com/ChainSafe/lodestar) - -[Prysm](https://prysm.offchainlabs.com/docs/) - -[Grandine](https://docs.grandine.io/) - -技术用户可以为非主流客户端编写更多教程和相关文档,并鼓励他们运营节点的对等体从主流客户端迁离,帮助加快这一进程。 [clientdiversity.org](https://clientdiversity.org/) 提供了改用非主流共识客户端的指南。 +技术用户可以为非主流客户端编写更多教程和相关文档,并鼓励他们运营节点的对等体从主流客户端迁离,帮助加快这一进程。 有关切换到非主流共识客户端的指南,请访问 [clientdiversity.org](https://clientdiversity.org/)。 ## 客户端多样性仪表板 {#client-diversity-dashboards} @@ -90,22 +109,24 @@ sidebarDepth: 2 **共识层:** - [Rated.network](https://www.rated.network/) -- [clientdiversity.org](https://clientdiversity.org/) **执行层:** +- [clientdiversity.org](https://clientdiversity.org/) + +**执行层:** - [supermajority.info](https://supermajority.info//) - [Ethernodes](https://ethernodes.org/) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [以太坊共识层的客户端多样性](https://mirror.xyz/jmcook.eth/S7ONEka_0RgtKTZ3-dakPmAHQNPvuj15nh0YGKPFriA) -- [以太坊合并:运行主流客户端须自担风险!](https://dankradfeist.de/ethereum/2022/03/24/run-the-majority-client-at-your-own-peril.html) – _Dankrad Fiest,2022 年 3 月 24 日_ +- [以太坊合并:运行多数客户端,风险自负!](https://dankradfeist.de/ethereum/2022/03/24/run-the-majority-client-at-your-own-peril.html) – _Dankrad Fiest,2022 年 3 月 24 日_ - [客户端多样性的重要性](https://our.status.im/the-importance-of-client-diversity/) - [以太坊节点服务列表](https://ethereumnodes.com/) -- [客户端多样性问题的“五个原因”](https://notes.ethereum.org/@afhGjrKfTKmksTOtqhB9RQ/BJGj7uh08) +- [客户端多样性问题的“五个为什么”](https://notes.ethereum.org/@afhGjrKfTKmksTOtqhB9RQ/BJGj7uh08) - [以太坊多样性及其解决方法 (YouTube)](https://www.youtube.com/watch?v=1hZgCaiqwfU) - [clientdiversity.org](https://clientdiversity.org/) -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [运行以太坊节点](/run-a-node/) - [节点和客户端](/developers/docs/nodes-and-clients/) diff --git a/public/content/translations/zh/developers/docs/nodes-and-clients/index.md b/public/content/translations/zh/developers/docs/nodes-and-clients/index.md index b47734a8b67..d5e9b57ee51 100644 --- a/public/content/translations/zh/developers/docs/nodes-and-clients/index.md +++ b/public/content/translations/zh/developers/docs/nodes-and-clients/index.md @@ -1,6 +1,6 @@ --- -title: 节点和客户端 -description: 以太坊节点和客户端软件的概述,以及如何设置节点和为什么应该这样做。 +title: "节点和客户端" +description: "以太坊节点和客户端软件的概述,以及如何设置节点和为什么应该这样做。" lang: zh sidebarDepth: 2 --- @@ -9,9 +9,9 @@ sidebarDepth: 2 ## 前提条件 {#prerequisites} -在更深入地探索并运行自己的以太坊客户端实例之前,你应该先理解对等网络的概念和[以太坊虚拟机基础知识](/developers/docs/evm/)。 请查看我们的[以太坊简介](/developers/docs/intro-to-ethereum/)。 +在更深入地探索并运行自己的以太坊客户端实例之前,你应该先理解对等网络的概念和 [EVM 基础知识](/developers/docs/evm/)。 查看我们的[以太坊简介](/developers/docs/intro-to-ethereum/)。 -如果你不熟悉节点这一主题,我们建议你首先查看便于用户理解的[运行以太坊节点](/run-a-node)介绍。 +如果你不熟悉节点这一主题,我们建议你首先查看我们关于[运行以太坊节点](/run-a-node)的用户友好型简介。 ## 什么是节点和客户端? {#what-are-nodes-and-clients} @@ -20,65 +20,69 @@ sidebarDepth: 2 - 执行客户端(也称为执行引擎、EL 客户端或旧称“以太坊 1”客户端)侦听网络中广播的新交易,并在以太坊虚拟机中执行它们,并保存所有当前以太坊数据的最新状态和数据库。 - 共识客户端(也称为信标节点、CL 客户端或旧称“以太坊 2”客户端)实现权益证明共识算法,使网络能够根据来自执行客户端的经验证数据达成一致。 此外还有名为“验证者”的第三种软件,它们可被添加到共识客户端中,使节点能参与保护网络安全。 -这些客户端软件相互协作,以追踪以太坊的链头,并允许用户与以太坊网络进行交互。 这种模块化设计称为[封装复杂性](https://vitalik.eth.limo/general/2022/02/28/complexity.html),包含多个协同运作的软件。 此方法让无缝实施[合并](/roadmap/merge)变得更简单,客户端软件更易于维护和开发,并且还能重复利用各个客户端(例如在[二层网络生态系统](/layer-2/)当中)。 +这些客户端软件相互协作,以追踪以太坊的链头,并允许用户与以太坊网络进行交互。 这种多个软件协同工作的模块化设计被称为[封装复杂性](https://vitalik.eth.limo/general/2022/02/28/complexity.html)。 此方法可以更轻松地无缝执行[合并](/roadmap/merge),使客户端软件更易于维护和开发,并能够重用各个客户端,例如,在[二层网络生态系统](/layer-2/)中。 -![关联执行和共识客户端](./eth1eth2client.png) 关联执行与共识客户端的简化图。 +![执行客户端和共识客户端的耦合](./eth1eth2client.png) +执行客户端和共识客户端的耦合简化图。 ### 客户端多样性 {#client-diversity} -不同团队开发的各种编程语言中都有[执行客户端](/developers/docs/nodes-and-clients/#execution-clients)和[共识客户端](/developers/docs/nodes-and-clients/#consensus-clients)。 +[执行客户端](/developers/docs/nodes-and-clients/#execution-clients)和[共识客户端](/developers/docs/nodes-and-clients/#consensus-clients)都有由不同团队开发的各种编程语言的版本。 -多种客户端实现减少了对于单一代码库的依赖,使网络更强大。 它的理想目标是实现多样性,即没有任何客户端在网络中占据主导地位,从而排除潜在的单点故障。 语言多样化有助于拓宽开发者社区,并允许他们用自己喜欢的语言创建集成。 +多种客户端实现减少了对于单一代码库的依赖,使网络更强大。 它的理想目标是实现多样性,即没有任何客户端在网络中占据主导地位,从而排除潜在的单点故障。 +语言多样化有助于拓宽开发者社区,并允许他们用自己喜欢的语言创建集成。 -了解有关[客户端多样性](/developers/docs/nodes-and-clients/client-diversity/)的更多信息。 +了解关于[客户端多样性](/developers/docs/nodes-and-clients/client-diversity/)的更多信息。 这些实现的共同点是它们都遵循同一套规范。 这些规范规定了以太坊网络和区块链如何运作。 此外,它们还定义了每项技术细节,你可以在以下内容中了解这些规范: -- 最初为[以太坊黄皮书](https://ethereum.github.io/yellowpaper/paper.pdf) +- 最初,[以太坊黄皮书](https://ethereum.github.io/yellowpaper/paper.pdf) - [执行规范](https://github.com/ethereum/execution-specs/) - [共识规范](https://github.com/ethereum/consensus-specs) -- 在各种[网络升级](/ethereum-forks/)中实现的[以太坊改进提案](https://eips.ethereum.org/) +- 在各种[网络升级](/ethereum-forks/)中实施的 [EIP](https://eips.ethereum.org/) ### 跟踪网络中的节点 {#network-overview} 多种跟踪器提供以太坊网络中节点的实时概览。 请注意,由于去中心化网络的性质,这些爬虫只能提供有限的网络视图,并且可能会报告不同的结果。 -- [节点地图](https://etherscan.io/nodetracker)由 Etherscan 区块浏览器提供 -- [以太坊节点](https://ethernodes.org/)由 Bitfly 提供 +- Etherscan 提供的[节点地图](https://etherscan.io/nodetracker) +- Bitfly 提供的 [Ethernodes](https://ethernodes.org/) - [Nodewatch](https://www.nodewatch.io/) 由 Chainsafe 提供,爬取共识节点 -- [Monitoreth](https://monitoreth.io/) — 由 MigaLabs 开发的分布式网络监测工具 +- [Monitoreth](https://monitoreth.io/) - 由 MigaLabs 开发,一个分布式网络监控工具 +- [每周网络健康报告](https://probelab.io) - 由 ProbeLab 提供,使用 [Nebula 爬虫](https://github.com/dennis-tra/nebula)和其他工具 ## 节点类型 {#node-types} -如果你想[运行自己的节点](/developers/docs/nodes-and-clients/run-a-node/),就应该明白节点有几种类型并且使用数据的方式亦不同。 事实上,客户端可以运行三种类型的节点:轻节点、全节点和归档节点。 其他一些不同的同步策略选项还能缩短同步时间。 同步是指节点能以多快的速度获取最新的以太坊状态信息。 +如果你想要[运行自己的节点](/developers/docs/nodes-and-clients/run-a-node/),你应该了解有不同类型的节点以不同的方式使用数据。 事实上,客户端可以运行三种类型的节点:轻节点、全节点和归档节点。 其他一些不同的同步策略选项还能缩短同步时间。 同步是指节点能以多快的速度获取最新的以太坊状态信息。 ### 全节点 {#full-node} -全节点对区块链进行逐块验证,包括下载和验证每个块的块体和状态数据。 全节点分多种类别——有些全节点从创世区块开始,验证区块链整个历史中的每一个区块。 另一些全节点则从更近期的区块开始验证,而且它们信任这些区块是有效的(如 Geth 的“快照同步”)。 无论验证从哪里开始,全节点只保留相对较新数据的本地副本(通常是最近的 128 个区块),允许删除比较旧的数据以节省磁盘空间。 旧数据可以在需要时重新生成。 +全节点对区块链进行逐块验证,包括下载和验证每个块的块体和状态数据。 全节点分多种类别——有些从创世区块开始,验证整个区块链历史中的每一个区块。 另一些全节点则从更近期的区块开始验证,而且它们信任这些区块是有效的(例如,Geth 的“快照同步”)。 无论验证从哪里开始,全节点只保留相对较新数据的本地副本(通常是最近的 128 个区块),允许删除比较旧的数据以节省磁盘空间。 旧数据可以在需要时重新生成。 - 存储全部区块链数据(会定期修剪,所以全节点并不存储包含创世块在内的所有状态数据) - 参与区块验证,验证所有区块和状态。 - 全节点可以从本地储存中检索所有状态,或从“快照”中重新生成。 - 为网络提供服务,并应要求提供数据。 -### 归档节点 {#archive-node} +### 存档节点 {#archive-node} 归档节点是从创世块开始验证每个区块的全节点,它们从不删除任何下载的数据。 -- 存储全节点中保存的所有内容,并建立历史状态存档。 如果你想查询区块 #4,000,000 的帐户余额,或者想简单可靠地测试自己的一组交易而不使用跟踪挖掘它们,则需要归档节点。 +- 存储全节点中保存的所有内容,并建立历史状态存档。 若你需要查询诸如“区块 #4,000,000 处的帐户余额”这类信息,或是想直接且可靠地测试自己的交易集合(无需通过追踪功能验证交易),则需要用到它。 - 这些数据以太字节为单位,这使得归档节点对普通用户的吸引力较低,但对于区块浏览器、钱包供应商和链分析等服务来说则很方便。 以归档以外的任何方式同步客户端将导致区块链数据被修剪。 这意味着,不存在包含所有历史状态的归档,但全节点能够在需要时构建它们。 -了解有关[归档节点](/developers/docs/nodes-and-clients/archive-nodes)的更多信息。 +了解关于[存档节点](/developers/docs/nodes-and-clients/archive-nodes)的更多信息。 ### 轻节点 {#light-node} -轻节点只下载区块头,而不会下载每个区块。 这些区块头包含区块内容的摘要信息。 轻节点会向全节点请求其所需的任何其他信息。 然后,轻节点可以根据区块头中的状态根独自验证收到的数据。 轻节点可以让用户加入以太坊网络,无需运行全节点所需的功能强大的硬件或高带宽。 最终,轻节点也许能在手机和嵌入式设备中运行。 轻节点不参与共识(即它们不能成为矿工/验证者),但可以访问功能和安全保障和全节点相同的以太坊区块链。 +轻节点只下载区块头,而不会下载每个区块。 这些区块头包含区块内容的摘要信息。 轻节点会向全节点请求其所需的任何其他信息。 然后,轻节点可以根据区块头中的状态根独自验证收到的数据。 轻节点可以让用户加入以太坊网络,无需运行全节点所需的功能强大的硬件或高带宽。 最终,轻节点也许能在手机和嵌入式设备中运行。 轻节点不参与共识过程(即无法作为验证者),但仍能访问以太坊区块链,且具备与全节点相同的功能及安全保障。 -轻客户端是以太坊积极发展的一个领域,我们预计很快就会看到共识层和执行层的新轻客户端。 一些潜在的途径可在[广播网络](https://www.ethportal.net/)上提供轻客户端数据。 这些途径的优点在于,广播网络可以支持轻节点网络而不需要全节点来处理请求。 +轻客户端是以太坊积极发展的一个领域,我们预计很快就会看到共识层和执行层的新轻客户端。 +一些潜在的途径可在[广播网络](https://www.ethportal.net/)上提供轻客户端数据。 这些途径的优点在于,广播网络可以支持轻节点网络而不需要全节点来处理请求。 -以太坊目前还不支持大量轻节点,但轻节点支持是一个有望在不久的将来快速发展的领域。 特别是像 [Nimbus](https://nimbus.team/)、[Helios](https://github.com/a16z/helios) 以及 [LodeStar](https://lodestar.chainsafe.io/) 这样的客户端目前都非常关注轻节点。 +以太坊目前还不支持大量轻节点,但轻节点支持是一个有望在不久的将来快速发展的领域。 特别是,像 [Nimbus](https://nimbus.team/)、[Helios](https://github.com/a16z/helios) 和 [LodeStar](https://lodestar.chainsafe.io/) 这样的客户端目前都非常关注轻节点。 ## 为什么应该运行以太坊节点? {#why-should-i-run-an-ethereum-node} @@ -89,22 +93,22 @@ sidebarDepth: 2 运行你自己的节点使你能够以私密、自给自足的去信任方式使用以太坊。 你去信任网络,因为你可以使用自己的客户端验证数据。 “不要信任,直接验证”是一句在区块链领域非常流行的口头禅。 - 你的节点根据共识规则独自验证所有交易和区块。 这意味着你不必依赖网络中的任何其他节点或完全信任它们。 -- 你可以将以太坊钱包与你自己的节点一起使用。 你可以更安全、更私密地使用去中心化应用程序,因为你不必将地址和余额泄露给中间商。 你可以用自己的客户端检查所有内容。 [MetaMask](https://metamask.io)、[Frame](https://frame.sh/) 和[许多其他钱包](/wallets/find-wallet/)提供远程过程调用导入,这让它们可以使用你的节点。 +- 你可以将以太坊钱包与你自己的节点一起使用。 你可以更安全、更私密地使用去中心化应用程序,因为你不必将地址和余额泄露给中间商。 你可以用自己的客户端检查所有内容。 [MetaMask](https://metamask.io)、[Frame](https://frame.sh/) 和[许多其他钱包](/wallets/find-wallet/)都提供 RPC 导入功能,允许它们使用你的节点。 - 你可以运行和自我托管其他依赖于以太坊数据的服务。 例如,可以是信标链验证者、二层网络等软件、基础设施、区块浏览器、支付机构等。 -- 你可以提供自己的自定义[远程过程调用端点](/developers/docs/apis/json-rpc/)。 你甚至可以公开地向社区提供这些端点,以帮助他们避免与大型中心化供应商合作。 -- 你可以使用**进程间通信 (IPC)** 连接到节点,或者重写节点将你的程序作为插件加载。 这样可以减少网络延迟,例如在使用 web3 库处理大量数据时或者当你需要尽快替换交易时(即抢先交易)会带来很大帮助。 -- 你可以直接质押以太币以保护网络并获得奖励。 请参见[单独质押](/staking/solo/)以便开始操作。 +- 你可以提供自己的自定义 [RPC 端点](/developers/docs/apis/json-rpc/)。 你甚至可以公开地向社区提供这些端点,以帮助他们避免与大型中心化供应商合作。 +- 你可以使用 **Inter-process Communications (IPC)** 连接到你的节点,或者重写该节点以将你的程序作为插件加载。 这样可以减少网络延迟,例如在使用 web3 库处理大量数据时或者当你需要尽快替换交易时(即抢先交易)会带来很大帮助。 +- 你可以直接质押以太币以保护网络并获得奖励。 请参阅[单独质押](/staking/solo/)以开始使用。 -![如何通过你的应用和节点访问以太坊](./nodes.png) +![如何通过你的应用程序和节点访问以太坊](./nodes.png) -### 对网络的好处 {#network-benefits} +### 网络效益 {#network-benefits} -多样化的节点对于以太坊的健康、安全和运行弹性非常重要。 +多种节点对以太坊的健康、安全和运行恢复能力非常重要。 - 全节点强制执行共识规则,因此无法欺骗它们接受不遵循规则的区块。 这在网络中提供了额外的安全性,因为如果所有节点都是轻节点,不进行完整验证,验证者可能会攻击网络。 -- 如果遇到攻击并且攻破了[权益证明](/developers/docs/consensus-mechanisms/pos/#what-is-pos)加密经济防御,全节点可以执行社交恢复以选择跟随最诚实的链。 +- 如果发生攻击并攻破了[权益证明](/developers/docs/consensus-mechanisms/pos/#what-is-pos)的加密经济防御,全节点可以通过选择遵循诚实链来执行社交恢复。 - 网络中的节点越多,网络就更加多样化和更加健壮,这是去中心化的最终目标,可实现一个抗审查的可靠系统。 -- 全节点使依赖区块链数据的轻量级客户端能够访问这些数据。 轻节点不存储整条区块链,而是通过[区块头中的状态根](/developers/docs/blocks/#block-anatomy)验证数据。 如果有需要,它们可以向全节点请求更多信息。 +- 全节点使依赖区块链数据的轻量级客户端能够访问这些数据。 轻节点不存储整个区块链,而是通过[区块头中的状态根](/developers/docs/blocks/#block-anatomy)来验证数据。 如果有需要,它们可以向全节点请求更多信息。 如果你运行一个全节点,整个以太坊网络都会从中受益,即使你没有运行验证者。 @@ -112,13 +116,13 @@ sidebarDepth: 2 是否有兴趣运行你自己的以太坊客户端? -如需适合初学者的简介,请访问我们的[运行节点](/run-a-node)页面以了解更多信息。 +要查看适合初学者的介绍,请访问我们的[运行节点](/run-a-node)页面以了解更多信息。 -如果你是精通技术的用户,请深入了解有关如何[启动你自己的节点](/developers/docs/nodes-and-clients/run-a-node/)的更多详细信息和选项。 +如果你是技术型用户,可以深入了解关于如何[启动你自己的节点](/developers/docs/nodes-and-clients/run-a-node/)的更多详细信息和选项。 -## 替代方法 {#alternatives} +## 替代方案 {#alternatives} -设置自己的节点会耗费你的时间和资源,但你并非总是需要运行自己的实例。 在这种情况下,你可以使用第三方应用程序接口提供商。 有关使用这些服务的概述,请查看[节点即服务](/developers/docs/nodes-and-clients/nodes-as-a-service/)。 +设置自己的节点会耗费你的时间和资源,但你并非总是需要运行自己的实例。 在这种情况下,你可以使用第三方应用程序接口提供商。 要大致了解如何使用这些服务,请查看[节点即服务](/developers/docs/nodes-and-clients/nodes-as-a-service/)。 如果有人在你的社区中运行带有公共应用程序接口的以太坊节点,你可以通过自定义的远程过程调用将你的钱包指向一个社区节点,并获得比一些随机的可信第三方更多的隐私保护。 @@ -126,20 +130,20 @@ sidebarDepth: 2 ## 执行客户端 {#execution-clients} -以太坊社区维护着多种开源的执行客户端(以前名为“以太坊 1 客户端”,或直接被称为“以太坊客户端”),它们由不同的团队使用不同的编程语言开发。 这使得网络更强大、更[多样化](/developers/docs/nodes-and-clients/client-diversity/)。 它的理想目标是实现多样性,即没有任何客户端占据主导地位,从而减少任何单点故障。 +以太坊社区维护着多种开源的执行客户端(以前名为“以太坊 1 客户端”,或直接被称为“以太坊客户端”),它们由不同的团队使用不同的编程语言开发。 这使得网络更强大、更多[样化](/developers/docs/nodes-and-clients/client-diversity/) 它的理想目标是实现多样性,即没有任何客户端占据主导地位,从而减少任何单点故障。 -下表汇总了不同的客户端。 这些客户端均通过[客户端测试](https://github.com/ethereum/tests)并得到积极维护,以保持与网络升级同步。 +下表汇总了不同的客户端。 它们都通过了[客户端测试](https://github.com/ethereum/tests),并得到积极维护,以与网络升级保持同步。 -| 客户端 | 语言 | 操作系统: | 网络 | 同步策略 | 状态缓冲 | -| ---------------------------------------------------------------------- | ---------- | ------------------- | ------------------ | -------------------------------------------------- | -------------- | -| [Geth](https://geth.ethereum.org/) | Go | Linux、Windows、macOS | 主网、Sepolia、Holesky | [快照](#snap-sync)、[完全](#full-sync) | Archive、Pruned | -| [Nethermind](https://www.nethermind.io/) | C#、.NET | Linux、Windows、macOS | 主网、Sepolia、Holesky | [快照](#snap-sync)(不提供服务)、快速、[完全](#full-sync) | Archive、Pruned | -| [Besu](https://besu.hyperledger.org/en/stable/) | Java | Linux、Windows、macOS | 主网、Sepolia、Holesky | [快照](#snap-sync)、[快速](#fast-sync)、[完全](#full-sync) | Archive、Pruned | -| [Erigon](https://github.com/ledgerwatch/erigon) | Go | Linux、Windows、macOS | 主网、Sepolia、Holesky | [完全](#full-sync) | Archive、Pruned | -| [Reth](https://reth.rs/) | Rust语言 | Linux、Windows、macOS | 主网、Sepolia、Holesky | [完全](#full-sync) | Archive、Pruned | -| [EthereumJS](https://github.com/ethereumjs/ethereumjs-monorepo)_(测试版)_ | TypeScript | Linux、Windows、macOS | Sepolia、Holesky | [完全](#full-sync) | 修剪 | +| 客户端 | 语言 | 操作系统: | 网络 | 同步策略 | 状态缓冲 | +| ------------------------------------------------------------------------------------------- | ----------------------- | --------------------- | ---------------- | -------------------------------------------------------- | -------------- | +| [Geth](https://geth.ethereum.org/) | Go | Linux, Windows, macOS | 主网、Sepolia、Hoodi | [快照同步](#snap-sync)、[完全同步](#full-sync) | Archive、Pruned | +| [Nethermind](https://www.nethermind.io/) | C#、.NET | Linux, Windows, macOS | 主网、Sepolia、Hoodi | [快照同步](#snap-sync)(不提供服务)、快速、[完全同步](#full-sync) | Archive、Pruned | +| [Besu](https://besu.hyperledger.org/en/stable/) | Java | Linux, Windows, macOS | 主网、Sepolia、Hoodi | [快照同步](#snap-sync)、[快速同步](#fast-sync)、[完全同步](#full-sync) | Archive、Pruned | +| [Erigon](https://github.com/ledgerwatch/erigon) | Go | Linux, Windows, macOS | 主网、Sepolia、Hoodi | [完全同步](#full-sync) | Archive、Pruned | +| [Reth](https://reth.rs/) | Rust | Linux, Windows, macOS | 主网、Sepolia、Hoodi | [完全同步](#full-sync) | Archive、Pruned | +| [EthereumJS](https://github.com/ethereumjs/ethereumjs-monorepo) _(beta)_ | TypeScript | Linux, Windows, macOS | Sepolia、Hoodi | [完全同步](#full-sync) | 修剪 | -有关受支持网络的更多信息,请仔细阅读[以太坊网络](/developers/docs/networks/)。 +要了解有关受支持网络的更多信息,请阅读[以太坊网络](/developers/docs/networks/)。 每种客户端都有独特的用例和优势,所以你应该根据自己的偏好来选择。 多样性使得实现能够侧重于不同的功能和用户群。 你可能想根据功能、支持、编程语言或许可证选择一种客户端。 @@ -147,7 +151,7 @@ sidebarDepth: 2 Hyperledger Besu 是一种企业级以太坊客户端,面向公共网络和许可网络。 它运行所有以太坊主网功能(从追踪到 GraphQL),可进行大范围监控,并通过开放的社区渠道和企业级商用服务等级协议获得 ConsenSys 支持。 Besu 用 Java 语言编写,并依照 Apache 2.0 获得许可。 -Besu 提供内容丰富的[文档](https://besu.hyperledger.org/en/stable/),以指导你了解有关其功能和设置的所有详细信息。 +Besu 的大量[相关文档](https://besu.hyperledger.org/en/stable/)将引导你了解其功能和设置的所有详细信息。 ### Erigon {#erigon} @@ -155,9 +159,9 @@ Erigon 以前称为 Turbo‐Geth,最初是 Go Ethereum 的一个分叉,注 ### Go Ethereum {#geth} -Go Ethereum(简称 Geth)是以太坊协议的原始实现之一。 目前,它是使用最为广泛的客户端,拥有最大的用户群,为用户和开发者提供各种工具。 Geth 用 Go 语言编写,完全开源,并依照 GNU LGPL v3 获得许可。 +Go Ethereum(简称 Geth)是以太坊协议的原始实现之一。 目前,它是使用最为广泛的客户端,拥有最大的用户群,为用户和开发者提供各种工具。 它用 Go 语言编写,完全开源,并依照 GNU LGPL v3 获得许可。 -在[相关文档](https://geth.ethereum.org/docs/)中了解有关 Geth 的更多信息。 +在其[相关文档](https://geth.ethereum.org/docs/)中了解有关 Geth 的更多信息。 ### Nethermind {#nethermind} @@ -167,7 +171,7 @@ Nethermind 是使用 C# .NET 技术栈创建的以太坊实现,依照 LGPL-3.0 - 状态访问 - 联网和丰富的功能,如 Prometheus/Grafana 仪表板、seq 企业日志支持、JSON-RPC 跟踪和分析插件。 -Nethermind 也有[详细的相关文档](https://docs.nethermind.io)、强大的开发支持、在线社区,并为高级用户提供全天候支持。 +Nethermind 还有[详细的相关文档](https://docs.nethermind.io),强大的开发者支持、一个在线社区,并为高级用户提供全天候支持。 ### Reth {#reth} @@ -175,9 +179,9 @@ Reth(Rust 以太坊的简称)是一个以太坊全节点实现,专注于 Reth 已达到生产就绪,适用于质押或高正常运行时间服务之类的关键任务环境。 在需要大裕度高性能保证的使用案例中表现良好,例如远程过程调用、最大可提取价值、索引、模拟和对等网络活动。 -查看 [Reth Book](https://reth.rs/) 或 [Reth GitHub 仓库](https://github.com/paradigmxyz/reth?tab=readme-ov-file#reth)了解更多信息。 +通过查看 [Reth Book](https://reth.rs/) 或 [Reth GitHub 存储库](https://github.com/paradigmxyz/reth?tab=readme-ov-file#reth)了解更多信息。 -### 开发中的客户端 {#execution-in-development} +### 开发中 {#execution-in-development} 以下客户端仍处于早期开发阶段,尚不建议用于生产。 @@ -185,58 +189,58 @@ Reth 已达到生产就绪,适用于质押或高正常运行时间服务之类 EthereumJS 执行客户端 (EthereumJS) 是用 TypeScript 编写的,由许多包组成,包括由区块、交易和默克尔帕特里夏树类表示的核心以太坊原语和核心客户端组件(包括以太坊虚拟机 (EVM) 的实现、区块链类和 DevP2P 网络堆栈)。 -通过阅读其[相关文档](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master)了解更多信息 +通过阅读其[相关文档](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master),了解关于它的更多信息 ## 共识客户端 {#consensus-clients} -有多种共识客户端(以前称为“以太坊 2 客户端”)支持[共识升级](/roadmap/beacon-chain/)。 它们负责所有共识相关的逻辑,包括分叉选择算法、处理认证与管理[权益证明](/developers/docs/consensus-mechanisms/pos)奖励及惩罚。 +有多个共识客户端(以前称为“Eth2”客户端)来支持[共识升级](/roadmap/beacon-chain/)。 它们负责所有共识相关的逻辑,包括分叉选择算法、处理认证和管理[权益证明](/developers/docs/consensus-mechanisms/pos)的奖励和惩罚。 -| 客户端 | 语言 | 操作系统: | 网络 | -| ------------------------------------------------------------- | ---------- | ------------------- | ------------------------------------ | -| [Lighthouse](https://lighthouse.sigmaprime.io/) | Rust | Linux、Windows、macOS | 信标链、Holesky、Pyrmont、Sepolia 等 | -| [Lodestar](https://lodestar.chainsafe.io/) | TypeScript | Linux、Windows、macOS | 信标链、Holesky、Sepolia 等 | -| [Nimbus](https://nimbus.team/) | Nim | Linux、Windows、macOS | 信标链、Holesky、Sepolia 等 | -| [Prysm](https://prysm.offchainlabs.com/docs/) | Go | Linux、Windows、macOS | 信标链、Gnosis、Holesky、Pyrmont、Sepolia 等 | -| [Teku](https://consensys.net/knowledge-base/ethereum-2/teku/) | Java | Linux、Windows、macOS | 信标链、Gnosis、Holesky、Sepolia 等 | -| [Grandine](https://docs.grandine.io/) | Rust语言 | Linux、Windows、macOS | 信标链、Holesky、Sepolia 等 | +| 客户端 | 语言 | 操作系统: | 网络 | +| ------------------------------------------------------------- | ---------- | --------------------- | ---------------------------------- | +| [Lighthouse](https://lighthouse.sigmaprime.io/) | Rust | Linux, Windows, macOS | 信标链、Hoodi、Pyrmont、Sepolia 等 | +| [Lodestar](https://lodestar.chainsafe.io/) | TypeScript | Linux, Windows, macOS | 信标链、Hoodi、Sepolia 等 | +| [Nimbus](https://nimbus.team/) | Nim | Linux, Windows, macOS | 信标链、Hoodi、Sepolia 等 | +| [Prysm](https://prysm.offchainlabs.com/docs/) | Go | Linux, Windows, macOS | 信标链、Gnosis、Hoodi、Pyrmont、Sepolia 等 | +| [Teku](https://consensys.net/knowledge-base/ethereum-2/teku/) | Java | Linux, Windows, macOS | 信标链、Gnosis、Hoodi、Sepolia 等 | +| [Grandine](https://docs.grandine.io/) | Rust | Linux, Windows, macOS | 信标链、Hoodi、Sepolia 等 | ### Lighthouse {#lighthouse} Lighthouse 是一种共识客户端实现,它用 Rust 语言编写,并依照 Apache-2.0 获得许可。 它由 Sigma Prime 维护,自信标链创世以来一直保持稳定且可直接投入生产。 各类企业、质押池和个人都依赖它。 从台式电脑到复杂的自动化部署,Lighthouse 的目标是在各种环境中实现安全、高性能和互操作性。 -你可以在 [Lighthouse 手册](https://lighthouse-book.sigmaprime.io/)中找到相关文档。 +可以在 [Lighthouse Book](https://lighthouse-book.sigmaprime.io/) 中找到相关文档 ### Lodestar {#lodestar} Lodestar 是一种生产就绪型共识客户端实现,它用 Typescript 语言编写,并依照 LGPL-3.0 获得许可。 它由 ChainSafe Systems 维护,是面向单独质押人、开发者和研究人员的最新共识客户端。 Lodestar 由信标节点和验证者客户端组成,并由以太坊协议的 JavaScript 实现提供支持。 Lodestar 旨在通过轻客户端提高以太坊的可用性,为更多开发者扩展可访问性,并进一步提高生态系统多样性。 -你可以在 [Lodestar 网站](https://lodestar.chainsafe.io/)上了解更多信息。 +更多信息请访问 [Lodestar 网站](https://lodestar.chainsafe.io/) ### Nimbus {#nimbus} Nimbus 是一种共识客户端实现,它用 Nim 语言编写,并依照 Apache-2.0 获得许可。 它是一种供单独质押人和质押池使用的生产就绪型客户端。 Nimbus 专为提高资源效率而设计,可同样轻松地在资源有限的设备和企业级基础设施上运行,并且不会影响稳定性或奖励性能。 更少的资源占用意味着客户端在网络处于压力下时具有更大的安全边际。 -在 [Nimbus 相关文档](https://nimbus.guide/)中了解更多信息 +在 [Nimbus 文档](https://nimbus.guide/)中了解更多信息 ### Prysm {#prysm} Prysm 是一种功能齐全的开源共识客户端,它用 Go 语言编写,并依照 GPL-3.0 获得许可。 它具有可选的 Web 应用程序用户界面,并将单独质押人和机构用户的用户体验、相关文档和可配置性放在首位。 -访问 [Prysm 相关文档](https://prysm.offchainlabs.com/docs/)以了解更多信息。 +访问 [Prysm 文档](https://prysm.offchainlabs.com/docs/)以了解更多信息。 ### Teku {#teku} Teku 是最早的信标链创世客户端之一。 除了常规目标(安全性、稳健性、稳定性、可用性、性能)外,Teku 还特别致力于恪守全部各类共识客户端标准。 -Teku 提供了非常灵活的部署选项。 信标节点和验证者客户端可以作为单个进程一起运行,这对于单独质押人来说非常方便;或者在处理复杂的质押操作时,节点也可以各自运行。 此外,Teku 实现了与 [Web3Signer](https://github.com/ConsenSys/web3signer/) 的完全互操作性,用于为密钥安全性签名并提供罚没防范措施。 +Teku 提供了非常灵活的部署选项。 信标节点和验证者客户端可以作为单个进程一起运行,这对于单独质押人来说非常方便;或者在处理复杂的质押操作时,节点也可以各自运行。 此外,Teku 可与 [Web3Signer](https://github.com/ConsenSys/web3signer/) 完全互操作,以确保签名密钥安全和提供罚没防范措施。 -Teku 用 Java 语言编写,并依照 Apache 2.0 获得许可。 它由 ConsenSys 的 Protocols 团队开发,该团队还要对 Besu 和 Web3Signer 负责。 在 [Teku 相关文档](https://docs.teku.consensys.net/en/latest/)中了解更多信息。 +Teku 用 Java 语言编写,并依照 Apache 2.0 获得许可。 它由 ConsenSys 的 Protocols 团队开发,该团队还要对 Besu 和 Web3Signer 负责。 在 [Teku 文档](https://docs.teku.consensys.net/en/latest/)中了解更多信息。 ### Grandine {#grandine} Grandine 是一种依据 GPL-3.0 许可的共识客户端实现,使用 Rust 语言编写。 它由 Grandine 核心团队维护,快速、高效且轻量。 它适合各种类型的质押者,从运行低资源设备(如树莓派设备)的单独质押者,到运行数万个验证者的机构质押者。 -你可以在 [Grandine 手册](https://docs.grandine.io/)中找到相关文档 +相关文档可以在 [Grandine Book](https://docs.grandine.io/) 中找到 ## 同步模式 {#sync-modes} @@ -252,10 +256,10 @@ Grandine 是一种依据 GPL-3.0 许可的共识客户端实现,使用 Rust 完全同步会下载所有区块(包括区块头和区块体),并通过执行自创世块以来的每个区块,以增量方式重新生成区块链的状态。 -- 通过验证每笔交易,最大限度地减少信任并实现最高安全性。 -- 随着交易数量的增加,处理所有交易可能需要几天到几周时间。 +- 通过验证每笔交易,最大限度地减少信任问题并实现最高安全性。 +- 随着交易数量的增加,完全同步掉所有交易可能需要花费几天到几周时间。 -[存档节点](#archive-node)会执行完全同步,以构建(并保留)每个区块中每笔事务所做的状态更改的完整历史记录。 +[存档节点](#archive-node)执行完全同步,以构建(并保留)每个区块中每笔交易造成的状态变化的完整历史记录。 #### 快速同步 {#fast-sync} @@ -277,10 +281,10 @@ Grandine 是一种依据 GPL-3.0 许可的共识客户端实现,使用 Rust 轻客户端模式下载所有区块头和区块数据,并对其中一些进行随机验证。 仅从可信的检查点同步链的头部。 -- 仅获取最新状态,同时依赖于对开发者和共识机制的信任。 -- 客户端在几分钟内便可以使用当前网络状态。 +- 依赖于对开发者和共识机制的信任,仅获取最新状态。 +- 几分钟内客户端便可以使用并且具有当前网络状态。 -**注意**:轻量同步暂不支持权益证明以太坊,新版本轻量同步应该很快就会发布! +**注意**:轻量同步尚不适用于权益证明以太坊——新版本的轻量同步应该很快就会发布! [关于轻客户端的更多信息](/developers/docs/nodes-and-clients/light-clients/) @@ -288,28 +292,28 @@ Grandine 是一种依据 GPL-3.0 许可的共识客户端实现,使用 Rust #### 乐观同步 {#optimistic-sync} -乐观同步是一种合并后同步策略,专为选择加入和向后兼容而设计,允许执行节点通过已确立的方法进行同步。 执行引擎可以在不进行完全验证的情况下_乐观地_导入信标区块,找到最新区块头,然后使用上述方法开始同步链。 接着,在执行客户端更新之后,它将通知共识客户端信标链中交易的有效性。 +乐观同步是一种合并后同步策略,专为选择加入和向后兼容而设计,允许执行节点通过已确立的方法进行同步。 执行引擎可以_乐观地_导入信标区块而无需完全验证它们,找到最新的区块头,然后用上述方法开始同步链。 接着,在执行客户端更新之后,它将通知共识客户端信标链中交易的有效性。 [关于乐观同步的更多信息](https://github.com/ethereum/consensus-specs/blob/dev/sync/optimistic.md) #### 检查点同步 {#checkpoint-sync} -检查点同步也称为“弱主观性同步”,在同步信标节点时可提供卓越的用户体验。 它基于[弱主观性](/developers/docs/consensus-mechanisms/pos/weak-subjectivity/)假设,因而能够从最近的弱主观性检查点而不是从创世块同步信标链。 检查点同步可大幅加快初始同步速度,其信任假设与从[创世块](/glossary/#genesis-block)同步时类似。 +检查点同步也称为“弱主观性同步”,在同步信标节点时可提供卓越的用户体验。 它基于[弱主观性](/developers/docs/consensus-mechanisms/pos/weak-subjectivity/)的假设,因而能够从最近的弱主观性检查点而不是创世块同步信标链。 检查点同步使初始同步时间大大加快,其信任假设与从[创世块](/glossary/#genesis-block)同步类似。 在实践中,这意味着你的节点会连接到远程服务,以下载最近的最终确定状态并从该点继续验证数据。 提供数据的第三方会受到信任,因此要谨慎选择。 关于[检查点同步](https://notes.ethereum.org/@djrtwo/ws-sync-in-practice)的更多信息 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [以太坊 101 - 第二部分 - 了解节点](https://kauri.io/ethereum-101-part-2-understanding-nodes/48d5098292fd4f11b251d1b1814f0bba/a) _– Wil Barnes,2019 年 2 月 13 日_ -- [运行以太坊全节点:勉励者指南](https://medium.com/@JustinMLeroux/running-ethereum-full-nodes-a-guide-for-the-barely-motivated-a8a13e7a0d31) _– Justin Leroux,2019 年 11 月 7 日_ +- [以太坊 101 - 第 2 部分 - 理解节点](https://kauri.io/ethereum-101-part-2-understanding-nodes/48d5098292fd4f11b251d1b1814f0bba/a) _– Wil Barnes, 2019 年 2 月 13 日_ +- [运行以太坊全节点:一份写给勉强有动力的人的指南](https://medium.com/@JustinMLeroux/running-ethereum-full-nodes-a-guide-for-the-barely-motivated-a8a13e7a0d31) _– Justin Leroux, 2019 年 11 月 7 日_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [区块](/developers/docs/blocks/) - [网络](/developers/docs/networks/) ## 相关教程 {#related-tutorials} -- [通过写入 MicroSD 卡将树莓派 4 变成验证者节点 – 安装指南](/developers/tutorials/run-node-raspberry-pi/) _– 写入你的树莓派 4,插入网线,连接固态硬盘并给设备供电,将树莓派 4 变成运行执行层(主网)和/或共识层(信标链/验证者)的以太坊全节点。_ +- [只需烧录 MicroSD 卡,即可将你的树莓派 4 变成一个验证者节点 – 安装指南](/developers/tutorials/run-node-raspberry-pi/)_– 烧录你的树莓派 4,插入以太网电缆,连接 SSD 硬盘并为设备通电,即可将树莓派 4 变成一个运行执行层 (Mainnet) 和/或共识层(信标链/验证者)的以太坊全节点。_ diff --git a/public/content/translations/zh/developers/docs/nodes-and-clients/light-clients/index.md b/public/content/translations/zh/developers/docs/nodes-and-clients/light-clients/index.md index d127e52e0a9..74d535e7000 100644 --- a/public/content/translations/zh/developers/docs/nodes-and-clients/light-clients/index.md +++ b/public/content/translations/zh/developers/docs/nodes-and-clients/light-clients/index.md @@ -1,18 +1,18 @@ --- -title: 轻客户端 -description: 以太坊轻客户端介绍。 +title: "轻客户端" +description: "以太坊轻客户端介绍。" lang: zh --- 运行全节点是与以太坊交互时最具去信任性、私密、去中心化而且抗审查性的方式。 借助全节点,你可以保留自己的区块链副本,从而即时查询并直接访问以太坊的点对点网络。 然而,运行全节点需要大量的内存、存储空间和 CPU 资源。 这意味着并不是每个人都能够运行自己的节点。 以太坊的发展路线图提供了多种解决方案,其中包括无状态性,但它还需要几年才能实现。 近期能实现的解决方法是放弃一些全节点的优点,以换取大幅度的性能提升,从而使节点可以在非常低的硬件要求下运行。 使用轻节点就是经权衡的做法。 -## 什么是轻客户端? {#what-is-a-light-client} +## 什么是轻客户端 {#what-is-a-light-client} 轻节点是指运行轻量级客户端软件的节点。 它们不保留区块链数据的本地副本,也不独立验证所有更改,而是向一些提供商请求必要的数据。 提供商可能直接或通过某些中心化远程过程调用服务器和全节点连接。 然后,轻节点会验证数据,使其和链头保持同步。 轻节点仅处理区块头,只会偶尔下载实际的区块内容。 节点的轻量程度可能有所不同,具体取决于它们所运行的轻客户端和完整客户端软件的组合。 例如,最轻量级的配置可能是运行一个轻量级执行客户端和一个轻量级共识客户端。 许多节点也可能选择运行轻量级共识客户端和完整的执行客户端,或者轻量级执行客户端和完整的共识客户端。 ## 轻客户端如何运作? {#how-do-light-clients-work} -以太坊在采用基于权益证明的共识机制时,引入了专门用于支持轻客户端的全新基础架构。 其工作原理是每隔 1.1 天随机选择一个包含 512 个验证者的子集,用于充当**同步委员会**。 同步委员会会在最新区块的头部签名。 每个区块头包含同步委员会中所有验证者的聚合签名,以及显示已签名和未签名验证者的“位域”。 每个区块头还包含预计参加下一个区块签名的验证者列表。 这意味着轻客户端可以迅速查看同步委员会是否已经为收到的数据提供签名,而且它们还可以通过比较收到的信息和在上一个区块中得到的预期信息,来验证同步委员会的真实性。 这样,轻客户端就可以不断更新其对最新以太坊区块的了解,而无需下载区块本身,因为区块头就包含有摘要信息。 +以太坊在采用基于权益证明的共识机制时,引入了专门用于支持轻客户端的全新基础架构。 其工作原理是每隔 1.1 天随机选择一个包含 512 个验证者的子集,用于充当**同步委员会**。 同步委员会会在最新区块的头部签名。 每个区块头都包含同步委员会中验证者的聚合签名,以及一个显示哪些验证者已签名、哪些未签名的“位域”。 每个区块头还包含预计参加下一个区块签名的验证者列表。 这意味着轻客户端可以迅速查看同步委员会是否已经为收到的数据提供签名,而且它们还可以通过比较收到的信息和在上一个区块中得到的预期信息,来验证同步委员会的真实性。 这样,轻客户端就可以不断更新其对最新以太坊区块的了解,而无需下载区块本身,因为区块头就包含有摘要信息。 在执行层,没有针对轻量级执行客户端的单一规范。 轻量级执行客户端的范围可以是完整的执行客户端的“轻量级模式”,具有全节点的所有以太坊虚拟机和网络功能,但只验证区块头而不下载相关数据;它也可以是更简化的客户端,极度依赖向远程过程调用转发请求以便和以太坊进行交互。 @@ -32,7 +32,7 @@ lang: zh 能够在存储空间、内存和处理能力都非常小的设备上运行以太坊节点,这是轻客户端开启的主要创新领域之一。 如今,以太坊节点需要大量计算资源,而轻客户端可以嵌入到浏览器、在手机上运行,甚至可能在智能手表等更小的设备上运行。 这意味着带有嵌入式客户端的以太坊钱包可以在手机上运行。 因为移动钱包不必信任其数据的中心化提供商,所以它们可以更加分散。 -启用**物联网 (IoT)** 设备是它的延伸。 借助同步委员会提供的所有安全保证,轻客户端可被用于快速证明某些代币余额或非同质化代币的所有权,从而触发物联网网络上的某些操作。 试想一下,[自行车租赁服务](https://youtu.be/ZHNrAXf3RDE?t=929)使用带有嵌入式轻客户端的应用程序快速验证你是否拥有租赁服务的非同质化代币;如果是,则为你解锁一辆自行车,让你骑走! +这项技术的延伸应用是启用**物联网 (IoT)** 设备。 借助同步委员会提供的所有安全保证,轻客户端可被用于快速证明某些代币余额或非同质化代币的所有权,从而触发物联网网络上的某些操作。 试想一下,某个[自行车租赁服务](https://youtu.be/ZHNrAXf3RDE?t=929)使用带有嵌入式轻客户端的应用程序,快速验证你是否拥有该租赁服务的 NFT,如果验证通过,则为你解锁一辆自行车,让你骑走! 以太坊卷叠也将受益于轻客户端。 以太坊卷叠存在一些严重问题,其中之一是黑客会攻击允许资金从以太坊主网转移到卷叠的链桥。 卷叠用来检测用户是否已存款到链桥的预言机是它的一个漏洞。 如果预言机馈送错误数据,它们会使卷叠误以为用户已存款到链桥并错误地释放资金。 嵌入到卷叠的轻客户端可被用于防范遭破坏的预言机,因为存入链桥的存款可能附带证明,而卷叠可在释放任何代币前对该证明进行验证。 同样的概念也可适用于其他链间桥。 @@ -42,20 +42,20 @@ lang: zh 正在开发的轻客户端有很多种,包括执行、共识和结合执行/共识的轻客户端。 以下是我们在撰写本页时所知的轻客户端实现: -- [Lodestar](https://github.com/ChainSafe/lodestar/tree/unstable/packages/light-client):TypeScript 中的共识轻客户端 -- [Helios](https://github.com/a16z/helios):Rust 中的执行和共识组合轻客户端 -- [Geth](https://github.com/ethereum/go-ethereum/tree/master/beacon/light):Go语言编写的执行客户端(开发中)轻量级模式 -- [Nimbus](https://nimbus.guide/el-light-client.html):Nim 中的共识轻客户端 +- [Lodestar](https://github.com/ChainSafe/lodestar/tree/unstable/packages/light-client):用 TypeScript 编写的共识轻客户端 +- [Helios](https://github.com/a16z/helios):用 Rust 编写的执行和共识组合轻客户端 +- [Geth](https://github.com/ethereum/go-ethereum/tree/master/beacon/light):执行客户端的轻模式(Go 语言,开发中) +- [Nimbus](https://nimbus.guide/el-light-client.html):用 Nim 语言编写的共识轻客户端 据我们所知,这些轻客户端都还没部署到生产环境。 -轻客户端访问以太坊数据的方式还有很大改进空间。 目前,轻客户端依赖于使用客户端/服务器模式向全节点发出远程过程调用请求,但将来可以借助专用网络(如[门户网络](https://www.ethportal.net/))以更加去中心化的方式请求数据,该网络可以使用点对点广播协议向轻客户端提供数据。 +轻客户端访问以太坊数据的方式还有很大改进空间。 目前,轻客户端依赖于使用客户端/服务器模式向全节点发出 RPC 请求,但在未来,可以借助 [Portal Network](https://www.ethportal.net/) 等专用网络,以更去中心化的方式请求数据,该网络可以通过点对点广播协议向轻客户端提供数据。 -其他[路线图](/roadmap/)项,如[沃克尔树](/roadmap/verkle-trees/)和[无状态性](/roadmap/statelessness/)等,终将为轻客户端带来与全客户端同等的安全保障。 +其他[路线图](/roadmap/)项目,如 [Verkle 树](/roadmap/verkle-trees/)和[无状态性](/roadmap/statelessness/),最终将为轻客户端带来与全客户端同等的安全保障。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [Zsolt Felfodhi - Geth 轻客户端](https://www.youtube.com/watch?v=EPZeFXau-RE) -- [Etan Kissling - 轻客户端网络](https://www.youtube.com/watch?v=85MeiMA4dD8) -- [Etan Kissling - 合并后的轻客户端](https://www.youtube.com/watch?v=ZHNrAXf3RDE) -- [Piper Merriam - 通往功能性轻客户端的曲折道路](https://snakecharmers.ethereum.org/the-winding-road-to-functional-light-clients/) +- [Zsolt Felfodhi 谈 Geth 轻客户端](https://www.youtube.com/watch?v=EPZeFXau-RE) +- [Etan Kissling 谈轻客户端网络](https://www.youtube.com/watch?v=85MeiMA4dD8) +- [Etan Kissling 谈合并后的轻客户端](https://www.youtube.com/watch?v=ZHNrAXf3RDE) +- [Piper Merriam:通往功能性轻客户端的曲折之路](https://snakecharmers.ethereum.org/the-winding-road-to-functional-light-clients/) diff --git a/public/content/translations/zh/developers/docs/nodes-and-clients/node-architecture/index.md b/public/content/translations/zh/developers/docs/nodes-and-clients/node-architecture/index.md index d182d9c15a3..17157b815b3 100644 --- a/public/content/translations/zh/developers/docs/nodes-and-clients/node-architecture/index.md +++ b/public/content/translations/zh/developers/docs/nodes-and-clients/node-architecture/index.md @@ -1,28 +1,28 @@ --- -title: 节点架构 -description: 关于如何组织以太坊节点的介绍。 +title: "节点架构" +description: "关于如何组织以太坊节点的介绍。" lang: zh --- -以太坊节点由[执行客户端](/developers/docs/nodes-and-clients/#execution-clients)和[共识客户端](/developers/docs/nodes-and-clients/#consensus-clients)这两种客户端构成。 对于要提议新区块的节点,还必须运行[验证者客户端](#validators)。 +一个以太坊节点由两个客户端组成:一个[执行客户端](/developers/docs/nodes-and-clients/#execution-clients)和一个[共识客户端](/developers/docs/nodes-and-clients/#consensus-clients)。 节点若要提议新区块,还必须运行一个[验证者客户端](#validators)。 -当以太坊使用[工作量证明](/developers/docs/consensus-mechanisms/pow/)时,执行客户端足以运行以太坊全节点。 然而,在实施[权益证明](/developers/docs/consensus-mechanisms/pow/)以后,执行客户端必须与另一种名为[共识客户端](/developers/docs/nodes-and-clients/#consensus-clients)的软件搭配使用。 +当以太坊使用[工作量证明](/developers/docs/consensus-mechanisms/pow/)时,一个执行客户端就足以运行一个完整的以太坊节点。 然而,自实施[权益证明](/developers/docs/consensus-mechanisms/pow/)以来,执行客户端必须与另一个名为[共识客户端](/developers/docs/nodes-and-clients/#consensus-clients)的软件一起使用。 以下图表显示了两种以太坊客户端之间的关系。 这两种客户端与其各自的点对点(对等)网络连接。 分离对等网络是有必要的,因为执行客户端通过它们的对等网络广播交易,确保它们能够管理自己的本地交易池,同时共识客户端通过它们的对等网络广播区块,保证共识和链增长。 ![](node-architecture-text-background.png) -_执行客户端的选择有很多,包括 Erigon、Nethermind 和 Besu_。 +_执行客户端有多种选择,包括 Erigon、Nethermind 和 Besu_。 -要使这种双客户端结构发挥作用,共识客户端必须将大量交易传递给执行客户端。 执行客户端本地执行这些交易,以验证这些交易没有违反任何以太坊规则、提议的以太坊状态更新是正确的。 当节点被选为区块生产者时,它的共识客户端实例从执行客户端请求各种交易,以便将它们添加到新的区块,并通过执行它们来更新全局状态。 共识客户端通过本地 RPC 连接,使用[引擎应用程序接口](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md)驱动执行客户端。 +要使这种双客户端结构发挥作用,共识客户端必须将大量交易传递给执行客户端。 执行客户端本地执行这些交易,以验证这些交易没有违反任何以太坊规则、提议的以太坊状态更新是正确的。 当节点被选为区块生产者时,它的共识客户端实例从执行客户端请求各种交易,以便将它们添加到新的区块,并通过执行它们来更新全局状态。 共识客户端通过使用[引擎 API](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md) 的本地 RPC 连接来驱动执行客户端。 ## 执行客户端的作用是什么? {#execution-client} -执行客户端负责交易验证、交易处理、交易广播、状态管理和支持以太坊虚拟机([EVM](/developers/docs/evm/))。 它**不**负责区块构建、区块广播或处理共识逻辑。 这些都是共识客户端的责任。 +执行客户端负责交易验证、处理和广播,以及状态管理和支持以太坊虚拟机 ([EVM](/developers/docs/evm/))。 它**不**负责区块构建、区块广播或处理共识逻辑。 这些都是共识客户端的责任。 -执行客户端会创建执行有效负载——交易列表、更新状态树和其他与执行相关的数据。 共识客户端在每个区块中添加执行有效负载。 执行客户端还要在新的区块中重新执行交易,以确保其有效性。 执行交易在执行客户端的嵌入式计算机中完成,这些计算机被称为[以太坊虚拟机 (EVM)](/developers/docs/evm)。 +执行客户端会创建执行有效负载——交易列表、更新状态树和其他与执行相关的数据。 共识客户端在每个区块中添加执行有效负载。 执行客户端还要在新的区块中重新执行交易,以确保其有效性。 执行交易是在执行客户端的嵌入式计算机上完成的,该计算机被称为[以太坊虚拟机 (EVM)](/developers/docs/evm)。 -执行客户端还通过[远程过程调用方法](/developers/docs/apis/json-rpc)提供用户界面,让用户可以查询以太坊区块链、提交交易和部署智能合约。 远程过程调用通常由 [Web3js](https://docs.web3js.org/)、[Web3py](https://web3py.readthedocs.io/en/v5/) 这样的库处理,或者由浏览器钱包等用户界面处理。 +执行客户端还通过 [RPC 方法](/developers/docs/apis/json-rpc)为以太坊提供用户界面,用户可以通过这些方法查询以太坊区块链、提交交易和部署智能合约。 RPC 调用通常由 [Web3js](https://docs.web3js.org/)、[Web3py](https://web3py.readthedocs.io/en/v5/) 等库或浏览器钱包等用户界面处理。 简而言之,执行客户端是: @@ -43,17 +43,17 @@ _执行客户端的选择有很多,包括 Erigon、Nethermind 和 Besu_。 ## 节点组件比较 {#node-comparison} -| 执行客户端 | 共识客户端 | 验证者 | -| -------------------------- | ----------------- | ------------ | -| 通过其对等网络广播交易 | 通过其对等网络广播区块和认证 | 提议区块 | -| 执行/重新执行交易 | 运行分叉选择算法 | 累积奖励/惩罚 | -| 验证传入的状态更改 | 追踪链头 | 认证 | -| 管理状态和收据树 | 管理信标状态(包含共识和执行信息) | 需要质押 32 个以太币 | -| 创建执行有效负载 | 跟踪 RanDAO 中累积的随机性 | 可被罚没 | -| 公开 JSON-RPC 应用程序接口以便与以太坊交互 | 追踪合理化和最终确定 | | +| 执行客户端 | 共识客户端 | 验证者 | +| -------------------------- | -------------------------------------------- | ------------ | +| 通过其对等网络广播交易 | 通过其对等网络广播区块和认证 | 提议区块 | +| 执行/重新执行交易 | 运行分叉选择算法 | 累积奖励/惩罚 | +| 验证传入的状态更改 | 追踪链头 | 认证 | +| 管理状态和收据树 | 管理信标状态(包含共识和执行信息) | 需要质押 32 个以太币 | +| 创建执行有效负载 | 追踪 RANDAO(一种为验证者选择和其他共识操作提供可验证随机性的算法)中累计的随机性 | 可被罚没 | +| 公开 JSON-RPC 应用程序接口以便与以太坊交互 | 追踪合理化和最终确定 | | -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [权益证明](/developers/docs/consensus-mechanisms/pos) -- [提出区块](/developers/docs/consensus-mechanisms/pos/block-proposal) -- [验证者奖惩](/developers/docs/consensus-mechanisms/pos/rewards-and-penalties) +- [区块提议](/developers/docs/consensus-mechanisms/pos/block-proposal) +- [验证者奖励和惩罚](/developers/docs/consensus-mechanisms/pos/rewards-and-penalties) diff --git a/public/content/translations/zh/developers/docs/nodes-and-clients/nodes-as-a-service/index.md b/public/content/translations/zh/developers/docs/nodes-and-clients/nodes-as-a-service/index.md index 37526266521..0001b76efd8 100644 --- a/public/content/translations/zh/developers/docs/nodes-and-clients/nodes-as-a-service/index.md +++ b/public/content/translations/zh/developers/docs/nodes-and-clients/nodes-as-a-service/index.md @@ -1,23 +1,23 @@ --- -title: 节点即服务 -description: 节点服务及其利弊和主流供应商的入门级概述。 +title: "节点即服务" +description: "节点服务及其利弊和主流供应商的入门级概述。" lang: zh sidebarDepth: 2 --- ## 简介 {#Introduction} -运行自己的 [以太坊](/developers/docs/nodes-and-clients/#what-are-nodes-and-clients)节点可能会比较困难,特别是在刚开始时或在快速扩展时。 [许多服务](#popular-node-services)都可以为你运行优化的节点基础设施,藉此,你可以专注于开发你的应用程序或产品。 我们将解释节点服务运行的原理以及它们的优缺点,并列出供应商,如果有兴趣,就着手开始吧。 +运行自己的[以太坊节点](/developers/docs/nodes-and-clients/#what-are-nodes-and-clients)可能具有挑战性,尤其是在入门或快速扩容时。 有许多[服务](#popular-node-services)可以为您运行优化的节点基础架构,以便您可以专注于开发应用程序或产品。 我们将解释节点服务运行的原理以及它们的优缺点,并列出供应商,如果有兴趣,就着手开始吧。 ## 前提条件 {#prerequisites} -如果你还不了解什么是节点和客户端,请查看[节点和客户端](/developers/docs/nodes-and-clients/)。 +如果您还不了解什么是节点和客户端,请查阅[节点和客户端](/developers/docs/nodes-and-clients/)。 -## 质押人 {#stakoooooooooooooors} +## 质押者 {#stakoooooooooooooors} -单独的质押人必须运行自己的基础设施,而不是依赖第三方提供商。 这意味着运行一个执行客户端和一个共识客户端。 在[合并](/roadmap/merge)之前,可以只运行共识客户端并通过中心化的提供商来获取执行数据;但现在已不存在这种情况——单独的质押人必须同时运行两种客户端。 但是,有一些服务可以简化这个过程。 +单独的质押人必须运行自己的基础设施,而不是依赖第三方提供商。 这意味着运行一个执行客户端和一个共识客户端。 在[合并](/roadmap/merge)之前,可以只运行一个共识客户端,并使用一个中心化的提供商来获取执行数据;现在已经不行了——个人质押者必须同时运行两种客户端。 但是,有一些服务可以简化这个过程。 -[阅读有关运行节点的更多信息](/developers/docs/nodes-and-clients/run-a-node/)。 +[阅读更多关于运行节点的内容](/developers/docs/nodes-and-clients/run-a-node/)。 本页描述的服务适用于非质押节点。 @@ -25,13 +25,13 @@ sidebarDepth: 2 节点服务提供商在幕后为你运行分布式节点客户端,因此你无需自己运行。 -这些服务通常提供一个可用来写入和读取区块链的应用程序接口密钥。 除了主网之外,通常还包括[以太坊测试网](/developers/docs/networks/#ethereum-testnets)访问权限。 +这些服务通常提供一个可用来写入和读取区块链的应用程序接口密钥。 除了主网,它们通常还包括对[以太坊测试网](/developers/docs/networks/#ethereum-testnets)的访问权限。 有些服务提供你自己的专用节点但由他们代为管理,而另外一些服务则使用负载均衡器在各节点之间分配活动。 几乎所有的节点服务都非常容易集成,只需要在你的代码中修改一行,就可以替换你自己的托管节点,甚至可以在服务本身之间切换。 -通常节点服务会运行各种[节点客户端](/developers/docs/nodes-and-clients/#execution-clients)和[节点](/developers/docs/nodes-and-clients/#node-types),使得用户可以通过一个应用程序接口访问全节点和归档节点以及客户端特定方法。 +节点服务通常会运行各种[节点客户端](/developers/docs/nodes-and-clients/#execution-clients)和[类型](/developers/docs/nodes-and-clients/#node-types),让您除了可以通过一个 API 访问客户端的特定方法外,还可以访问完整节点和存档节点。 值得注意的是,节点服务不存储也不应该存储你的私钥或信息。 @@ -45,15 +45,15 @@ sidebarDepth: 2 使用节点服务,你产品的基础设施部分走向了中心化。 因此,可能更喜欢对那些极为注重去中心化的项目采用自我托管节点,而不是外包给第三方。 -详细了解[运行自己节点的好处](/developers/docs/nodes-and-clients/#benefits-to-you)。 +阅读更多关于[运行您自己的节点的好处](/developers/docs/nodes-and-clients/#benefits-to-you)。 -## 主流节点服务 {#popular-node-services} +## 热门节点服务 {#popular-node-services} 下面列出了一些最受欢迎的以太坊节点服务提供商,如有遗漏,欢迎随时补充! 每种节点服务除了免费或付费层级外,还提供各种好处和功能。做出决定之前,你应该调查哪些服务最符合自己的需求。 - [**Alchemy**](https://alchemy.com/) - - [相关文档](https://docs.alchemyapi.io/) - - 特性 + - [文档](https://www.alchemy.com/docs/) + - 功能 - 最大的免费层级,每月有 3 亿个计算单元(约 3000 万个 getLatestBlock 请求) - 对 Polygon、Starknet、Optimism、Arbitrum 的多链支持 - 为大约 70% 的以太坊去中心化应用程序和去中心化金融最大交易量提供支持 @@ -64,8 +64,21 @@ sidebarDepth: 2 - 集成了测试网水龙头访问权限 - 拥有 1.8 万用户的活跃 Discord 构建者社区 +- [**Allnodes**](https://www.allnodes.com/) + - [文档](https://docs.allnodes.com/) + - 功能 + - 在 Allnodes 投资组合页面上创建的 PublicNode 代币无速率限制。 + - 在 [PublicNode](https://www.publicnode.com) 上提供注重隐私的免费 RPC 端点(100 多个区块链) + - 为 90+ 区块链提供无速率限制的专用节点 + - 为 30+ 区块链提供专用归档节点 + - 在 3 个地区可用(美国、欧盟、亚洲) + - 在 [PublicNode](https://www.publicnode.com/snapshots) 上提供 100 多个区块链的快照 + - 提供全天候技术支持,正常运行时间 SLA 为 99.90%-99.98%(取决于套餐)。 + - 按小时计费定价 + - 使用信用卡、PayPal 或加密货币支付 + - [**All That Node**](https://allthatnode.com/) - - [相关文档](https://docs.allthatnode.com/) + - [文档](https://docs.allthatnode.com/) - 功能 - 免费套餐每天 50,000 个请求 - 支持 40 多种协议 @@ -78,8 +91,8 @@ sidebarDepth: 2 - 自动更新 - [**Amazon Managed Blockchain**](https://aws.amazon.com/managed-blockchain/) - - [相关文档](https://aws.amazon.com/managed-blockchain/resources/) - - 特性 + - [文档](https://aws.amazon.com/managed-blockchain/resources/) + - 功能 - 完全托管的以太坊节点 - 可在六个地区使用 - 基于 HTTP 的 JSON-RPC 和安全 WebSockets @@ -88,8 +101,8 @@ sidebarDepth: 2 - Go-ethereum 和 Lighthouse - [**Ankr**](https://www.ankr.com/) - - [相关文档](https://docs.ankr.com/) - - 特性 + - [文档](https://docs.ankr.com/) + - 功能 - Ankr 协议 - 在超过 8 条链上开放式访问公共远程过程调用应用程序接口端点 - 通过负载均衡和节点健康监测,为最近可用节点提供快速可靠的网关 - 启用网络套接字安全端点和无速率上限的高级套餐 @@ -101,8 +114,8 @@ sidebarDepth: 2 - 直接支持 - [**Blast**](https://blastapi.io/) - - [相关文档](https://docs.blastapi.io/) - - 特性 + - [文档](https://docs.blastapi.io/) + - 功能 - 远程过程调用和网络套接字安全支持 - 多区域节点托管 - 去中心化基础设施 @@ -116,15 +129,15 @@ sidebarDepth: 2 - 加密货币支付 - [**BlockDaemon**](https://blockdaemon.com/) - - [相关文档](https://ubiquity.docs.blockdaemon.com/) + - [文档](https://ubiquity.docs.blockdaemon.com/) - 好处 - - 管理面板 + - 仪表板 - 基于每个节点 - 分析 - [**BlockPI**](https://blockpi.io/) - - [相关文档](https://docs.blockpi.io/) - - 特性 + - [文档](https://docs.blockpi.io/) + - 功能 - 稳健的分布式节点结构 - 多达 40 个安全套接字层超文本传输协议和网络套接字安全端点 - 免费注册套餐和月度套餐 @@ -135,44 +148,44 @@ sidebarDepth: 2 - 直接支持与技术支持 - [**Chainbase**](https://www.chainbase.com/) - - [相关文档](https://docs.chainbase.com) - - 特性 + - [文档](https://docs.chainbase.com) + - 功能 - 高可用性、高速和可扩展的远程过程调用服务 - 多链支持 - 不收费 - 用户友好的仪表板 - 提供远程过程调用之外的区块链数据服务 -- [**ChainStack**](https://chainstack.com/) - - [相关文档](https://docs.chainstack.com/) +- [**Chainstack**](https://chainstack.com/) + - [文档](https://docs.chainstack.com/) - 功能 - 免费共享节点 - 共享归档节点 - GraphQL 支持 - - 远程过程调用和网络套接字安全端点 + - RPC 、 HTTPS 和 WSS 端点 - 专用全节点和归档节点 - 专用部署的快速同步时间 - - 使用自己的云服务 + - 使用自己的云端服务 - 按小时计费定价 - 全天候直接支持 -- [**DRPC**](https://drpc.org/) - - [相关文档](https://docs.drpc.org/) - - 特性 - - 去中心化远程过程调用节点 - - 超过 15 个节点提供商 - - 节点平衡 - - 免费套餐每月计算单元无限制 - - 数据验证 - - 自定义端点 - - HTTP 和 WSS 端点 - - 无限密钥(免费和付费套餐) - - 灵活的回退选项 - - [公共端点](https://eth.drpc.org) - - 免费共享归档节点 +- [**dRPC**](https://drpc.org/) + - [文档](https://drpc.org/docs) + - NodeCloud:即插即用型 RPC 基础设施,10 美元起步——全速,无限制 + - NodeCloud 特性: + - 支持 185 个网络的 API + - 由 40 多个提供商组成的分布式池 + - 九 (9) 个地理集群实现全球覆盖 + - 人工智能驱动的负载均衡系统 + - 按需付费的统一定价——无涨价、无期限、无锁仓 + - 无限密钥、精细密钥调整、团队角色、前端保护 + - 每个方法固定费率为 20 个计算单元 (CU) + - [公共端点链列表](https://drpc.org/chainlist) + - [价格计算器](https://drpc.org/pricing#calculator) + - NodeCore:为希望完全控制的组织提供的开源堆栈 - [**GetBlock**](https://getblock.io/) - - [相关文档](https://getblock.io/docs/get-started/authentication-with-api-key/) + - [文档](https://getblock.io/docs/get-started/authentication-with-api-key/) - 功能 - 访问超过 40 个区块链节点 - 4 万个每日免费请求 @@ -196,7 +209,7 @@ sidebarDepth: 2 - 访问超过 50 个区块链节点 - [**Infura**](https://infura.io/) - - [相关文档](https://infura.io/docs) + - [文档](https://infura.io/docs) - 功能 - 免费套餐选项 - 随时扩容 @@ -205,18 +218,18 @@ sidebarDepth: 2 - 仪表板 - [**Kaleido**](https://kaleido.io/) - - [相关文档](https://docs.kaleido.io/) + - [文档](https://docs.kaleido.io/) - 功能 - - 免费初学者套餐 + - 免费初学者层级 - 一键部署以太坊节点 - 可自定义的客户端和算法(Geth、Quorum 和 Besu || PoA、IBFT 和 Raft) - 500 多个管理和服务应用程序接口 - 用于提交以太坊交易的 RESTful 接口(支持 Apache Kafka) - 用于事件传送的出站流(支持 Apache Kafka) - - “链下”和辅助服务的深度集合(例如双边加密消息传输) + - 大量的“链下”和辅助服务(例如,双边加密消息传输) - 简单明了的配置入网,提供治理和基于角色的访问控制 - 适用于管理员和最终用户的精细用户管理 - - 高度可扩展、复原力强的企业级基础设施 + - 高度可扩展、恢复力强的企业级基础设施 - Cloud HSM 私钥管理 - 以太坊主网网络共享 - ISO 27k 和 SOC 2 Type 2 认证 @@ -226,7 +239,7 @@ sidebarDepth: 2 - 服务等级协议和全天候支持 - [**Lava Network**](https://www.lavanet.xyz/) - - [相关文档](https://docs.lavanet.xyz/) + - [文档](https://docs.lavanet.xyz/) - 功能 - 免费使用测试网 - 适用于高正常运行时间的去中心化冗余 @@ -238,7 +251,7 @@ sidebarDepth: 2 - 多链支持 - [**Moralis**](https://moralis.io/) - - [相关文档](https://docs.moralis.io/) + - [文档](https://docs.moralis.io/) - 功能 - 免费共享节点 - 免费共享归档节点 @@ -248,10 +261,10 @@ sidebarDepth: 2 - 仪表板 - 独特的以太坊软件开发工具包 - 独有的应用程序接口端点 - - 直接技术支持 + - 点对点技术支持 - [**NodeReal MegaNode**](https://nodereal.io/) - - [相关文档](https://docs.nodereal.io/docs/introduction) + - [文档](https://docs.nodereal.io/docs/introduction) - 功能 - 可靠、快速而且可扩展的远程过程调用应用程序接口服务 - 面向 Web3 开发者的增强型应用程序接口 @@ -278,7 +291,7 @@ sidebarDepth: 2 - Pre-Stake+ 计划(如果你每天需要超过 100 万个请求) - 支持超过 15 条区块链 - 6400 多个节点为应用程序服务并赚取 POKT - - 归档节点、包含追踪数据的归档节点及测试网节点支持 + - 归档节点、带跟踪的归档节点和测试网节点支持 - 以太坊主网节点客户端多样性 - 无单点故障 - 零停机 @@ -286,22 +299,22 @@ sidebarDepth: 2 - 无每月沉没成本,将你的基础设施变成资产 - 协议中内置负载均衡 - 随时无限增加每日请求数量和每小时节点数量 - - 最私密的抗审查选项 + - 最隐密的抗审查选择 - 开发者实战支持 - [Pocket Portal](https://bit.ly/ETHorg_POKTportal) 仪表板和分析 - [**QuickNode**](https://www.quicknode.com) - [文档](https://www.quicknode.com/docs/) - 功能 - - 全天候技术支持和开发者 Discord 社区 + - 全天候技术支持和开发人员 Discord 社区 - 区域负载均衡、多云端/元模型、低延迟网络 - 多链支持(Optimism、Arbitrum、Polygon 及 11 个其他网络) - - 快速且稳定的中间层(调用路由、缓存、索引) + - 用于提高速度和稳定性的中间层(调用路由、缓存、索引) - 通过网络钩子进行智能合约监控 - 直观的仪表板、分析套件、远程过程调用编写器 - 高级安全功能(JWT、屏蔽、白名单) - 非同质化代币数据和分析应用程序接口 - - [已获 SOC2 认证](https://www.quicknode.com/security) + - [SOC2 认证](https://www.quicknode.com/security) - 适用于企业开发者 - [**Rivet**](https://rivet.cloud/) @@ -320,13 +333,13 @@ sidebarDepth: 2 - [**SettleMint**](https://console.settlemint.com/) - [文档](https://docs.settlemint.com/) - - 特性 + - 功能 - 免费试用 - 随时扩容 - GraphQL 支持 - - 远程过程调用和网络套接字安全端点 + - RPC 、 HTTPS 和 WSS 端点 - 专用全节点 - - 使用自己的云服务 + - 使用自己的云端服务 - 分析工具 - 仪表板 - 按小时计费定价 @@ -334,7 +347,7 @@ sidebarDepth: 2 - [**Tenderly**](https://tenderly.co/web3-gateway) - [文档](https://docs.tenderly.co/web3-gateway/web3-gateway) - - 特性 + - 功能 - 免费套餐包含每月 2500 万个 Tenderly 单位 - 免费访问历史数据 - 读取繁重型工作负载的速度最多提高 8 倍 @@ -349,8 +362,8 @@ sidebarDepth: 2 - [**Tokenview**](https://services.tokenview.io/) - [文档](https://services.tokenview.io/docs?type=nodeService) - - 特性 - - 全天候技术支持和开发者 Telegram 社区 + - 功能 + - 全天候技术支持和开发人员 Telegram 社区 - 多链支持(比特币、以太坊、Tron、BNB Smart Chain 和以太坊经典) - RPC 和 WSS 端点均开放使用 - 无限制访问归档数据应用程序接口 @@ -361,7 +374,7 @@ sidebarDepth: 2 - [**Watchdata**](https://watchdata.io/) - [文档](https://docs.watchdata.io/) - - 特性 + - 功能 - 数据可靠性 - 不间断连接,不会出现停机 - 过程自动化 @@ -373,7 +386,7 @@ sidebarDepth: 2 - [**ZMOK**](https://zmok.io/) - [文档](https://docs.zmok.io/) - - 特性 + - 功能 - 前台运行即服务 - 带有搜索/过滤方法的全局交易内存池 - 发送交易时,交易手续费和燃料均不受限制 @@ -382,21 +395,20 @@ sidebarDepth: 2 - [**Zeeve**](https://www.zeeve.io/) - [文档](https://www.zeeve.io/docs/) - - 特性 + - 功能 - 企业级无代码自动化平台,提供区块链节点和网络的部署、监控和管理 - - 超过 30 种支持的协议与集成,种类还在增加 + - 支持超过 30 种协议与集成,且仍在不断增加 - 增值型 Web3 基础设施服务,如去中心化存储、去中心化身份和用于真实世界用例的区块链账本数据应用程序接口 - 全天候支持和主动监控始终确保节点的健康 - 远程过程调用端点提供对应用程序接口的验证访问,并通过直观的仪表板和分析实现无忧管理。 - 提供托管云和自带云选项,支持所有主要云服务提供商,例如 AWS、Azure、Google Cloud、Digital Ocean 和本地服务 - 我们每次都会通过智能路由接入到距离你的用户最近的节点 - -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [以太坊节点服务列表](https://ethereumnodes.com/) -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [节点和客户端](/developers/docs/nodes-and-clients/) diff --git a/public/content/translations/zh/developers/docs/nodes-and-clients/run-a-node/index.md b/public/content/translations/zh/developers/docs/nodes-and-clients/run-a-node/index.md index 504b9538e1d..d35edf1d8aa 100644 --- a/public/content/translations/zh/developers/docs/nodes-and-clients/run-a-node/index.md +++ b/public/content/translations/zh/developers/docs/nodes-and-clients/run-a-node/index.md @@ -1,41 +1,42 @@ --- -title: 启动自己的以太坊节点 -description: 如何运行自己的以太坊客户端简介 +title: "启动自己的以太坊节点" +description: "如何运行自己的以太坊客户端简介" lang: zh sidebarDepth: 2 --- 运行你自己的节点为你提供各种好处,打开新的可能性,并为支持生态系统提供帮助。 这个页面将引导你启动自己的节点,并参与验证以太坊交易。 -注意,在[合并](/roadmap/merge)之后,运行以太坊节点需要两种客户端,即**执行层 (EL) **客户端和**共识层 (CL) **客户端。 本页面将展示如何安装、配置和连接这两种客户端以运行以太坊节点。 +请注意,在[合并](/roadmap/merge)之后,运行以太坊节点需要两个客户端:**执行层 (EL)** 客户端和**共识层 (CL)** 客户端。 本页面将展示如何安装、配置和连接这两种客户端以运行以太坊节点。 ## 前提条件 {#prerequisites} -你应该明白什么是以太坊节点,以及你可能想要运行客户端的原因。 [节点和客户端](/developers/docs/nodes-and-clients/)涵盖了这一主题。 +你应该明白什么是以太坊节点,以及你可能想要运行客户端的原因。 相关内容请参见[节点和客户端](/developers/docs/nodes-and-clients/)。 如果你不熟悉运行节点这一主题,或者正在寻找技术含量较低的方式,建议你先参阅我们为了便于用户理解而编撰的[运行以太坊节点](/run-a-node)简介。 -## 选择一种方式 {#choosing-approach} +## 选择一种方法 {#choosing-approach} 要启动自己的以太坊节点,第一步是选择你的运行方式。 根据要求和各种可能性,你必须选择客户端实现(执行客户端和共识客户端)、环境(硬件、系统)和客户端设置参数。 本页面将指导你做出这些决定,并帮助你找到运行以太坊实例的最合适方式。 -要选择客户端实现,请查看所有可用的主网就绪[执行客户端](/developers/docs/nodes-and-clients/#execution-clients)和[共识客户端](/developers/docs/nodes-and-clients/#consensus-clients),并了解[客户端多样性](/developers/docs/nodes-and-clients/client-diversity)。 +要从客户端实现中进行选择,请查看所有可用的主网就绪[执行客户端](/developers/docs/nodes-and-clients/#execution-clients)、[共识客户端](/developers/docs/nodes-and-clients/#consensus-clients)并了解[客户端多样性](/developers/docs/nodes-and-clients/client-diversity)。 -决定是在自己的[硬件还是云端](#local-vs-cloud)运行软件,同时考虑客户端的[要求](#requirements)。 +根据客户端的[要求](#requirements),决定是在自己的[硬件或云端](#local-vs-cloud)运行软件。 -准备好环境后,使用带有高级选项的终端,通过[初学者友好界面](#automatized-setup)或[手动](#manual-setup)安装所选客户端。 +准备好环境后,通过[适合初学者的界面](#automatized-setup)或使用带有高级选项的终端[手动](#manual-setup)安装所选的客户端。 -在节点运行和同步后,你便随时可以[使用该节点](#using-the-node),但请务必留意节点的[维护](#operating-the-node)。 +节点运行并同步后,你就可以[使用它](#using-the-node)了,但请务必留意其[维护](#operating-the-node)。 ![客户端设置](./diagram.png) -### 运行环境和硬件设施 {#environment-and-hardware} +### 环境和硬件 {#environment-and-hardware} -#### 本地或云端 {#local-vs-cloud} +#### 本地或云 {#local-vs-cloud} -以太坊客户端能够在消费级电脑上运行,并且不需要任何专用硬件,例如矿机。 因此,你可以根据需要选择多种节点部署方案。 简而言之,我们考虑在本地物理计算机和云端服务器上运行节点: +以太坊客户端能够在消费级电脑上运行,并且不需要任何专用硬件,例如矿机。 因此,你可以根据需要选择多种节点部署方案。 +简而言之,我们考虑在本地物理计算机和云端服务器上运行节点: - 云端 - 服务商提供了高可用的服务器以及静态公共 IP 地址 @@ -48,11 +49,11 @@ sidebarDepth: 2 - 可以购买预先配置好的机器 - 你必须亲自准备并维护机器和网络,并有可能亲自对机器和网络进行故障排除 -上面两种方案各有优点,总结如上。 如果你正在寻找云端解决方案,除了许多传统云计算服务商外,还有一些专注于部署以太坊节点的服务商, 查看[节点即服务](/developers/docs/nodes-and-clients/nodes-as-a-service/),了解有关托管节点的更多选项。 +上面两种方案各有优点,总结如上。 如果你正在寻找云端解决方案,除了许多传统云计算服务商外,还有一些专注于部署以太坊节点的服务商, 查看[节点即服务](/developers/docs/nodes-and-clients/nodes-as-a-service/),了解更多关于托管节点的信息。 #### 硬件 {#hardware} -不过,一个抗审查的去中心化网络不应该依赖于云服务提供商。 而且,在自己的本地硬件上运行节点对该生态系统来说更健康。 从[估算数据](https://www.ethernodes.org/network-types)来看,在云端运行大部分节点可能引发单点故障。 +不过,一个抗审查的去中心化网络不应该依赖于云服务提供商。 而且,在自己的本地硬件上运行节点对该生态系统来说更健康。 [估算数据](https://www.ethernodes.org/networkType/cl/Hosting)显示,大部分节点都在云端运行,这可能成为单点故障。 以太坊客户端可以在你的计算机、笔记本电脑、服务器甚至单板计算机上运行。 虽然可以在你的个人计算机上运行客户端,但为你的节点配备一台专用机器可以显著提高其性能和安全性,同时最大限度地减少对你的主计算机的影响。 @@ -66,9 +67,9 @@ sidebarDepth: 2 硬件的瓶颈通常是磁盘空间。 同步以太坊区块链是一种高强度的输入/输出密集型操作,并且需要大量空间。 最好使用在同步完成后还有数百 GB 可用空间的**固态硬盘 (SSD)**。 -数据库的大小和初始同步速度取决于所选客户端、其配置和[同步策略](/developers/docs/nodes-and-clients/#sync-modes)。 +数据库的大小和初始同步速度取决于所选的客户端、其配置和[同步策略](/developers/docs/nodes-and-clients/#sync-modes)。 -你还要确保网络连接没有[带宽限制](https://wikipedia.org/wiki/Data_cap)。 我们建议你使用不计流量的网络连接,因为初始同步和广播到网络的数据可能超过你的限额。 +另外,请确保你的互联网连接不受[带宽上限](https://wikipedia.org/wiki/Data_cap)的限制。 我们建议你使用不计流量的网络连接,因为初始同步和广播到网络的数据可能超过你的限额。 ##### 操作系统 @@ -90,17 +91,17 @@ sidebarDepth: 2 你选择的同步模式和客户端将影响磁盘空间要求,但我们估计了下面每种客户端需要的磁盘空间。 -| 客户端 | 磁盘大小(快照同步) | 磁盘大小(完整归档) | -| ---------- | ---------- | ---------- | -| Besu | 800GB 以上 | 12TB 以上 | -| Erigon | 未提供 | 2.5TB 以上 | -| Geth | 500GB+ | 12TB 以上 | -| Nethermind | 500GB+ | 12TB 以上 | -| Reth | 未提供 | 2.2TB 以上 | +| 客户端 | 磁盘大小(快照同步) | 磁盘大小(完整归档) | +| ---------- | ---------- | ------------------------ | +| Besu | 800GB 以上 | 12TB+ | +| Erigon | 未提供 | 2.5TB 以上 | +| Geth | 500GB+ | 12TB+ | +| Nethermind | 500GB+ | 12TB+ | +| Reth | 未提供 | 2.2TB 以上 | - 注意:Erigon 和 Reth 不支持快照同步,但能支持完全修剪(Erigon 约需 2TB,Reth 约需 1.2TB) -对于共识客户端,空间要求也取决于客户端实现和启用的功能(例如验证者、罚没者),但通常需要另外 200GB 磁盘空间存储信标数据。 由于验证者数量巨大,带宽负载也会增加。 你可以[在此分析中找到关于共识客户端要求的详细信息](https://mirror.xyz/0x934e6B4D7eee305F8C9C42b46D6EEA09CcFd5EDc/b69LBy8p5UhcGJqUAmT22dpvdkU-Pulg2inrhoS9Mbc)。 +对于共识客户端,空间要求也取决于客户端实现和启用的功能(例如验证者罚没者),但通常需要另外 200GB 磁盘空间存储信标数据。 由于验证者数量巨大,带宽负载也会增加。 你可以在[这篇分析文章中找到有关共识客户端要求的详细信息](https://mirror.xyz/0x934e6B4D7eee305F8C9C42b46D6EEA09CcFd5EDc/b69LBy8p5UhcGJqUAmT22dpvdkU-Pulg2inrhoS9Mbc)。 #### 即插即用解决方案 {#plug-and-play} @@ -109,9 +110,9 @@ sidebarDepth: 2 - [DappNode](https://dappnode.io/) - [Avado](https://ava.do/) -#### 在单板计算机上运行以太坊 {#ethereum-on-a-single-board-computer} +#### 单板计算机上的以太坊 {#ethereum-on-a-single-board-computer} -运行以太坊节点的一种经济简便的方法是使用单板计算机,甚至可以使用 ARM 架构的单板机,如树莓派。 [ARM 上的以太坊](https://ethereum-on-arm-documentation.readthedocs.io/en/latest/)为树莓派和其他 ARM 单板机提供便于运行的多种执行客户端和共识客户端映像。 +运行以太坊节点的一种经济简便的方法是使用单板计算机,甚至可以使用 ARM 架构的单板机,如树莓派。 [ARM 上的以太坊](https://ethereum-on-arm-documentation.readthedocs.io/en/latest/)为树莓派和其他 ARM 单板机提供便于运行的多种执行和共识客户端映像。 这类小型、实惠且高效的设备非常适合在家中运行节点,但请记住它们的性能有限。 @@ -127,13 +128,14 @@ sidebarDepth: 2 以下是一些可以帮助你安装和控制客户端的项目,只需单击几下即可: -- [DappNode](https://docs.dappnode.io/docs/user/getting-started/choose-your-path) - DappNode 不仅仅可以在供应商提供的机器上安装。 该软件、实际的节点启动器和具有许多功能的控制中心可以在任意硬件上使用。 -- [eth-docker](https://eth-docker.net/) - 使用 Docker 进行的自动化设置专注于简便和安全的质押,它需要用户具备基本的终端和 Docker 知识。我们推荐进阶用户可以选择此项目。 -- [Stereum](https://stereum.net/ethereum-node-setup/) - 通过 SSH 连接在远程服务器上安装客户端的启动器,配备 GUI 设置指南、控制中心和许多其他功能。 +- [DappNode](https://docs.dappnode.io/docs/user/getting-started/choose-your-path) - DappNode 不仅仅是来自供应商的机器。 该软件、实际的节点启动器和具有许多功能的控制中心可以在任意硬件上使用。 +- [EthPillar](https://www.coincashew.com/coins/overview-eth/ethpillar) - 设置全节点最快捷、最简单的方法。 一行命令设置工具及节点管理图形用户界面。 免费。 开源。 以太坊的公共商品由独立质押者提供。 支持 ARM64 和 AMD64。 +- [eth-docker](https://eth-docker.net/) - 使用 Docker 的自动化设置,专注于简单、安全的质押,需要基本的终端和 Docker 知识,推荐给更高级的用户。 +- [Stereum](https://stereum-dev.github.io/ethereum-node-web-docs) - 通过 SSH 连接在远程服务器上安装客户端的启动器,配备 GUI 设置指南、控制中心和许多其他功能。 - [NiceNode](https://www.nicenode.xyz/) - 提供简便用户体验的启动器,可在你的计算机上运行节点。 只需选择客户端并单击几下即可启动它们。 仍在开发中。 -- [Sedge](https://docs.sedge.nethermind.io/docs/intro) - 节点设置工具,使用 CLI 向导自动生成 Docker 配置。 由 Nethermind 使用 Go 编写。 +- [Sedge](https://docs.sedge.nethermind.io/docs/intro) - 节点设置工具,它使用 CLI 向导自动生成 Docker 配置。 由 Nethermind 使用 Go 编写。 -### 手动客户端设置 {#manual-setup} +### 手动设置客户端 {#manual-setup} 另一种选择是手动下载、验证和配置客户端软件。 即使一些客户端提供图形界面,手动设置仍然需要一些基本的终端使用技能,但它可以提供更多功能。 @@ -141,7 +143,7 @@ sidebarDepth: 2 #### 获取客户端软件 {#getting-the-client} -首先,你需要获取自己喜欢的[执行客户端](/developers/docs/nodes-and-clients/#execution-clients)和[共识客户端](/developers/docs/nodes-and-clients/#consensus-clients)软件。 +首先,你需要获取你偏好的[执行客户端](/developers/docs/nodes-and-clients/#execution-clients)和[共识客户端](/developers/docs/nodes-and-clients/#consensus-clients)软件。 你可以仅下载适合你的操作系统和架构的可执行应用或安装包。 始终验证下载安装包的签名和校验和。 一些客户端还提供存储库或 Docker 映像,以简化安装和更新。 所有客户端都是开源的,因此你也可以使用源代码构建它们。 这是一种更高阶的方法,但在某些情况下,你可能需要这么做。 @@ -157,25 +159,25 @@ sidebarDepth: 2 - [Nethermind](https://downloads.nethermind.io/) - [Reth](https://reth.rs/installation/installation.html) -另外值得注意的是,客户端多样性有关[执行层的问题](/developers/docs/nodes-and-clients/client-diversity/#execution-layer)之一。 我们建议读者考虑运行非主流执行客户端。 +还值得注意的是,客户端多样性是[执行层的一个问题](/developers/docs/nodes-and-clients/client-diversity/#execution-layer)。 我们建议读者考虑运行非主流执行客户端。 ##### 共识客户端 - [Lighthouse](https://github.com/sigp/lighthouse/releases/latest) -- [Lodestar](https://chainsafe.github.io/lodestar/run/getting-started/installation#build-from-source/)(不提供预构建的二进制文件,仅提供 Docker 映像或使用源代码进行构建) +- [Lodestar](https://chainsafe.github.io/lodestar/run/getting-started/installation#build-from-source/)(不提供预构建的二进制文件,仅提供 Docker 镜像或从源代码构建) - [Nimbus](https://github.com/status-im/nimbus-eth2/releases/latest) - [Prysm](https://github.com/prysmaticlabs/prysm/releases/latest) - [Teku](https://github.com/ConsenSys/teku/releases) -[客户端多样性](/developers/docs/nodes-and-clients/client-diversity/)对于运行验证者的共识节点来说至关重要。 如果大多数验证者都在运行单一客户端实现,网络安全就会面临风险。 因此,我们建议考虑选择非主流客户端。 +对于运行验证者的共识节点而言,[客户端多样性](/developers/docs/nodes-and-clients/client-diversity/)至关重要。 如果大多数验证者都在运行单一客户端实现,网络安全就会面临风险。 因此,我们建议考虑选择非主流客户端。 -[查看最新的网络客户端使用情况](https://clientdiversity.org/),并了解关于[客户端多样性](/developers/docs/nodes-and-clients/client-diversity)的更多信息。 +[查看最新的网络客户端使用情况](https://clientdiversity.org/)并了解有关[客户端多样性](/developers/docs/nodes-and-clients/client-diversity)的更多信息。 ##### 验证软件 从互联网下载软件时,建议验证其完整性。 此步骤是可选的,但特别是对于像以太坊客户端这样的关键基础设施,务必要了解潜在的攻击向量并避免它们。 如果下载了预构建的二进制文件,则需要信任它,并冒着攻击者将可执行文件替换为恶意文件的风险。 -开发者使用他们的 PGP 密钥签署已发布的二进制文件,这样你就可以通过加密方式验证你正在运行他们创建的软件。 你只需要获取开发者使用的公钥,公钥可以在客户端发布页面或文档中找到。 下载客户端版本及其签名后,你可以使用 PGP 实现(例如 [GnuPG](https://gnupg.org/download/index.html))轻松验证它们。 查看有关在 [Linux](https://www.tecmint.com/verify-pgp-signature-downloaded-software/) 或 [Windows/MacOS](https://freedom.press/training/verifying-open-source-software/) 上使用 `gpg` 验证开源软件的教程。 +开发者使用他们的 PGP 密钥签署已发布的二进制文件,这样你就可以通过加密方式验证你正在运行他们创建的软件。 你只需要获取开发者使用的公钥,公钥可以在客户端发布页面或文档中找到。 下载客户端版本及其签名后,你可以使用 PGP 实现(例如 [GnuPG](https://gnupg.org/download/index.html))轻松地进行验证。 查看关于在 [linux](https://www.tecmint.com/verify-pgp-signature-downloaded-software/) 或 [Windows/MacOS](https://freedom.press/training/verifying-open-source-software/) 上使用 `gpg` 验证开源软件的教程。 另一种验证方式是确保所下载软件的哈希(一种唯一的加密指纹)与开发者提供的哈希相符。 这种方式甚至比使用 PGP 更容易,并且一些客户端仅提供此选项。 只需在下载的软件上运行哈希函数并将其与发布页面中的哈希进行比较。 例如: @@ -189,11 +191,11 @@ sha256sum teku-22.6.1.tar.gz 安装、下载或编译客户端软件后,你就可以运行它了。 这仅意味着必须使用正确的配置执行客户端。 客户端提供丰富的配置选项,你可以通过它们启用各种功能。 -我们从可以显著影响客户端性能和数据使用的选项开始介绍。 [同步模式](/developers/docs/nodes-and-clients/#sync-modes)是指下载和验证区块链数据的不同方法。 在启动节点前,你应该决定使用哪种网络和同步模式。 最重要的考虑因素是客户端需要的磁盘空间和同步时间。 关注客户端文档以便确定默认的同步模式。 如果默认的同步模式不适合你,请根据安全级别、可用数据和成本选择另一种同步模式。 除了同步算法之外,你还可以设置修剪不同类型的旧数据。 修剪可以删除过时的数据,例如删除最近区块上无法访问的状态树节点。 +我们从可以显著影响客户端性能和数据使用的选项开始介绍。 [同步模式](/developers/docs/nodes-and-clients/#sync-modes)代表了下载和验证区块链数据的不同方法。 在启动节点前,你应该决定使用哪种网络和同步模式。 最重要的考虑因素是客户端需要的磁盘空间和同步时间。 关注客户端文档以便确定默认的同步模式。 如果默认的同步模式不适合你,请根据安全级别、可用数据和成本选择另一种同步模式。 除了同步算法之外,你还可以设置修剪不同类型的旧数据。 修剪可以删除过时的数据,例如删除最近区块上无法访问的状态树节点。 -其他基本配置选项包括:选择网络(主网或测试网)、为远程过程调用或 WebSocket 启用超文本传输协议端点等。 你可以在客户端相关文档中找到所有功能和选项。 你可以通过使用对应的标记在 CLI 或配置文件中直接执行客户端,以便设置不同的客户端配置。 每种客户端都有一点差异;有关配置选项的详细信息,请始终参阅其官方文档或帮助页面。 +其他基本配置选项包括选择网络(主网或测试网)、为 RPC 或 WebSocket 启用 HTTP 端点等。 你可以在客户端相关文档中找到所有功能和选项。 你可以通过使用对应的标记在 CLI 或配置文件中直接执行客户端,以便设置不同的客户端配置。 每种客户端都有一点差异;有关配置选项的详细信息,请始终参阅其官方文档或帮助页面。 -进行测试时,你可能更愿意在其中一个测试网上运行客户端。 [参阅受支持网络概览](/developers/docs/nodes-and-clients/#execution-clients)。 +进行测试时,你可能更愿意在其中一个测试网上运行客户端。 [查看支持的网络概览](/developers/docs/nodes-and-clients/#execution-clients)。 要了解如何运行具有基本配置的执行客户端,请见下一节中的示例。 @@ -211,9 +213,9 @@ sha256sum teku-22.6.1.tar.gz 你需要在一开始就声明所有非默认的客户端配置。 你可以使用标记或配置文件来声明你的首选配置。 每种客户端的功能集和配置语法都不同。 请查看你的客户端相关文档,了解具体细节。 -执行客户端和共识客户端通过[引擎应用程序接口](https://github.com/ethereum/execution-apis/tree/main/src/engine)中指定的经过身份验证的端点进行通信。 为了连接到共识客户端,执行客户端必须在已知路径上生成 [`jwtsecret`](https://jwt.io/)。 出于安全和稳定性的原因,客户端应该在同一台机器上运行,并且两种客户端都必须知道该路径,因为该路径用于验证它们之间的本地远程过程调用连接。 执行客户端还必须为经过身份验证的应用程序接口定义一个监听端口。 +执行客户端和共识客户端通过 [Engine API](https://github.com/ethereum/execution-apis/tree/main/src/engine) 中指定的经身份验证的端点进行通信。 为了连接到共识客户端,执行客户端必须在已知路径上生成一个 [`jwtsecret`](https://jwt.io/)。 出于安全和稳定性的原因,客户端应该在同一台机器上运行,并且两种客户端都必须知道该路径,因为该路径用于验证它们之间的本地远程过程调用连接。 执行客户端还必须为经过身份验证的应用程序接口定义一个监听端口。 -此令牌由客户端软件自动生成,但在某些情况下,你可能需要自己生成它。 你可以使用 [OpenSSL](https://www.openssl.org/) 生成该令牌: +此令牌由客户端软件自动生成,但在某些情况下,你可能需要自己生成它。 你可以使用 [OpenSSL](https://www.openssl.org/) 生成它: ```sh openssl rand -hex 32 > jwtsecret @@ -224,21 +226,21 @@ openssl rand -hex 32 > jwtsecret 本节将指导你启动执行客户端。 它仅提供基本配置示例,该示例将使用以下设置启动客户端: - 指定要连接的网络,在我们的示例中为主网 - - 你也可以选择[任一测试网络](/developers/docs/networks/),用于设置的初步测试 + - 你也可以选择[其中一个测试网](/developers/docs/networks/)来对你的设置进行初步测试 - 定义数据目录,包括区块链在内的所有数据都将存储在其中 - 确保用真实路径代替该路径,例如指向外置驱动器的路径 - 启用与客户端通信的接口 - 包括用于与共识客户端通信的 JSON-RPC 和引擎应用程序接口 -- 为经过身份验证的应用程序接口定义 `jwtsecret` 的路径 +- 为经过身份验证的 API 定义 `jwtsecret` 的路径 - 确保将示例路径替换为客户端可以访问的真实路径,例如 `/tmp/jwtsecret` 请记住,这只是一个基本示例,所有其他设置都将设置为默认值。 请关注每种客户端的相关文档以了解默认的值、设置和功能。 有关更多功能的信息,例如运行验证者、监测等,请参考具体客户端的相关文档。 -> 请注意,示例中的反斜杠 `\` 仅用于设置格式;配置标记可以在一行中定义。 +> 请注意,示例中的反斜杠 `` 仅用于格式化目的;配置标志可以在一行中定义。 ##### 运行 Besu -此示例在主网上启动 Besu,将区块链数据以默认格式存储在 `/data/ethereum` 下,启用 JSON-RPC 和引擎远程过程调用以连接共识客户端。 使用令牌 `jwtsecret` 对引擎应用程序接口进行身份验证,并且只允许来自 `localhost` 的调用。 +此示例在主网上启动 Besu,将区块链数据以默认格式存储在 `/data/ethereum`,并为连接共识客户端启用 JSON-RPC 和引擎 RPC。 引擎 API 使用 `jwtsecret` 令牌进行身份验证,并且只允许来自 `localhost` 的调用。 ```sh besu --network=mainnet \ @@ -256,11 +258,11 @@ Besu 还带有一个启动器选项,它会询问一系列问题并生成配置 besu --Xlauncher ``` -[Besu 相关文档](https://besu.hyperledger.org/public-networks/get-started/start-node/)包含更多选项和配置详细信息。 +[Besu 的文档](https://besu.hyperledger.org/public-networks/get-started/start-node/)包含其他选项和配置详情。 ##### 运行 Erigon -此示例在主网上启动 Erigon,将区块链数据存储在 `/data/ethereum` 下,启用 JSON-RPC,定义允许的命名空间,并启用身份验证以连接由 `jwtsecret` 路径定义的共识客户端。 +此示例在主网上启动 Erigon,将区块链数据存储在 `/data/ethereum`,启用 JSON-RPC,定义允许的命名空间,并为连接由 `jwtsecret` 路径定义的共识客户端启用身份验证。 ```sh erigon --chain mainnet \ @@ -269,11 +271,11 @@ erigon --chain mainnet \ --authrpc.jwtsecret=/path/to/jwtsecret ``` -默认情况下,Erigon 使用 8GB 机械硬盘执行完全同步,这将产生超过 2TB 的归档数据。 确保 `datadir` 指向有足够可用空间的磁盘,或者考虑使用可以修剪不同类型数据的 `--prune` 标记。 查看 Erigon 的 `--help` 了解更多信息。 +默认情况下,Erigon 使用 8GB 机械硬盘执行完全同步,这将产生超过 2TB 的归档数据。 确保 `datadir` 指向有足够可用空间的磁盘,或查看可修剪不同类型数据的 `--prune` 标志。 查看 Erigon 的 `--help` 以了解更多信息。 ##### 运行 Geth -此示例在主网上启动 Geth,将区块链数据存储在 `/data/ethereum` 下,启用 JSON-RPC 并定义允许的命名空间。 它还会启用身份验证(以便连接需要使用 `jwtsecret` 路径的共识客户端)以及定义允许哪些连接的选项,在我们的示例中仅允许来自 `localhost` 的连接。 +此示例在主网上启动 Geth,将区块链数据存储在 `/data/ethereum`,启用 JSON-RPC 并定义允许的命名空间。 它还为连接共识客户端启用身份验证,这需要 `jwtsecret` 的路径,以及一个定义允许哪些连接的选项,在我们的示例中只允许来自 `localhost` 的连接。 ```sh geth --mainnet \ @@ -284,7 +286,7 @@ geth --mainnet \ --authrpc.jwtsecret=/path/to/jwtsecret ``` -查看[相关文档中的所有配置选项](https://geth.ethereum.org/docs/fundamentals/command-line-options),并了解关于[运行 Geth 和共识客户端](https://geth.ethereum.org/docs/getting-started/consensus-clients)的更多信息。 +查看[所有配置选项的文档](https://geth.ethereum.org/docs/fundamentals/command-line-options),并了解有关[与共识客户端一起运行 Geth](https://geth.ethereum.org/docs/getting-started/consensus-clients) 的更多信息。 ##### 运行 Nethermind @@ -296,13 +298,13 @@ Nethermind.Runner --config mainnet \ --JsonRpc.JwtSecretFile=/path/to/jwtsecret ``` -Nethermind 相关文档提供了有关运行 Nethermind 和共识客户端的[完整指南](https://docs.nethermind.io/get-started/running-node/)。 +Nethermind 文档提供了一份关于如何与共识客户端一起运行 Nethermind 的[完整指南](https://docs.nethermind.io/get-started/running-node/)。 执行客户端将启动其核心功能及所选端点,并开始寻找对等节点。 成功发现对等节点后,该客户端开始同步。 执行客户端将等待来自共识客户端的连接。 当客户端成功同步到最新状态时,最新的区块链数据将可用。 ##### 运行 Reth -此示例使用默认数据位置在主网上启动 Reth。 启用 JSON-RPC 和引擎远程过程调用身份验证以连接由 `jwtsecret` 路径定义的共识客户端,并仅允许来自 `localhost` 的调用。 +此示例使用默认数据位置在主网上启动 Reth。 为连接由 `jwtsecret` 路径定义的共识客户端启用 JSON-RPC 和引擎 RPC 身份验证,只允许来自 `localhost` 的调用。 ```sh reth node \ @@ -311,23 +313,23 @@ reth node \ --authrpc.port 8551 ``` -查看[配置 Reth](https://reth.rs/run/config.html?highlight=data%20directory#configuring-reth) 以了解更多有关默认数据目录的信息。 [Reth 的相关文档](https://reth.rs/run/mainnet.html)包含更多选项和配置详情。 +请参阅[配置 Reth](https://reth.rs/run/config.html?highlight=data%20directory#configuring-reth) 来了解有关默认数据目录的更多信息。 [Reth 的相关文档](https://reth.rs/run/mainnet.html)包含更多选项和配置详情。 #### 启动共识客户端 {#starting-the-consensus-client} 共识客户端必须以正确的端口配置启动,才能与执行客户端建立本地远程过程调用连接。 它在运行时必须使用公开的执行客户端端口作为配置参数。 -共识客户端还需要执行客户端的 `jwt-secret` 的路径,以便对它们之间的远程过程调用连接进行身份验证。 与上面的执行示例类似,每种共识客户端都有一个配置标记,该标记使用 jwt 令牌文件的路径作为参数。 此路径必须与提供给执行客户端的 `jwt-secret` 路径一致。 +共识客户端还需要执行客户端的 `jwt-secret` 路径,以便对它们之间的 RPC 连接进行身份验证。 与上面的执行示例类似,每种共识客户端都有一个配置标记,该标记使用 jwt 令牌文件的路径作为参数。 此路径必须与提供给执行客户端的 `jwtsecret` 路径一致。 如果你打算运行验证者,确保添加一个配置标记以指定接收费用的以太坊地址。 这是为你的验证者积攒以太币奖励的地址。 每种共识客户端都有一个将以太坊地址作为参数的选项,例如 `--suggested-fee-recipient=0xabcd1`。 -在测试网上启动信标节点时,可以使用公共端点进行[检查点同步](https://notes.ethereum.org/@launchpad/checkpoint-sync),从而大大节省同步时间。 +在测试网上启动信标节点时,可以通过使用公共端点进行[检查点同步](https://notes.ethereum.org/@launchpad/checkpoint-sync)来显著节省同步时间。 #### 运行共识客户端 {#running-a-consensus-client} ##### 运行 Lighthouse -在运行 Lighthouse 之前,请在 [Lighthouse 手册](https://lighthouse-book.sigmaprime.io/installation.html)中详细了解如何安装和配置它。 +运行 Lighthouse 之前,请在 [Lighthouse Book](https://lighthouse-book.sigmaprime.io/installation.html) 中详细了解如何安装和配置它。 ```sh lighthouse beacon_node \ @@ -340,11 +342,11 @@ lighthouse beacon_node \ ##### 运行 Lodestar -通过编译或下载 Docker 映像来安装 Lodestar 软件。 在[相关文档](https://chainsafe.github.io/lodestar/)和更全面的[设置指南](https://hackmd.io/@philknows/rk5cDvKmK)中了解更多信息。 +通过编译或下载 Docker 映像来安装 Lodestar 软件。 在[文档](https://chainsafe.github.io/lodestar/)和更全面的[设置指南](https://hackmd.io/@philknows/rk5cDvKmK)中了解更多信息。 ```sh lodestar beacon \ - --rootDir="/data/ethereum" \ + --dataDir="/data/ethereum" \ --network=mainnet \ --eth1.enabled=true \ --execution.urls="http://127.0.0.1:8551" \ @@ -353,7 +355,8 @@ lodestar beacon \ ##### 运行 Nimbus -Nimbus 包括共识客户端和执行客户端。 它也可以在各种设备上运行,甚至可以在算力很一般的设备上运行。 [安装依赖项和 Nimbus](https://nimbus.guide/quick-start.html) 后,你可以运行它的共识客户端: +Nimbus 包括共识客户端和执行客户端。 它也可以在各种设备上运行,甚至可以在算力很一般的设备上运行。 +[安装完依赖项和 Nimbus 本身](https://nimbus.guide/quick-start.html)之后,你就可以运行其共识客户端: ```sh nimbus_beacon_node \ @@ -365,7 +368,7 @@ nimbus_beacon_node \ ##### 运行 Prysm -Prysm 带有脚本,可实现轻松自动安装。 详细信息可以在 [Prysm 相关文档](https://prysm.offchainlabs.com/docs/install-prysm/install-with-script/)中找到。 +Prysm 带有脚本,可实现轻松自动安装。 详情请参阅 [Prysm 文档](https://prysm.offchainlabs.com/docs/install-prysm/install-with-script/)。 ```sh ./prysm.sh beacon-chain \ @@ -384,47 +387,47 @@ teku --network mainnet \ --ee-jwt-secret-file "/path/to/jwtsecret" ``` -当共识客户端连接到执行客户端读取存款合约并识别验证者时,它也连接到其他对等信标节点并开始从创世块同步共识时隙。 信标节点达到当前时段后,信标应用程序接口将可供验证者使用。 了解关于[信标节点应用程序接口](https://eth2docs.vercel.app/)的更多信息。 +当共识客户端连接到执行客户端读取存款合约并识别验证者时,它也连接到其他对等信标节点并开始从创世块同步共识时隙。 信标节点达到当前时段后,信标应用程序接口将可供验证者使用。 了解更多关于[信标节点 API](https://eth2docs.vercel.app/) 的信息。 ### 添加验证者 {#adding-validators} 共识客户端充当验证者要连接的信标节点。 每种共识客户端都有自己的验证者软件,后者在各自的相关文档中都有详细描述。 -运行自己的验证者便可以进行[单独质押](/staking/solo/),这是支持以太坊网络的最有影响的去信任方法。 然而,单独质押需要存入 32 个以太币。 若想在自己的节点上运行验证者并质押较少数量的以太币,你可能会对由无需许可的节点运营商组成的去中心化池感兴趣,例如 [Rocket Pool](https://rocketpool.net/node-operators)。 +运行自己的验证者便可以进行[独立质押](/staking/solo/),这是支持以太坊网络最有效、最无需信任的方法。 然而,单独质押需要存入 32 个以太币。 若想在自己的节点上以较少的资金运行验证者,你可能会对去中心化的、有无需许可的节点运营商的池感兴趣,例如 [Rocket Pool](https://rocketpool.net/node-operators)。 -开始质押和生成验证者密钥的最简单方法是使用 [Holesky 测试网质押启动板](https://holesky.launchpad.ethereum.org/),它允许你通过[在 Holesky 上运行节点](https://notes.ethereum.org/@launchpad/holesky)来测试你的设置。 当准备好使用主网时,你可以使用[主网质押启动板](https://launchpad.ethereum.org/)重复这些步骤。 +开始质押和生成验证者密钥的最简单方法是使用 [Hoodi 测试网质押启动板](https://hoodi.launchpad.ethereum.org/),它允许你通过[在 Hoodi 上运行节点](https://notes.ethereum.org/@launchpad/hoodi)来测试你的设置。 当你准备好在主网上操作时,可以使用[主网质押启动板](https://launchpad.ethereum.org/)重复这些步骤。 -研读[质押页面](/staking)以了解质押选项概述。 +查看[质押页面](/staking),了解质押选项的概述。 ### 使用节点 {#using-the-node} -执行客户端提供[远程过程调用应用程序接口端点](/developers/docs/apis/json-rpc/);在以太坊网络上,你可以通过多种方式使用这些端点提交交易、与智能合约交互或部署智能合约: +执行客户端提供 [RPC API 端点](/developers/docs/apis/json-rpc/),你可以通过多种方式使用它们在以太坊网络上提交交易、与智能合约交互或部署智能合约: -- 使用合适的协议(例如,`curl`)手动调用端点 -- 附加提供的控制台(例如 `geth attach`) -- 使用 Web3 库在应用中实现端点,例如 [web3.py](https://web3py.readthedocs.io/en/stable/overview.html#overview) 和 [ethers](https://github.com/ethers-io/ethers.js/) +- 使用合适的协议(例如 `curl`)手动调用它们 +- 附加一个提供的控制台(例如 `geth attach`) +- 在应用程序中使用 web3 库(例如 [web3.py](https://web3py.readthedocs.io/en/stable/overview.html#overview)、[ethers](https://github.com/ethers-io/ethers.js/))实现它们 -不同的客户端有不同的远程过程调用端点实现。 不过,你可以选择一种标准 JSON-RPC 与每种客户端搭配使用。 想要了解概况,[请阅读 JSON-RPC 文档](/developers/docs/apis/json-rpc/)。 需要从以太坊网络中获取信息的应用,可以使用此远程过程调用。 例如,受欢迎的钱包 MetaMask 可让你[连接到自己的远程过程调用端点](https://metamask.zendesk.com/hc/en-us/articles/360015290012-Using-a-Local-Node),该端点具有卓越的隐私和安全优势。 +不同的客户端有不同的远程过程调用端点实现。 不过,你可以选择一种标准 JSON-RPC 与每种客户端搭配使用。 要了解概述,请[阅读 JSON-RPC 文档](/developers/docs/apis/json-rpc/)。 需要从以太坊网络中获取信息的应用,可以使用此远程过程调用。 例如,热门钱包 MetaMask 可让你[连接到自己的 RPC 端点](https://metamask.zendesk.com/hc/en-us/articles/360015290012-Using-a-Local-Node),这在隐私和安全方面有很大优势。 -共识客户端都公开一个[信标应用程序接口](https://ethereum.github.io/beacon-APIs),可用于检查共识客户端的状态,或者通过使用 [Curl](https://curl.se) 等工具发送请求来下载区块和共识数据。 更多相关信息可在每种共识客户端的相关文档中找到。 +所有共识客户端都公开一个[信标 API](https://ethereum.github.io/beacon-APIs),可用于检查共识客户端的状态,或使用 [Curl](https://curl.se) 等工具发送请求来下载区块和共识数据。 更多相关信息可在每种共识客户端的相关文档中找到。 -#### 访问远程过程调用 {#reaching-rpc} +#### 访问 RPC {#reaching-rpc} -执行客户端 JSON-RPC 的默认端口是 `8545`,但可以在配置中修改本地端点的端口。 默认情况下,远程过程调用接口只能在计算机的本地主机上访问。 为了让该端口可被远程访问,你可以通过将地址改为 `0.0.0.0` 公开它。 这样就可以通过本地网络或公共互联网协议地址访问该端口。 大多数情况下,你还需要在路由器上设置端口转发。 +执行客户端 JSON-RPC 的默认端口是 `8545`,但你可以在配置中修改本地端点的端口。 默认情况下,远程过程调用接口只能在计算机的本地主机上访问。 为了使其能够远程访问,你可能需要将其地址更改为 `0.0.0.0` 以将其公开。 这样就可以通过本地网络或公共互联网协议地址访问该端口。 大多数情况下,你还需要在路由器上设置端口转发。 在互联网上公开端口时应保持谨慎,因为这会让互联网上的任何人都可以控制你的节点。 恶意行为者可以通过访问你的节点让你的系统下线,或者如果你将客户端用作钱包,他们会窃取你的资金。 -解决该问题的办法是,禁止修改可能有危害的远程过程调用方法。 例如,对于 Geth,你可以使用标记 `—http.api web3,eth,txpool` 声明可修改的方法。 +解决该问题的办法是,禁止修改可能有危害的远程过程调用方法。 例如,对于 Geth,你可以使用一个标志来声明可修改的方法:`--http.api web3,eth,txpool`。 -开发边缘层应用程序接口或 Web 服务器应用(如 Nginx)并将它们连接到客户端的本地地址和端口,这样做可扩展对远程过程调用接口的访问。 利用中间层还让开发者能够设置远程过程调用接口的安全 `https` 连接证书。 +开发边缘层应用程序接口或 Web 服务器应用(如 Nginx)并将它们连接到客户端的本地地址和端口,这样做可扩展对远程过程调用接口的访问。 利用中间层还可以让开发者为到 RPC 接口的安全 `https` 连接设置证书。 -设置 Web 服务器、代理或面向外部的表现层状态转换应用程序接口,并不是访问节点的远程过程调用端点的唯一方法。 另一种设置可公开访问端点且保护隐私的方法是,将节点托管在自己的 [Tor](https://www.torproject.org/) 洋葱服务上。 这将让你在本地网络外部无需静态公共互联网协议地址或开放的端口也能访问此远程过程调用端口。 然而,使用此配置可能只允许通过 Tor 网络访问远程过程调用端点,但并非所有应用程序都支持 Tor 网络,从而可能导致发生连接问题。 +设置 Web 服务器、代理或面向外部的表现层状态转换应用程序接口,并不是访问节点的远程过程调用端点的唯一方法。 另一种保护隐私且可设置公开可访问端点的方法是,将节点托管在你自己的 [Tor](https://www.torproject.org/) 洋葱服务上。 这将让你在本地网络外部无需静态公共互联网协议地址或开放的端口也能访问此远程过程调用端口。 然而,使用此配置可能只允许通过 Tor 网络访问远程过程调用端点,但并非所有应用程序都支持 Tor 网络,从而可能导致发生连接问题。 -为此,你必须创建自己的[洋葱服务](https://community.torproject.org/onion-services/)。 查看有关洋葱服务设置的[相关文档](https://community.torproject.org/onion-services/setup/)以托管你自己的节点。 你可以将其指向具有远程过程调用端口代理的 Web 服务器,或者直接指向远程过程调用。 +为此,你必须创建自己的[洋葱服务](https://community.torproject.org/onion-services/)。 查看关于设置洋葱服务以托管你自己的服务的[文档](https://community.torproject.org/onion-services/setup/)。 你可以将其指向 Web 服务器并通过代理指向远程过程调用端口,或者直接指向远程过程调用端口。 -最后,访问内部网络最流行的方式之一是通过虚拟专用网连接。 根据你的用例和需要访问节点的用户数,也许可以选择安全的虚拟专用网连接。 [OpenVPN](https://openvpn.net/) 是一种功能完善的安全套接层虚拟专用网,它使用行业标准安全套接字层/传输层安全协议实现了开放式系统互联二层或三层安全网络扩展,支持基于证书、智能卡和/或用户名/密码凭据的灵活客户端身份验证方法,并允许用户或群组特定的访问控制策略(使用应用于虚拟专用网虚拟接口的防火墙规则)。 +最后,访问内部网络最流行的方式之一是通过虚拟专用网连接。 根据你的用例和需要访问节点的用户数,也许可以选择安全的虚拟专用网连接。 [OpenVPN](https://openvpn.net/) 是一种功能齐全的 SSL VPN,它使用行业标准的 SSL/TLS 协议实现 OSI 第 2 层或第 3 层的安全网络扩展。它支持基于证书、智能卡和/或用户名/密码凭证的灵活客户端身份验证方法,并允许通过应用于 VPN 虚拟接口的防火墙规则,实施针对特定用户或群组的访问控制策略。 -### 运行节点 {#operating-the-node} +### 操作节点 {#operating-the-node} 你应该定期监控你的节点,确保它正常运行。 你可能还需要偶尔对它进行维护。 @@ -436,44 +439,45 @@ teku --network mainnet \ - 强制关闭会破坏数据库,这可能需要你重新同步整个节点。 - 客户端将无法与网络同步,重启后,客户端需要重新同步。 虽然节点可以从它最近一次关闭的位置开始同步,但此过程需要的时间取决于它离线的时间。 -_但是,共识层的验证者节点就需要一直在线。_验证者节点离线将影响所有依赖它的服务。 如果你是为了_质押_而运行节点,应该尽可能地减少停机时间。 +_此规则不适用于共识层验证者节点。_ 将你的节点下线会影响所有依赖它的服务。 如果你是为了_质押_而运行节点,应该尽可能地减少停机时间。 #### 创建客户端服务 {#creating-client-services} -考虑创建一个在启动时自动运行客户端的服务。 例如,在 Linux 服务器上,最佳做法是创建一种服务,例如使用 `systemd`,为有限权限的用户执行配置正确的客户端并自动重启。 +考虑创建一个在启动时自动运行客户端的服务。 例如,在 Linux 服务器上,一个好的做法是创建一个服务(例如,使用 `systemd`),该服务在权限受限的用户下使用正确的配置执行客户端,并能自动重启。 #### 更新客户端 {#updating-clients} -你应该通过安装最新的安全补丁、功能和[以太坊改进提案](/eips/),让客户端软件更新到最新版本。 特别是在[硬分叉](/ethereum-forks/)之前,确保运行正确的客户端版本。 +你需要用最新的安全补丁、功能和 [EIP](/eips/) 来保持客户端软件是最新版本。 尤其是在[硬分叉](/ethereum-forks/)之前,请确保你运行的是正确的客户端版本。 -> 在重要的网络更新之前,以太坊基金会在其[博客](https://blog.ethereum.org)上发布相关文章。 你可以[订阅这些公告](https://blog.ethereum.org/category/protocol#subscribe),以便在你的节点需要更新时收到邮件通知。 +> 在重要的网络更新之前,以太坊基金会 (EF) 会在其[博客](https://blog.ethereum.org)上发布一篇文章。 你可以[订阅这些公告](https://blog.ethereum.org/category/protocol#subscribe),以便在你的节点需要更新时收到邮件通知。 更新客户端非常简单。 每种客户端在其相关文档中都有具体说明,但通常更新过程仅包括下载最新版本并使用正确的可执行文件重启而已。 客户端应该会从上一次中断的位置继续,但请应用所有更新。 -每种客户端实现都有一个人类可读的版本字符串,该字符串在点对点协议中使用但也可以从命令行访问。 该版本字符串让用户可以检查他们运行的客户端版本是否正确,并支持区块浏览器和用来量化网络上特定客户端分布的其他分析工具。 有关版本字符串的更多信息,请参阅各客户端相关文档。 +每种客户端实现都有一个人类可读的版本字符串,该字符串在点对点协议中使用但也可以从命令行访问。 该版本字符串让用户可以检查他们运行的客户端版本是否正确,并支持区块浏览器和用来量化网络上特定客户端分布的其他分析工具。 更多关于版本字符串的信息,请参阅各客户端相关文档。 -#### 运行额外服务 {#running-additional-services} +#### 运行附加服务 {#running-additional-services} -运行自己的节点,可以让你使用需要直接访问以太坊客户端远程过程调用的服务。 这些服务构建在以太坊上,如[二层网络解决方案](/developers/docs/scaling/#layer-2-scaling)、钱包后端、区块浏览器、开发者工具和其他以太坊基础设施。 +运行自己的节点,可以让你使用需要直接访问以太坊客户端远程过程调用的服务。 这些是构建在以太坊之上的服务,例如[二层网络解决方案](/developers/docs/scaling/#layer-2-scaling)、钱包后端、区块浏览器、开发者工具和其他以太坊基础设施。 -#### 监测节点 {#monitoring-the-node} +#### 监控节点 {#monitoring-the-node} -为了正确监测节点,请考虑收集指标。 客户端提供了指标端点,因此你可以获得有关节点的全面数据。 使用 [InfluxDB](https://www.influxdata.com/get-influxdb/) 或 [Prometheus](https://prometheus.io/) 等工具创建数据库,并且可以在 [Grafana](https://grafana.com/) 等软件中将其可视化并转换成图表。 在可视化节点和整个网络时,Grafana 有许多设置和各种仪表版可供使用。 例如,查看[有关监测 Geth 的教程](/developers/tutorials/monitoring-geth-with-influxdb-and-grafana/)。 +为了正确监测节点,请考虑收集指标。 客户端提供了指标端点,因此你可以获得有关节点的全面数据。 使用 [InfluxDB](https://www.influxdata.com/get-influxdb/) 或 [Prometheus](https://prometheus.io/) 等工具创建数据库,然后在 [Grafana](https://grafana.com/) 等软件中将它们转化为可视化和图表。 在可视化节点和整个网络时,Grafana 有许多设置和各种仪表版可供使用。 例如,查看[关于使用 InfluxDB 和 Grafana 监控 Geth 的教程](/developers/tutorials/monitoring-geth-with-influxdb-and-grafana/)。 -在监测过程中,请务必密切关注机器的性能。 在节点初始同步期间,客户端软件可能会占用大量 CPU 和内存资源。 除了 Grafana,你也可以使用操作系统自带的 `htop` 或 `uptime` 等工具来监测节点。 +在监测过程中,请务必密切关注机器的性能。 在节点初始同步期间,客户端软件可能会占用大量 CPU 和内存资源。 除了 Grafana,你还可以使用操作系统提供的 `htop` 或 `uptime` 等工具来完成此操作。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [以太坊质押指南](https://github.com/SomerEsat/ethereum-staking-guides) _ – Somer Esat,定期更新_ -- [指南 | 如何在主网上为以太坊质押设置验证者](https://www.coincashew.com/coins/overview-eth/guide-or-how-to-setup-a-validator-on-eth2-mainnet) _– CoinCashew,定期更新_ -- [有关在测试网上运行验证者的 ETHStaker 指南](https://github.com/remyroy/ethstaker#guides) – _ETHStaker,定期更新_ -- [面向节点运营商的合并常见问题解答](https://notes.ethereum.org/@launchpad/node-faq-merge) - _2022 年 7 月_ -- [分析成为已验证以太坊全节点的硬件要求](https://medium.com/coinmonks/analyzing-the-hardware-requirements-to-be-an-ethereum-full-validated-node-dc064f167902)_ - Albert Palau,2018 年 9 月 24 日_ -- [运行以太坊全节点:勉励者指南](https://medium.com/@JustinMLeroux/running-ethereum-full-nodes-a-guide-for-the-barely-motivated-a8a13e7a0d31) _– Justin Leroux,2019 年 11 月 7 日_ -- [在以太坊主网上运行 Hyperledger Besu 节点:优点、要求和设置](https://pegasys.tech/running-a-hyperledger-besu-node-on-the-ethereum-mainnet-benefits-requirements-and-setup/) _– Felipe Faraggi,2020 年 5 月 7 日_ -- [部署具有监测堆栈的 Nethermind 以太坊客户端](https://medium.com/nethermind-eth/deploying-nethermind-ethereum-client-with-monitoring-stack-55ce1622edbd) _– Nethermind.eth,2020 年 7 月 8 日_ +- [以太坊质押指南](https://github.com/SomerEsat/ethereum-staking-guides) - _Somer Esat,经常更新_ +- [指南 | 如何在主网上为以太坊质押设置验证者](https://www.coincashew.com/coins/overview-eth/guide-or-how-to-setup-a-validator-on-eth2-mainnet) _– CoinCashew,经常更新_ +- [关于在测试网上运行验证者的 ETHStaker 指南](https://github.com/remyroy/ethstaker#guides) – _ETHStaker,定期更新_ +- [用于以太坊节点的 AWS 区块链节点运行器示例应用](https://aws-samples.github.io/aws-blockchain-node-runners/docs/Blueprints/Ethereum) - _AWS,经常更新_ +- [针对节点运营商的合并常见问题解答](https://notes.ethereum.org/@launchpad/node-faq-merge) - _2022 年 7 月_ +- [分析成为以太坊全验证节点的硬件要求](https://medium.com/coinmonks/analyzing-the-hardware-requirements-to-be-an-ethereum-full-validated-node-dc064f167902) _– Albert Palau,2018 年 9 月 24 日_ +- [运行以太坊全节点:一份写给勉强有动力的人的指南](https://medium.com/@JustinMLeroux/running-ethereum-full-nodes-a-guide-for-the-barely-motivated-a8a13e7a0d31) _– Justin Leroux, 2019 年 11 月 7 日_ +- [在以太坊主网上运行 Hyperledger Besu 节点:好处、要求和设置](https://pegasys.tech/running-a-hyperledger-besu-node-on-the-ethereum-mainnet-benefits-requirements-and-setup/) _– Felipe Faraggi,2020 年 5 月 7 日_ +- [使用监控堆栈部署 Nethermind 以太坊客户端](https://medium.com/nethermind-eth/deploying-nethermind-ethereum-client-with-monitoring-stack-55ce1622edbd) _– Nethermind.eth,2020 年 7 月 8 日_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [节点和客户端](/developers/docs/nodes-and-clients/) - [区块](/developers/docs/blocks/) diff --git a/public/content/translations/zh/developers/docs/oracles/index.md b/public/content/translations/zh/developers/docs/oracles/index.md index 4612e3e44bf..756f74e98fa 100644 --- a/public/content/translations/zh/developers/docs/oracles/index.md +++ b/public/content/translations/zh/developers/docs/oracles/index.md @@ -1,20 +1,20 @@ --- -title: 预言机 -description: 以太坊智能合约通过预言机访问真实数据,为用户解锁更多用例并提供更大价值。 +title: "预言机" +description: "以太坊智能合约通过预言机访问真实数据,为用户解锁更多用例并提供更大价值。" lang: zh --- -预言机是产生数据馈送的应用程序,使链下数据来源可供区块链用于智能合约。 由于默认情况下,基于以太坊的智能合约无法访问存储在区块链网络外部的信息,预言机是必不可少的。 +预言机是产生并发送数据的应用程序。它使链下数据可供智能合约区块链使用。 由于默认情况下,基于以太坊的智能合约无法访问存储在区块链网络外部的信息,预言机是必不可少的。 -赋予智能合约使用链下数据执行的能力,扩展了去中心化应用程序的效用和价值。 例如,链上预测市场依靠预言机提供有关结果的信息,用于验证用户的预测。 假设 Alice 下注 20 个以太币赌谁将成为下一任美国 总统。 在这种情况下,预测市场去中心化应用程序需要预言机来确认选举结果,并判定 Alice 是否有资格获得付款。 +赋予智能合约使用链下数据的能力扩展了去中心化应用程序的效用和价值。 例如,链上预测市场依靠预言机提供有关结果的信息。这些结果用于验证针对用户的预测。 假设 Alice 下注 20 个以太币赌谁将成为下一任美国 总统。 在这种情况下,预测市场去中心化应用程序需要预言机来确认选举结果,并判定 Alice 是否有资格获得付款。 ## 前提条件 {#prerequisites} -本页面假设读者熟悉以太坊基础知识,例如[节点](/developers/docs/nodes-and-clients/)、[共识机制](/developers/docs/consensus-mechanisms/)和[以太坊虚拟机](/developers/docs/evm/)等。 读者还应该深刻了解[智能合约](/developers/docs/smart-contracts/)和[智能合约分析](/developers/docs/smart-contracts/anatomy/),尤其要了解[事件](/glossary/#events)。 +本页内容假定读者熟悉以太坊基础知识,包括[节点](/developers/docs/nodes-and-clients/)、[共识机制](/developers/docs/consensus-mechanisms/)和 [EVM](/developers/docs/evm/)。 你还应该对[智能合约](/developers/docs/smart-contracts/)和[智能合约剖析](/developers/docs/smart-contracts/anatomy/)有很好的了解,特别是[事件](/glossary/#events)。 ## 什么是区块链预言机? {#what-is-a-blockchain-oracle} -预言机是指获取、验证外部信息(即存储在链下的信息)并将外部信息传送给在区块链上运行的智能合约的应用程序。 预言机除了“拉取”链下数据并在以太坊上广播以外,还可以将信息从区块链“推送”到外部系统,例如,一旦用户通过以太坊交易发送费用,就解锁智能锁。 +预言机是获取、验证外部信息(即存储在链下的信息)并将其传输到在区块链上运行的智能合约的应用程序。 预言机除了“抓取”链下数据并在以太坊上广而告之以外,还可以将信息从区块链“推送”到外部系统,例如,一旦用户通过以太坊交易并缴费,就能解锁智能锁。 如果没有预言机,智能合约将只能使用链上数据。 @@ -22,11 +22,11 @@ lang: zh ## 智能合约为什么需要预言机? {#why-do-smart-contracts-need-oracles} -许多开发者将智能合约视为在区块链上特定地址运行的代码。 然而,对[智能合约更为普遍的观点](/smart-contracts/)是,它们是自动执行的软件程序,一旦满足特定条件,就能够执行各方之间的协议 - 因此术语称为“智能合约”。 +许多开发者将智能合约视为在区块链上特定地址运行的代码。 然而,对[智能合约](/smart-contracts/)更为普遍的观点是,它们是自动执行的软件程序,一旦满足特定条件,就能够执行各方之间的协议——因此术语称为“智能合约”。 但是,使用智能合约执行人之间的协议并非易事,因为以太坊是确定性系统。 [确定性系统](https://en.wikipedia.org/wiki/Deterministic_algorithm)是指在给定初始状态和特定输入的情况下始终产生相同结果的系统,这意味着根据输入计算输出的过程不存在随机性或变化。 -要实现确定性执行,区块链将节点限制为通过_仅_使用存储在区块链本身中的数据就简单的二进制 (true/false) 问题达成共识。 这类问题的示例包括: +为了实现确定性执行,区块链将节点限制为通过_仅_使用存储在区块链本身中的数据就简单的二进制 (true/false) 问题达成共识。 这类问题的示例包括: - “帐户所有者(由公钥识别)是否使用配对私钥签署该交易?” - “该帐户是否有足够资金支付这笔交易?” @@ -40,11 +40,11 @@ lang: zh 为此,预言机通常由链上运行的智能合约和一些链下组件构成。 链上合约接收其他智能合约的数据请求,并将这些请求传送给链下组件(称为预言机节点)。 这类预言机节点可以查询数据源—例如使用应用程序接口 (API)—并发送交易将请求的数据存储在智能合约的存储中。 -就本质而言,区块链预言机弥合了区块链和外部环境之间的信息缺口,创建了“混合智能合约”。 混合智能合约的工作原理基于链上合约代码和链下基础设施的结合。 去中心化预测市场就是混合智能合约的一个很好的示例。 其他示例可能包括作物保险智能合约,在一组预言机确定某些天气现象已经发生时这些合约做出赔付。 +就本质而言,区块链预言机弥合了区块链和外部环境之间的信息缺口,创建了“混合智能合约”。 混合智能合约的工作原理是链上合约代码和链下基础设施的结合。 去中心化预测市场就是混合智能合约的一个很好的示例。 其他示例可能包括作物保险智能合约,在一组预言机确定某些天气现象已经发生时这些合约做出赔付。 ## 什么是预言机问题? {#the-oracle-problem} -预言机解决了一个重要问题,但也带来了一些复杂性,例如: +预言机解决了一个重要问题,但也带来了一些复杂问题,例如: - 如何验证注入信息是从正确来源提取的或者未被篡改? @@ -54,11 +54,11 @@ lang: zh 不同的预言机对于预言机问题有着不同的解决方案,稍后将进行探讨。 通常会根据预言机应对以下挑战的能力来评估它们: -1. **正确性**:预言机不应导致智能合约基于无效的链下数据触发状态变化。 预言机必须保证数据的_真实性_与_完整性_。 真实性是指数据是从正确来源获取的,完整性是指数据在发送到链上前保持完好无缺(即数据未修改过)。 +1. **正确性**:预言机不应导致智能合约基于无效的链下数据触发状态更改。 预言机必须保证数据的_真实性_和_完整性_。 真实性意味着数据来自正确的来源,而完整性意味着数据在发送到链上之前保持完好无损(即未被更改)。 -2. **可用性**:预言机不应延迟或阻止智能合约执行操作或触发状态变化。 这意味着预言机提供的数据必须_在请求时可用_并且不会出现间断。 +2. **可用性**:预言机不应延迟或阻止智能合约执行操作和触发状态更改。 这意味着预言机提供的数据必须_按需可用_且不中断。 -3. **激励兼容性**:预言机应激励链下数据提供者向智能合约提交正确的信息。 奖励兼容性包括_可归因性_和_问责性_。 可归因性指将一条外部信息与其提供者联系起来,而问责性则将数据提供者和他们提供的信息联结起来,因此能够根据提供的数据质量奖励或者惩罚数据提供者。 +3. **激励兼容性**:预言机应激励链下数据提供者向智能合约提交正确的信息。 激励兼容性包括_可归因性_和_问责性_。 可归因性指将一条外部信息与其提供者联系起来,而问责性则将数据提供者和他们提供的信息联结起来,因此能够根据提供的数据质量奖励或者惩罚数据提供者。 ## 区块链预言机服务是如何运作的? {#how-does-a-blockchain-oracle-service-work} @@ -66,7 +66,7 @@ lang: zh 用户是指需要区块链外部的信息以完成特定操作的实体(即智能合约)。 预言机服务的基本工作流程始于用户向预言机合约发送数据请求。 数据请求通常将回答下列一部分或所有问题: -1. 链下节点可以在哪些来源中查询请求的信息? +1. 链下节点可以从哪里查询到想要了解的信息? 2. 报告者如何处理数据来源中的信息并提取有用的数据点? @@ -80,37 +80,37 @@ lang: zh 预言机合约是预言机服务的链上部分。 它侦听其他合约的数据请求,将数据查询转送到预言机节点,并将返回的数据广播到客户端合约。 该合约还可以对返回的数据点进行一些计算,以产生聚合值并发送给请求合约。 -预言机合约公开了一些函数,客户端合约在发出数据请求时调用它们。 收到新查询后,智能合约将触发一个[日志事件](/developers/docs/smart-contracts/anatomy/#events-and-logs),其中有数据请求详细信息。 这将通知订阅该日志的链下节点(通常使用类似 JSON-RPC `eth_comment` 的命令),让其继续检索日志事件中定义的数据。 +预言机合约公开了一些函数,客户端合约在发出数据请求时调用它们。 收到新查询后,智能合约将发出一个包含数据请求详情的[日志事件](/developers/docs/smart-contracts/anatomy/#events-and-logs)。 这将通知订阅该日志的链下节点(通常使用 JSON-RPC `eth_subscribe` 之类的命令),这些节点会继续检索日志事件中定义的数据。 -下面是 Pedro Costa 提供的[预言机合约示例](https://medium.com/@pedrodc/implementing-a-blockchain-oracle-on-ethereum-cedc7e26b49e)。 它是一个简单的预言机服务,可以在其他智能合约发出请求时查询链下应用程序接口,并在区块链上存储请求的信息: +以下是 Pedro Costa 编写的一个[预言机合约示例](https://medium.com/@pedrodc/implementing-a-blockchain-oracle-on-ethereum-cedc7e26b49e)。 它是一个简单的预言机服务,可以在其他智能合约发出请求时查询链下应用程序接口,并在区块链上存储要求的信息: ```solidity pragma solidity >=0.4.21 <0.6.0; contract Oracle { - Request[] requests; //list of requests made to the contract - uint currentId = 0; //increasing request id - uint minQuorum = 2; //minimum number of responses to receive before declaring final result - uint totalOracleCount = 3; // Hardcoded oracle count + Request[] requests; //向合约发出的请求列表 + uint currentId = 0; //递增的请求 id + uint minQuorum = 2; //宣布最终结果前收到的最少响应数 + uint totalOracleCount = 3; //硬编码的预言机数量 - // defines a general api request + // 定义一个通用的 API 请求 struct Request { - uint id; //request id + uint id; //请求 id string urlToQuery; //API url - string attributeToFetch; //json attribute (key) to retrieve in the response - string agreedValue; //value from key - mapping(uint => string) answers; //answers provided by the oracles - mapping(address => uint) quorum; //oracles which will query the answer (1=oracle hasn't voted, 2=oracle has voted) + string attributeToFetch; //要在响应中检索的 json 属性 (键) + string agreedValue; //来自键的值 + mapping(uint => string) answers; //预言机提供的答案 + mapping(address => uint) quorum; //将查询答案的预言机(1=预言机未投票,2=预言机已投票) } - //event that triggers oracle outside of the blockchain + //在区块链外部触发预言机的事件 event NewRequest ( uint id, string urlToQuery, string attributeToFetch ); - //triggered when there's a consensus on the final result + //就最终结果达成共识时触发 event UpdatedRequest ( uint id, string urlToQuery, @@ -127,23 +127,23 @@ contract Oracle { uint length = requests.push(Request(currentId, _urlToQuery, _attributeToFetch, "")); Request storage r = requests[length-1]; - // Hardcoded oracles address + // 硬编码的预言机地址 r.quorum[address(0x6c2339b46F41a06f09CA0051ddAD54D1e582bA77)] = 1; r.quorum[address(0xb5346CF224c02186606e5f89EACC21eC25398077)] = 1; r.quorum[address(0xa2997F1CA363D11a0a35bB1Ac0Ff7849bc13e914)] = 1; - // launch an event to be detected by oracle outside of blockchain + // 启动一个事件,供区块链外部的预言机检测 emit NewRequest ( currentId, _urlToQuery, _attributeToFetch ); - // increase request id + // 增加请求 id currentId++; } - //called by the oracle to record its answer + //由预言机调用以记录其答案 function updateRequest ( uint _id, string memory _valueRetrieved @@ -151,18 +151,18 @@ contract Oracle { Request storage currRequest = requests[_id]; - //check if oracle is in the list of trusted oracles - //and if the oracle hasn't voted yet + //检查预言机是否在可信预言机列表中 + //以及预言机是否尚未投票 if(currRequest.quorum[address(msg.sender)] == 1){ - //marking that this address has voted + //标记此地址已投票 currRequest.quorum[msg.sender] = 2; - //iterate through "array" of answers until a position if free and save the retrieved value + //迭代答案“数组”,直到找到一个空闲位置并保存检索到的值 uint tmpI = 0; bool found = false; while(!found) { - //find first empty slot + //查找第一个空时隙 if(bytes(currRequest.answers[tmpI]).length == 0){ found = true; currRequest.answers[tmpI] = _valueRetrieved; @@ -172,8 +172,8 @@ contract Oracle { uint currentQuorum = 0; - //iterate through oracle list and check if enough oracles(minimum quorum) - //have voted the same answer as the current one + //迭代预言机列表,检查是否有足够的预言机(最低法定人数) + //投票给了与当前答案相同的答案 for(uint i = 0; i < totalOracleCount; i++){ bytes memory a = bytes(currRequest.answers[i]); bytes memory b = bytes(_valueRetrieved); @@ -200,19 +200,19 @@ contract Oracle { 预言机节点是预言机服务的链下部分。 它从外部来源提取信息,例如托管在第三方服务器上的应用程序接口,并将信息放在链上供智能合约使用。 预言机节点侦听来自链上预言机合约的事件,继而完成日志中描述的任务。 -预言机节点的常见任务是,向应用程序接口服务发送 [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) 请求,解析响应以提取相关数据,设置为区块链可读的输出格式,并通过将输入包含在预言机合约的交易中将其发送到链上 在利用“真实性证明”证明所提交信息的有效性和完整性时,可能也会用到预言机节点,我们稍后会对此进行探讨。 +预言机节点的常见任务是,向 API 服务发送 [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) 请求,解析响应以提取相关数据,将其格式化为区块链可读的输出,并通过将其包含在发送给预言机合约的交易中来发送到链上。 在利用“真实性证明”证明所提交信息的有效性和完整性时,可能也会用到预言机节点,我们稍后会对此进行探讨。 -计算预言机也依赖链下节点执行计算任务,但因为燃料成本和区块大小限制,这类计算在链上执行是不切实际的。 例如,预言机节点的任务可能是生成一个可验证的随机数字(例如,用于区块链游戏)。 +计算预言机也依赖链下节点执行计算任务,因为燃料成本和区块大小限制,这类计算想在链上执行是不切实际的。 例如,预言机节点的任务可能是生成一个可验证的随机数字(例如,用于区块链游戏)。 ## 预言机设计模式 {#oracle-design-patterns} -预言机有不同的类型,包括_立即读取_、_发布-订阅_和_请求-响应_,后两者在太坊智能合约中最受欢迎。 在此我们简单描述发布-订阅和请求-响应模型。 +预言机有不同类型,包括_立即读取_、_发布-订阅_和_请求-响应_,后两者在以太坊智能合约中最受欢迎。 在此我们简单描述发布-订阅和请求-响应模型。 -### 发布-订阅预言机 {#publish-subscribe-oracles} +### 发布-订阅型预言机 {#publish-subscribe-oracles} 这类预言机公开了“数据馈送”,其他合约通常可以通过读取数据馈来获取信息。 在这种情况下,数据可能会频繁变化,因此客户端合约必须侦听预言机存储中数据的更新。 例如,向用户提供最新以太币-美元价格信息的预言机。 -### 请求-响应预言机 {#request-response-oracles} +### 请求-响应型预言机 {#request-response-oracles} 请求-响应设置允许客户端合约请求除发布-订阅预言机所提供数据以外的任意数据。 当数据集太大而无法存储在智能合约的存储中,并且/或者用户在任何时间点只需要一小部分数据时,请求-响应预言机是理想之选。 @@ -220,19 +220,19 @@ contract Oracle { 发起数据查询的用户必须承担从链下来源检索信息的费用。 客户端合约还必须提供资金,用以支付预言机合约通过请求中指定的回调函数返回响应所产生的燃料费用。 -## 中心化和去中心化预言机 {#types-of-oracles} +## 中心化预言机与去中心化预言机 {#types-of-oracles} ### 中心化预言机 {#centralized-oracles} 中心化预言机由单个实体控制,该实体负责聚合链下信息并按照请求更新预言机合约的数据。 中心化预言机效率高,因为它们依赖单一真实性来源。 在专有数据集由所有者直接发布并有公认签名的情况下,中心化预言机表现更佳。 然而,它们也带来了弊端: -#### 低正确性保障 {#low-correctness-guarantees} +#### 低正确性保证 {#low-correctness-guarantees} 使用中心化预言机时,无法确认提供的信息是否正确。 甚至“信誉良好”的提供者会耍无赖或者遭遇黑客攻击。 如果预言机被破坏,智能合约将基于错误数据执行。 #### 可用性差 {#poor-availability} -中心化预言机无法保证始终向其他智能合约提供链下数据。 如果提供者决定关闭服务或者黑客劫持了预言机的链下组件,智能合约则会面临拒绝服务 (Dos) 攻击的风险。 +中心化预言机无法保证始终向智能合约提供链下数据。 如果提供者决定关闭服务或者黑客劫持了预言机的链下组件,智能合约就会面临拒绝服务 (Dos)的风险。 #### 激励兼容性差 {#poor-incentive-compatibility} @@ -246,7 +246,7 @@ contract Oracle { 使用去中心化预言机有以下好处: -### 高正确性保障 {#high-correctness-guarantees} +### 高正确性保证 {#high-correctness-guarantees} 去中心化预言机尝试使用不同的方法实现数据的正确性。 其中包括使用证明来证明返回信息的真实性和完整性,以及要求多个实体就链下数据的有效性集体达成一致。 @@ -256,9 +256,9 @@ contract Oracle { 真实性证明的示例包括: -**传输层安全性 (TLS) 证明**:预言机节点通常使用基于传输层安全性 (TLS) 协议的安全 HTTP 连接从外部数据源检索数据。 一些去中心化预言机使用真实性证明验证传输层安全性会话(即,确认节点和特定服务器之间的信息交换),并确认会话内容未被改动。 +**传输层安全协议 (TLS) 证明**:预言机节点通常使用基于传输层安全协议 (TLS) 的安全 HTTP 连接从外部来源检索数据。 一些去中心化预言机使用真实性证明验证传输层安全性会话(即,确认节点和特定服务器之间的信息交换),并确认会话内容未被改动。 -**可信执行环境 (TEE) 认证**:[可信执行环境](https://en.wikipedia.org/wiki/Trusted_execution_environment) (TEE) 是一种沙盒计算环境,它与主机系统的操作进程隔离。 可信执行环境确保在计算环境中存储/使用的任何应用代码或数据都保持完整性、保密性和不可变性。 用户还可以生成一个认证,证明应用程序实例正在可信执行环境中运行。 +**可信执行环境 (TEE) 证明**:[可信执行环境](https://en.wikipedia.org/wiki/Trusted_execution_environment) (TEE) 是一种沙盒化计算环境,与其主机系统的操作进程隔离。 可信执行环境确保在计算环境中存储/使用的任何应用代码或数据都保持完整性、保密性和不可变性。 用户还可以生成一个认证,证明应用程序实例正在可信执行环境中运行。 某些类别的去中心化预言机要求预言机节点运营者提供可信执行环境认证。 这向用户证实,节点运营者在可信执行环境中运行预言机客户端的实例。 可信执行环境防止外部进程更改或读取应用程序的代码和数据,因此,这些认证证明预言机节点保持了信息的完整性和保密性。 @@ -274,17 +274,17 @@ contract Oracle { 如果节点的答案不同于多数答案,将对其进行惩罚,即将其代币分发给提供更正确值的其他节点。 强制节点在提供数据之前提供保证金将激励节点做出诚实的响应,因为假定节点是理性的经济活动参与者,意在最大限度地增加回报。 -质押/投票还能保护去中心化预言机免受[女巫攻击](/glossary/#sybil-attack),在这种攻击中,恶意参与者创建多个身份来利用共识系统。 然而,质押机制不能防止“揩油行为”(预言机节点从其他节点复制信息)和“懒散验证”(预言机节点随大流而不亲自验证信息)。 +质押/投票也能保护去中心化预言机免受[女巫攻击](/glossary/#sybil-attack),在这种攻击中,恶意行为者会创建多个身份来操纵共识系统。 然而,质押机制不能防止“揩油行为”(预言机节点从其他节点复制信息)和“懒散验证”(预言机节点随大流而不亲自验证信息)。 ##### 谢林点机制 -[谢林点](https://en.wikipedia.org/wiki/Focal_point_(game_theory))是一个博弈论概念,它假设在缺乏任何沟通的情况下,多个实体总是默认对一个问题选择共同解决方案。 谢林点机制常用于去中心化预言机网络,使节点对数据请求的应答达成共识。 +[谢林点](https://en.wikipedia.org/wiki/Focal_point_\(game_theory\))是一个博弈论概念,它假设在没有任何沟通的情况下,多个实体总是会默认采用一个共同的解决方案来解决问题。 谢林点机制常用于去中心化预言机网络,使节点对数据请求的应答达成共识。 -这方面的一个早期想法是[谢林币](https://blog.ethereum.org/2014/03/28/schellingcoin-a-minimal-trust-universal-data-feed/),这是一种提议的数据馈送,参与者提交“标量”问题的答案(这些问题的答案由数量描述,例如“以太币的价格是多少?”)及存款。 提供的值在第 25 和第 75 [百分位](https://en.wikipedia.org/wiki/Percentile)之间的用户将得到奖励,而提供的值大幅偏离中值的用户将受到惩罚。 +这方面的一个早期想法是 [SchellingCoin](https://blog.ethereum.org/2014/03/28/schellingcoin-a-minimal-trust-universal-data-feed/),这是一种提议的数据馈送,参与者提交“标量”问题的答案(这些问题的答案由数量描述,例如“ETH 的价格是多少?”),并附带一笔押金。 提供的值在第 25 和第 75 [百分位](https://en.wikipedia.org/wiki/Percentile)之间的用户将得到奖励,而提供的值大幅偏离中值的用户将受到惩罚。 -虽然谢林币目前已不存在,但许多去中心化预言机—特别是 [Maker 协议预言机](https://docs.makerdao.com/smart-contract-modules/oracle-module)—仍使用谢林点机制来提高预言机数据的准确性。 每个 Maker 预言机均由提交抵押品资产的市场价格的链下对等节点网络(“中继者”和“馈送者”)和链上“中值器”合约组成,后者计算所有提供价值的中值。 规定的延迟期结束后,该中值成为相关资产的新参考价格。 +虽然 SchellingCoin 如今已不存在,但许多去中心化预言机(特别是 [Maker 协议的预言机](https://docs.makerdao.com/smart-contract-modules/oracle-module))仍使用谢林点机制来提高预言机数据的准确性。 每个 Maker 预言机均由提交抵押品资产的市场价格的链下对等节点网络(“中继者”和“馈送者”)和链上“中值器”合约组成,后者会计算所有提交的价格的中值。 规定的延迟期结束后,该中值成为相关资产的新参考价格。 -使用谢林点机制的其他预言机示例包括 [Chainlink 链下报告](https://docs.chain.link/docs/off-chain-reporting/)和 [Witnet](https://witnet.io/)。 在这两种系统中,对等网络中的预言机节点的答复聚合成一个单一聚合值,如平均值或中值。 根据其答复与聚合值的一致或偏离程度奖励或惩罚节点。 +使用谢林点机制的其他预言机示例包括 [Chainlink 链下报告](https://docs.chain.link/architecture-overview/off-chain-reporting)和 [Witnet](https://witnet.io/)。 在这两种系统中,对等网络中的预言机节点的答复聚合成一个单一聚合值,如平均值或中值。 根据其答复与聚合值的一致或偏离程度奖励或惩罚节点。 谢林点机制具有吸引力,因为这类机制能够最大限度地减少对链上的影响(只需要发送一笔交易)同时又能保证去中心化。 后者是可行的,因为节点必须批准已提交答复的列表,然后再将答复输入生成平均值/中值的算法。 @@ -292,15 +292,15 @@ contract Oracle { 去中心化预言机服务确保链下数据对智能合约的高可用性。 高可用性是通过对链下信息来源和负责将信息传输到链上的节点同时去中心化实现的。 -这确保了容错,因为预言机合约能够依靠多个节点(这些节点也依靠多个数据源)执行其他合约发出的查询。 在信息来源_和_节点运营商层面实现去中心化至关重要—提供从同一来源检索的信息的预言机节点网络将遇到与中心化预言机相同的问题。 +这确保了容错,因为预言机合约能够依靠多个节点(这些节点也依靠多个数据源)执行其他合约发出的查询。 在来源_和_节点运行者层面实现去中心化至关重要——一个服务于从同一来源检索的信息的预言机节点网络将遇到与中心化预言机相同的问题。 基于质押的预言机也可以对未能快速响应数据请求的节点运营商进行惩罚。 这极大地激励了预言机节点投资于容错基础设施并及时提供数据。 -### 激励兼容性好 {#good-incentive-compatibility} +### 良好的激励兼容性 {#good-incentive-compatibility} -去中心化预言机采纳了不同的激励设计,避免预言机节点中出现[拜占庭](https://en.wikipedia.org/wiki/Byzantine_fault)行为。 具体而言,它们实现了_可归因性_和_问责性_: +去中心化预言机采用各种激励设计,以防止预言机节点之间出现[拜占庭](https://en.wikipedia.org/wiki/Byzantine_fault)行为。 具体而言,它们实现了_可归因性_和_问责性_: -1. 通常,要求去中心化预言机节点对它们为了响应数据请求而提供的数据签名。 这些信息有助于评估预言机节点的历史表现,让用户在发出数据请求时筛选掉不可靠的预言机节点。 例如 Witnet 的[算法信誉系统](https://docs.witnet.io/intro/about/architecture#algorithmic-reputation-system)。 +1. 通常,要求去中心化预言机节点对它们为了响应数据请求而提供的数据签名。 这些信息有助于评估预言机节点的历史表现,让用户在发出数据请求时筛选掉不可靠的预言机节点。 一个例子是 Witnet 的[算法声誉系统](https://docs.witnet.io/intro/about/architecture#algorithmic-reputation-system)。 2. 如前所述,去中心化预言机可能要求节点对其提交数据的真实性的可信度进行质押。 如果声明得到证实,这笔质押可以连同诚信服务的奖励一起返还。 但是如果信息不正确,也可以对节点进行惩罚,这就提供了一定程度的问责性。 @@ -308,15 +308,15 @@ contract Oracle { 以下是以太坊中预言机的常见用例: -### 检索金融数据 {#retrieving-financial-data} +### 检索财务数据 {#retrieving-financial-data} -[去中心化金融](/defi/) (DeFi) 应用程序允许点对点贷款、借款和资产交易。 通常,这需要获取不同的金融信息,包括汇率数据(用于计算加密货币的法币价值或比较代币的价格)和资本市场数据(用于计算代币化资产的价值,如黄金或美元)。 +[去中心化金融](/defi/) (DeFi) 应用程序允许点对点借贷和资产交易。 通常,这需要获取不同的金融信息,包括汇率数据(用于计算加密货币的法币价值或比较代币的价格)和资本市场数据(用于计算代币化资产的价值,如黄金或美元)。 例如,一个去中心化金融贷款协议需要查询作为抵押品存储的资产(例如以太币)的当前市场价格。 这样,合约可以确定抵押品资产的价值,并确定它能从系统中借出多少钱。 -去中心化金融中热门的“价格预言机”(常用名称)包括 Chainlink Price Feeds、Compound Protocol 的[开放式喂价工具](https://compound.finance/docs/prices)、Uniswap 的[时间加权平均价格 (TWAP) ](https://docs.uniswap.org/contracts/v2/concepts/core-concepts/oracles)以及 [Maker 预言机](https://docs.makerdao.com/smart-contract-modules/oracle-module)。 +DeFi 中流行的“价格预言机”(人们通常这样称呼它们)包括 Chainlink Price Feeds、Compound Protocol 的[开放价格信息流](https://compound.finance/docs/prices)、Uniswap 的[时间加权平均价格 (TWAP)](https://docs.uniswap.org/contracts/v2/concepts/core-concepts/oracles) 和 [Maker 预言机](https://docs.makerdao.com/smart-contract-modules/oracle-module)。 -在将这些价格预言机整合到项目中之前,构建者应该了解它们附带的注意事项。 本[文](https://blog.openzeppelin.com/secure-smart-contract-guidelines-the-dangers-of-price-oracles/)详细分析了计划使用任何上述价格预言机时要考虑的因素。 +在将这些价格预言机整合到项目中之前,构建者应该了解它们附带的注意事项。 这篇[文章](https://blog.openzeppelin.com/secure-smart-contract-guidelines-the-dangers-of-price-oracles/)详细分析了计划使用任何上述价格预言机时需要考虑的因素。 下面是一个示例,说明如何使用 Chainlink 喂价工具从智能合约中检索最新以太币价格: @@ -358,73 +358,76 @@ contract PriceConsumerV3 { 某些区块链应用程序(如基于区块链的游戏或彩票方案),需要高度的不可预测性和随机性才能有效工作。 然而,区块链的确定性执行消除了任何随机性。 -原始方法是采用伪随机加密函数(例如 `blockhash`),但是它们可被[矿工操纵](https://ethereum.stackexchange.com/questions/3140/risk-of-using-blockhash-other-miners-preventing-attack#:~:text=So%20while%20the%20miners%20can,to%20one%20of%20the%20players.),对工作量证明算法进行求解。 同样,以太坊[切换到权益证明](/roadmap/merge/)意味着开发者不再能够依赖 `blockhash` 得到链上随机性。 信标链的 [RANDAO 机制](https://eth2book.info/altair/part2/building_blocks/randomness)为随机性来源提供了替代选择。 +最初的方法是使用伪随机加密函数,例如 `blockhash`,但这些函数可能会被[矿工操纵](https://ethereum.stackexchange.com/questions/3140/risk-of-using-blockhash-other-miners-preventing-attack#:~:text=So%20while%20the%20miners%20can,to%20one%20of%20the%20players.) 解决工作量证明算法。 此外,以太坊[转向权益证明](/roadmap/merge/)意味着开发者不能再依赖 `blockhash` 来获取链上随机性。 信标链的 [RANDAO 机制](https://eth2book.info/altair/part2/building_blocks/randomness)则提供了另一种随机性来源。 -可以在链下生成随机值并发送到链上,但这样做对用户有很高的信任要求。 他们必须相信值确实是通过不可预测的机制产生的,并且未在传输过程中遭到改动。 +可以在链下生成随机值并发送到链上,但这样做需要对用户有很高的信任度。 他们必须相信值确实是通过不可预测的机制产生的,并且未在传输过程中遭到改动。 -为链下计算设计的预言机解决了这一问题,它们安全地生成链下随机结果并连同证实该过程不可预测性的加密证明一起在链上广播。 [Chainlink VRF](https://docs.chain.link/docs/chainlink-vrf/)(可验证随机函数)便是一个示例,它是一个可证明公平且防篡改的随机数生成器 (RNG),用于为依靠不可预测结果的应用程序构建可靠的智能合约。 +为链下计算设计的预言机解决了这一问题,它们安全地生成链下随机结果并连同证明该过程不可预测的加密证明一起在链上广播。 一个例子是 [Chainlink VRF](https://docs.chain.link/docs/chainlink-vrf/)(可验证随机函数),它是一个可证明公平且防篡改的随机数生成器 (RNG),可用于为依赖不可预测结果的应用程序构建可靠的智能合约。 ### 获取事件结果 {#getting-outcomes-for-events} -有了预言机,创建响应真实事件的智能合约并非难事。 预言机服务允许合约通过链下组件连接到外部应用程序接口并使用来自这些数据源的信息,实现了这一点。 例如,前面介绍的预测去中心化应用程序可能会请求预言机返回可信链下来源(如美联社)提供的选举结果。 +有了预言机,创建响应真实事件的智能合约并非难事。 预言机服务允许合约通过链下组件连接到外部应用程序接口并使用来自这些数据源的信息。 例如,前面介绍的预测去中心化应用程序可能会请求预言机提供可信链下来源(如美联社)的选举结果。 使用预言机检索基于真实结果的数据,可以实现其他新颖的用例;例如,去中心化保险产品需要关于天气、灾害等的准确信息才能有效地工作。 -### 智能合约自动化 {#automating-smart-contracts} +### 自动化智能合约 {#automating-smart-contracts} 智能合约不会自动运行;相反,外部帐户 (EOA) 或另一个合约帐户必须触发正确的函数来执行合约代码。 大多数情况下,合约的大部分函数是公共函数,可由外部帐户和其他合约调用。 -但合约中也有其他合约无法访问的_私有函数_,然而它们对于去中心化应用程序的整体功能至关重要。 示例包括定期为用户铸造新非同质化代币的 `mintERC721Token()` 函数、在预测市场中付款的函数或在去中心化交易所中解锁质押代币的函数。 +但是,合约中也有其他人无法访问的_私有函数_;但这些函数对去中心化应用程序的整体功能至关重要。 示例包括定期为用户铸造新 NFT 的 `mintERC721Token()` 函数、在预测市场中奖励支付的函数,或在去中心化交易所 (DEX) 中解锁已质押代币的函数。 开发者需要每隔一段时间触发这些函数,以保持应用程序平稳运行。 然而,这可能导致开发者在普通任务上浪费更多时间,它是智能合约自动执行吸引人的原因。 一些去中心化预言机网络提供自动化服务,允许链下预言机节点根据用户定义的参数触发智能合约函数。 通常,这需要向预言机服务“注册”目标合约,提供资金支付预言机运营商,并指定触发合约的条件或时间。 -Chainlink 的 [Keeper 网络](https://chain.link/keepers)提供智能合约方案,以信任最小化和去中心化的方式将常规维护工作外包。 阅读官方 [Keeper 文档](https://docs.chain.link/docs/chainlink-keepers/introduction/),了解有关如何使合约与 Keeper 兼容以及如何使用 Upkeep 服务的信息。 +Chainlink 的 [Keeper Network](https://chain.link/keepers) 为智能合约提供了以信任最小化和去中心化的方式外包常规维护任务的选项。 阅读官方 [Keeper 文档](https://docs.chain.link/docs/chainlink-keepers/introduction/),了解如何使你的合约与 Keeper 兼容以及如何使用 Upkeep 服务的信息。 ## 如何使用区块链预言机 {#use-blockchain-oracles} 许多预言机应用程序都可以集成到以太坊去中心化应用程序中,如下所示: -**[Chainlink](https://chain.link/)** - _Chainlink 去中心化预言机网络提供防篡改的输入、输出和计算,支持任何区块链上的高级智能合约。_ +**[Chainlink](https://chain.link/)** - _Chainlink 去中心化预言机网络提供防篡改的输入、输出和计算,以支持任何区块链上的高级智能合约。_ -**[Chronicle](https://chroniclelabs.org/)** - _Chronicle 通过开发真正可扩展、经济高效、去中心化且可验证的预言机来克服当前链上数据传输面临的局限。_ +**[RedStone Oracles](https://redstone.finance/)** - _RedStone 是一个去中心化的模块化预言机,可提供 gas 优化数据馈送。 _它专门为新兴资产提供价格馈送,例如流动性质押代币 (LST)、流动性再质押代币 (LRT) 和比特币质押衍生品。_ -**[Witnet](https://witnet.io/)** - _Witnet 是一种无需许可、去中心化和抗审查的预言机,帮助智能合约对真实事件做出响应,提供强大的加密经济保障。_ +**[Chronicle](https://chroniclelabs.org/)** - _Chronicle 通过开发真正可扩展、经济高效、去中心化且可验证的预言机,克服了当前在链上传输数据的局限性。_ -**[UMA 预言机](https://uma.xyz)** - _UMA 的乐观预言机允许智能合约快速接收不同应用程序的任何类型的数据,包括保险、金融衍生品和预测市场。_ +**[Witnet](https://witnet.io/)** - _Witnet 是一种无需许可、去中心化且抗审查的预言机,可帮助智能合约以强大的加密经济保障对现实世界事件做出反应。_ -**[Tellor](https://tellor.io/)** - _Tellor 是一种透明的、无需许可的预言机协议,可以让智能合约在需要时轻松获取任何数据。_ +**[UMA Oracle](https://uma.xyz)** - _UMA 的乐观预言机允许智能合约为不同应用程序快速接收任何类型的数据,包括保险、金融衍生品和预测市场。_ -**[Band Protocol](https://bandprotocol.com/)** - _Band Protocol 是一个跨链数据预言机平台,它将真实数据和应用程序接口聚合并连接到智能合约。_ +**[Tellor](https://tellor.io/)** - _Tellor 是一个透明且无需许可的预言机协议,可让你的智能合约在需要时轻松获取任何数据。_ -**[Pyth 网络](https://pyth.network/)** - _Pyth 网络是第一方金融预言机网络,旨在在防篡改、去中心化和自我可持续的环境中在链上发布连续的真实数据。_ +**[Band Protocol](https://bandprotocol.com/)** - _Band Protocol 是一个跨链数据预言机平台,可将现实世界数据和 API 聚合和连接到智能合约。_ -**[API3 去中心化自治组织](https://www.api3.org/)** - _API3 去中心化自治组织提供第一方预言机解决方案,在智能合约的去中心化解决方案中实现更高的来源透明度、安全性和可扩展性_。 +**[Pyth Network](https://pyth.network/)** - _Pyth 网络是第一方金融预言机网络,旨在防篡改、去中心化和自给自足的环境中,在链上发布连续的真实世界数据。_ -**[Supra](https://supra.com/)** - 跨链解决方案的垂直集成工具包,可互连所有区块链,不论公共区块链(一层网络和二层网络)还是私人区块链(企业),提供可用于链上和链下用例的去中心化预言机价格源。 +**[API3 DAO](https://www.api3.org/)** - _API3 DAO 正在提供第一方预言机解决方案,在为智能合约提供的去中心化解决方案中,能够实现更高的来源透明度、安全性和可扩展性_ -## 延伸阅读 {#further-reading} +**[Supra](https://supra.com/)** - 一套垂直集成的跨链解决方案工具包,可互连所有区块链(公共(一层和二层网络)或私有(企业)),提供可用于链上和链下用例的去中心化预言机价格馈送。 + +**[Gas Network](https://gas.network/)** - 一个分布式预言机平台,提供跨区块链的实时燃料价格数据。 通过将主要燃料价格数据提供商的数据引入链上,Gas Network 正在帮助推动互操作性。 Gas Network 支持超过 35 条链的数据,包括以太坊主网和许多领先的二层网络。 + +## 扩展阅读{#further-reading} **文章** - [什么是区块链预言机?](https://chain.link/education/blockchain-oracles) — _Chainlink_ -- [什么是区块链预言机?](https://betterprogramming.pub/what-is-a-blockchain-oracle-f5ccab8dbd72) — _Patrick Collins_ -- [去中心化预言机:综述](https://medium.com/fabric-ventures/decentralised-oracles-a-comprehensive-overview-d3168b9a8841) — _Julien Thevenard_ -- [在以太坊实现区块链预言机](https://medium.com/@pedrodc/implementing-a-blockchain-oracle-on-ethereum-cedc7e26b49e) – _Pedro Costa_ -- [为什么智能合约无法调用应用程序接口?](https://ethereum.stackexchange.com/questions/301/why-cant-contracts-make-api-calls) — _StackExchange_ -- [那么,你想要使用价格预言机](https://samczsun.com/so-you-want-to-use-a-price-oracle/) — _samczsun_ +- [什么是区块链预言机?](https://medium.com/better-programming/what-is-a-blockchain-oracle-f5ccab8dbd72) — _Patrick Collins_ +- [去中心化预言机:全面概述](https://medium.com/fabric-ventures/decentralised-oracles-a-comprehensive-overview-d3168b9a8841) — _Julien Thevenard_ +- [在以太坊上实现区块链预言机](https://medium.com/@pedrodc/implementing-a-blockchain-oracle-on-ethereum-cedc7e26b49e) – _Pedro Costa_ +- [为什么智能合约不能进行 API 调用?](https://ethereum.stackexchange.com/questions/301/why-cant-contracts-make-api-calls) — _StackExchange_ +- [所以你想使用价格预言机](https://samczsun.com/so-you-want-to-use-a-price-oracle/) — _samczsun_ **视频** -- [预言机和区块链实用程序拓展](https://youtu.be/BVUZpWa8vpw) — _Real Vision Finance_ -- [第一方与第三方预言机的区别](https://blockchainoraclesummit.io/first-party-vs-third-party-oracles/) - _Blockchain Oracle Summit_ +- [预言机与区块链效用的扩展](https://youtu.be/BVUZpWa8vpw) — _Real Vision Finance_ **教程** -- [如何通过 Solidity 语言在以太坊上提取当前价格](https://blog.chain.link/fetch-current-crypto-price-data-solidity/) — _Chainlink_ -- [使用预言机数据](https://docs.chroniclelabs.org/Developers/tutorials/Remix) - _Chronicle_ +- [如何在 Solidity 中获取以太坊的当前价格](https://blog.chain.link/fetch-current-crypto-price-data-solidity/) — _Chainlink_ +- [使用预言机数据](https://docs.chroniclelabs.org/Developers/tutorials/Remix) — _Chronicle_ **示例项目** -- [使用 Solidity 语言为以太坊编写的完整 Chainlink 启动项目y](https://github.com/hackbg/chainlink-fullstack) — _HackBG_ +- [完整的以太坊 Chainlink Solidity 入门项目](https://github.com/hackbg/chainlink-fullstack) — _HackBG_ diff --git a/public/content/translations/zh/developers/docs/programming-languages/dart/index.md b/public/content/translations/zh/developers/docs/programming-languages/dart/index.md index bb0ec0ff318..d87dc9a4812 100644 --- a/public/content/translations/zh/developers/docs/programming-languages/dart/index.md +++ b/public/content/translations/zh/developers/docs/programming-languages/dart/index.md @@ -1,28 +1,32 @@ --- -title: 面向 Dart 开发者的以太坊资源 -description: 学习如何使用 Dart 语言进行以太坊开发 +title: "面向 Dart 开发者的以太坊资源" +description: "学习如何使用 Dart 语言进行以太坊开发" lang: zh incomplete: true --- -## 智能合约和 Solidity 语言入门 {#getting-started-with-smart-contracts-and-solidity} +## 从学习智能合约和 Solidity 语言入手 {#getting-started-with-smart-contracts-and-solidity} ## 教程 {#tutorials} -- [Flutter 和区块链 – Hello World 去中心化应用程序](https://www.geeksforgeeks.org/flutter-and-blockchain-hello-world-dapp/)带你了解所有步骤,内容包括: - 1. 使用 [Solidity](https://soliditylang.org/) 编写一个智能合约 - 2. 使用 Dart 编写一个用户界面 -- 如果你已经了解基础知识,[使用 Flutter 构建移动去中心化应用程序](https://medium.com/dash-community/building-a-mobile-dapp-with-flutter-be945c80315a)的篇幅要短得多,效果可能更好 -- 如果你喜欢通过观看视频来学习,可以观看[构建你的第一个区块链 Flutter 应用程序](https://www.youtube.com/watch?v=3Eeh3pJ6PeA),时长大约一个小时 -- 如果你不想花这么多时间,你可能喜欢[在以太坊上使用 Flutter 和 Dart 创建去中心化的区块链应用](https://www.youtube.com/watch?v=jaMFEOCq_1s),时长仅约 20 分钟 -- [使用 WalletConnect 开发的 Web3Modal 库,将 MetaMask 集成到 Flutter 应用程序中](https://www.youtube.com/watch?v=v_M2buHCpc4) - 这个短视频教你使用 WallectConnect 开发的 [Web3Modal](https://pub.dev/packages/web3modal_flutter) 库,一步步地将 MetaMask 集成到你的 Flutter 应用程序中 -- [Solidity & Flutter 移动区块链开发者训练营课程](https://youtube.com/playlist?list=PL4V4Unlk5luhQ26ERO6hWEbcUwHDSSmVH) - 全栈移动区块链开发者课程播放列表 +- [Flutter 和区块链 – Hello World 去中心化应用程序](https://www.geeksforgeeks.org/flutter-and-blockchain-hello-world-dapp/) 为你讲解所有入门步骤: + 1. 使用 [Solidity](https://soliditylang.org/) 编写智能合约 + 2. 使用 Dart 编写一个用户界面 +- [使用 Flutter 构建移动端去中心化应用程序](https://medium.com/dash-community/building-a-mobile-dapp-with-flutter-be945c80315a)的篇幅要短得多, + 如果你已了解基础知识,这篇教程可能更适合你 +- 如果你喜欢通过观看视频来学习,可以观看 [构建你的第一个区块链 Flutter 应用程序](https://www.youtube.com/watch?v=3Eeh3pJ6PeA),时长大约一个小时 +- 如果你比较心急,你可能更喜欢 [在以太坊上使用 Flutter 和 Dart 构建区块链去中心化应用程序](https://www.youtube.com/watch?v=jaMFEOCq_1s),时长仅约 20 分钟 +- [通过 WalletConnect 的 Web3Modal 将 MetaMask 集成到 Flutter 应用中](https://www.youtube.com/watch?v=v_M2buHCpc4) - 这个短视频将逐步向你演示如何使用 WalletConnect 的 [Web3Modal](https://pub.dev/packages/web3modal_flutter) 程序库将 MetaMask 集成到你的 Flutter 应用中 +- [使用 Solidity 和 Flutter 的移动区块链开发者训练营课程](https://youtube.com/playlist?list=PL4V4Unlk5luhQ26ERO6hWEbcUwHDSSmVH) - 全栈移动区块链开发者课程播放列表 ## 使用以太坊客户端 {#working-with-ethereum-clients} -你可以使用以太坊来创建去中心化应用程序(或称“dapp”),这种应用可以利用加密货币和区块链技术。 目前至少有两个为 Dart 维护的库,用于调用以太坊的 [JSON-RPC 应用程序接口](/developers/docs/apis/json-rpc/)。 +你可以使用以太坊来创建去中心化应用程序(或称“dapp”),这种应用可以利用加密货币和区块链技术。 +目前,Dart 至少有两个仍在维护的程序库,可用于以太坊的 +[JSON-RPC API](/developers/docs/apis/json-rpc/)。 -1. [来自 simonbutler.eu 的 Web3dart](https://pub.dev/packages/web3dart) -1. [来自 darticulate.com 的以太坊 5.0.0](https://pub.dev/packages/ethereum) +1. [来自 pwa.ir](https://pub.dev/packages/web3dart 的 Web3dart) +2. [来自 darticulate.com](https://pub.dev/packages/ethereum 的以太坊 5.0.0) -还有其他的一些库,可用于操作特定的以太坊地址或者让你检索各种加密货币的价格。 [你可以在这里查看完整的列表](https://pub.dev/dart/packages?q=ethereum)。 +还有其他的一些库,可用于操作特定的以太坊地址或者让你检索各种加密货币的价格。 +[你可以在此处查看完整列表](https://pub.dev/dart/packages?q=ethereum)。 diff --git a/public/content/translations/zh/developers/docs/programming-languages/delphi/index.md b/public/content/translations/zh/developers/docs/programming-languages/delphi/index.md index 1eff5a22461..9349b96ae0d 100644 --- a/public/content/translations/zh/developers/docs/programming-languages/delphi/index.md +++ b/public/content/translations/zh/developers/docs/programming-languages/delphi/index.md @@ -1,6 +1,6 @@ --- -title: 面向 Delphi 开发者的以太坊 -description: 学习如何使用 Delphi 编程语言为以太坊开发 +title: "面向 Delphi 开发者的以太坊资源" +description: "学习如何使用 Delphi 编程语言为以太坊开发" lang: zh incomplete: true --- @@ -11,46 +11,46 @@ incomplete: true -使用以太坊来创建去中心化应用程序,发挥加密货币和区块链技术的优势。 这些去中心化应用程序可以是值得信赖的,也即一旦被部署到以太坊上,它们将总是按程序运行。 这些应用程序可以控制数字资产,以便创造新的金融应用; 它们可以是去中心化的,也即没有任何单一实体或个人能够控制它们,而且它们几乎是不可能被审查的。 +使用以太坊来创建去中心化应用程序,发挥加密货币和区块链技术的优势。 这些去中心化应用程序可被信任,意味着一旦被部署到以太坊上,它们将总是按既定程序运行。 这些应用程序可以控制数字资产并构建新的金融应用。 它们可以是去中心化的,即没有任何单一实体或个人控制它们,而且它们几乎不可能被审查。 在以太坊顶部构建去中心化应用程序,并使用 Delphi 编程语言与智能合约交互! -## 智能合约和 Solidity 语言入门 {#getting-started-with-smart-contracts-and-the-solidity-language} +## 从学习智能合约和 Solidity 语言入手 {#getting-started-with-smart-contracts-and-the-solidity-language} **迈出第一步,将 Delphi 与以太坊集成** -需要更基础的入门知识? 请查看 [ethereum.org/learn](/learn/) 或者 [ethereum.org/developers](/developers/)。 +想对以太坊有更加全面的认识? 查看 [ethereum.org/learn](/learn/) 或 [ethereum.org/developers](/developers/)。 -- [区块链详解](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) -- [理解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [区块链解析](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [了解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) - [编写你的第一个智能合约](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) -- [学习如何编写和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) +- [学习如何编译和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) -## 初学者参考文献和链接 {#beginner-references-and-links} +## 入门参考资料和链接 {#beginner-references-and-links} **介绍 Delphereum 库** -- [什么是 Delphereum?](https://github.com/svanas/delphereum/blob/master/README.md) -- [连接 Delphi 到本地(内存)区块链中](https://medium.com/@svanas/connecting-delphi-to-a-local-in-memory-blockchain-9a1512d6c5b0) -- [连接 Delphi 到以太坊主网络](https://medium.com/@svanas/connecting-delphi-to-the-ethereum-main-net-5faf1feffd83) -- [连接 Delphi 到智能合约](https://medium.com/@svanas/connecting-delphi-to-smart-contracts-3146b12803a1) +- [Delphereum 是什么?](https://github.com/svanas/delphereum/blob/master/README.md) +- [将 Delphi 连接到本地(内存中)区块链](https://medium.com/@svanas/connecting-delphi-to-a-local-in-memory-blockchain-9a1512d6c5b0) +- [将 Delphi 连接到以太坊主网](https://medium.com/@svanas/connecting-delphi-to-the-ethereum-main-net-5faf1feffd83) +- [将 Delphi 连接到智能合约](https://medium.com/@svanas/connecting-delphi-to-smart-contracts-3146b12803a1) -**现在想要跳过设置,直接跳转到样本?** +**想要立即跳过设置,直接查看示例吗?** -- [3 分钟的智能合约和 Delphi - 第 1 部分](https://medium.com/@svanas/a-3-minute-smart-contract-and-delphi-61d998571d) -- [3 分钟的智能合约和 Delphi - 第 2 部分](https://medium.com/@svanas/a-3-minute-smart-contract-and-delphi-part-2-446925faa47b) +- [3 分钟了解智能合约与 Delphi — 第 1 部分](https://medium.com/@svanas/a-3-minute-smart-contract-and-delphi-61d998571d) +- [3 分钟了解智能合约与 Delphi — 第 2 部分](https://medium.com/@svanas/a-3-minute-smart-contract-and-delphi-part-2-446925faa47b) -## 面向中等程度用户的文章 {#intermediate-articles} +## 中级文章 {#intermediate-articles} -- [在 Delphi 中生成一个以太坊认证的消息签名](https://medium.com/@svanas/generating-an-ethereum-signed-message-signature-in-delphi-75661ce5031b) -- [使用 Delphi 交易以太币](https://medium.com/@svanas/transferring-ether-with-delphi-b5f24b1a98a4) -- [使用 Delphi 交易基于 ERC-20 的代币](https://medium.com/@svanas/transferring-erc-20-tokens-with-delphi-bb44c05b295d) +- [在 Delphi 中生成以太坊签名的消息签名](https://medium.com/@svanas/generating-an-ethereum-signed-message-signature-in-delphi-75661ce5031b) +- [用 Delphi 转移以太币](https://medium.com/@svanas/transferring-ether-with-delphi-b5f24b1a98a4) +- [用 Delphi 转移 ERC-20 代币](https://medium.com/@svanas/transferring-erc-20-tokens-with-delphi-bb44c05b295d) -## 面向高等程度用户的使用模式 {#advanced-use-patterns} +## 高级使用模式 {#advanced-use-patterns} -- [Delphi 和以太坊域名服务](https://medium.com/@svanas/delphi-and-ethereum-name-service-ens-4443cd278af7) +- [Delphi 与以太坊域名服务 (ENS)](https://medium.com/@svanas/delphi-and-ethereum-name-service-ens-4443cd278af7) - [QuikNode、以太坊和 Delphi](https://medium.com/@svanas/quiknode-ethereum-and-delphi-f7bfc9671c23) -- [Delphi 和以太坊黑暗森林](https://svanas.medium.com/delphi-and-the-ethereum-dark-forest-5b430da3ad93) -- [在 Delphi 中用一个代币交换另一个代币](https://svanas.medium.com/swap-one-token-for-another-in-delphi-bcb999c47f7) +- [Delphi 与以太坊的黑暗森林](https://svanas.medium.com/delphi-and-the-ethereum-dark-forest-5b430da3ad93) +- [在 Delphi 中将一种代币交换为另一种代币](https://svanas.medium.com/swap-one-token-for-another-in-delphi-bcb999c47f7) -想要获取更多的资源? 请查看 [ethereum.org/developers](/developers/)。 +正在寻找更多资源? 请访问 [ethereum.org/developers](/developers/)。 diff --git a/public/content/translations/zh/developers/docs/programming-languages/dot-net/index.md b/public/content/translations/zh/developers/docs/programming-languages/dot-net/index.md index 73e05baaa9d..ec0312ca5a0 100644 --- a/public/content/translations/zh/developers/docs/programming-languages/dot-net/index.md +++ b/public/content/translations/zh/developers/docs/programming-languages/dot-net/index.md @@ -1,84 +1,84 @@ --- -title: 面向 .NET 开发者的以太坊 -description: 学习如何使用并通过基于 .NET 的项目及工具参与以太坊的开发 +title: "面向 .NET 开发者的以太坊资源" +description: "学习如何使用并通过基于 .NET 的项目及工具参与以太坊的开发" lang: zh incomplete: true --- -学习如何使用并通过基于 .NET 的项目及工具参与以太坊的开发 +了解如何使用基于 .NET 的项目和工具为以太坊进行开发 -使用以太坊来创建去中心化应用程序(或称“dapp”),发挥加密货币和区块链技术的优势。 这些去中心化应用程序可以是值得信赖的,也即一旦被部署到以太坊上,它们将总是按程序运行。 这些应用程序可以控制数字资产,以便创造新的金融应用; 它们可以是去中心化的,也即没有任何单一实体或个人能够控制它们,而且它们几乎是不可能被审查的。 +使用以太坊来创建去中心化应用程序,发挥加密货币和区块链技术的优势。 这些去中心化应用程序可被信任,意味着一旦被部署到以太坊上,它们将总是按既定程序运行。 这些应用程序可以控制数字资产并构建新的金融应用。 它们可以是去中心化的,即没有任何单一实体或个人控制它们,而且它们几乎不可能被审查。 使用 Microsoft 技术堆栈中的工具和语言在以太坊上搭建去中心化应用程序和与智能合约交互 —— .NET Framework/.NET Core/.NET Standard 支持 VSCode 和 Visual Studio 等工具上的 C#、# Visual Basic .NET、F#。 使用 Microsoft Azure 区块链在 Azure 上部署一条以太坊区块链,几分钟即可完成。 将人们对 .NET 的喜爱带到以太坊上! -## 智能合约和 Solidity 语言入门 {#getting-started-with-smart-contracts-and-the-solidity-language} +## 从学习智能合约和 Solidity 语言入手 {#getting-started-with-smart-contracts-and-the-solidity-language} **迈出集成 .NET 与以太坊的第一步** -需要更基础的入门知识? 请查看 [ethereum.org/learn](/learn/) 或者 [ethereum.org/developers](/developers/)。 +想对以太坊有更加全面的认识? 查看 [ethereum.org/learn](/learn/) 或 [ethereum.org/developers](/developers/)。 -- [区块链详解](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) -- [理解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [区块链解析](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [了解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) - [编写你的第一个智能合约](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) -- [学习如何编写和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) +- [学习如何编译和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) -## 初学者参考文献和链接 {#beginner-references-and-links} +## 入门参考资料和链接 {#beginner-references-and-links} **介绍 Nethereum 库和 VS Code Solidity** -- [开始了解 Nethereum](https://docs.nethereum.com/en/latest/getting-started/) -- [安装 VS Code Solidity](https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity) -- [.NET 开发者创建和调用以太坊智能合约的工作流](https://medium.com/coinmonks/a-net-developers-workflow-for-creating-and-calling-ethereum-smart-contracts-44714f191db2) -- [智能合约与 Nethereum 的集成](https://kauri.io/#collections/Getting%20Started/smart-contracts-integration-with-nethereum/#smart-contracts-integration-with-nethereumm) -- [使用 Nethereum 连接 .NET 和以太坊区块链智能合约](https://medium.com/my-blockchain-development-daily-journey/interfacing-net-and-ethereum-blockchain-smart-contracts-with-nethereum-2fa3729ac933),也可参考此[中文版](https://medium.com/my-blockchain-development-daily-journey/%E4%BD%BF%E7%94%A8nethereum%E9%80%A3%E6%8E%A5-net%E5%92%8C%E4%BB%A5%E5%A4%AA%E7%B6%B2%E5%8D%80%E5%A1%8A%E9%8F%88%E6%99%BA%E8%83%BD%E5%90%88%E7%B4%84-4a96d35ad1e1) -- [Nethereum——开源的区块链 .NET 集成库](https://kauri.io/#collections/a%20hackathon%20survival%20guide/nethereum-an-open-source-.net-integration-library/) +- [Nethereum,入门](https://docs.nethereum.com/en/latest/getting-started/) +- [安装 VS Code Solidity 插件](https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity) +- [.NET 开发者创建和调用以太坊智能合约的工作流程](https://medium.com/coinmonks/a-net-developers-workflow-for-creating-and-calling-ethereum-smart-contracts-44714f191db2) +- [使用 Nethereum 集成智能合约](https://kauri.io/#collections/Getting%20Started/smart-contracts-integration-with-nethereum/#smart-contracts-integration-with-nethereumm) +- [使用 Nethereum 连接 .NET、以太坊区块链和智能合约](https://medium.com/my-blockchain-development-daily-journey/interfacing-net-and-ethereum-blockchain-smart-contracts-with-nethereum-2fa3729ac933),另有 [中文版](https://medium.com/my-blockchain-development-daily-journey/%E4%BD%BF%E7%94%A8nethereum%E9%80%A3%E6%8E%A5-net%E5%92%8C%E4%BB%A5%E5%A4%AA%E7%B6%B2%E5%8D%80%E5%A1%8A%E9%8F%88%E6%99%BA%E8%83%BD%E5%90%88%E7%B4%84-4a96d35ad1e1) +- [Nethereum - 一个用于区块链的开源 .NET 集成库](https://kauri.io/#collections/a%20hackathon%20survival%20guide/nethereum-an-open-source-.net-integration-library/) - [使用 Nethereum 将以太坊交易写入 SQL 数据库](https://medium.com/coinmonks/writing-ethereum-transactions-to-sql-database-using-nethereum-fd94e0e4fa36) -- [查看如何使用 C# 和 VisualStudio 轻松地部署以太坊智能合约](https://koukia.ca/deploy-ethereum-smart-contracts-using-c-and-visualstudio-5be188ae928c) +- [了解如何使用 C# 和 VisualStudio 轻松部署以太坊智能合约](https://koukia.ca/deploy-ethereum-smart-contracts-using-c-and-visualstudio-5be188ae928c) -**现在想要跳过设置,直接跳转到样本?** +**想要立即跳过设置,直接查看示例吗?** -- [训练场](http://playground.nethereum.com/) - 与以太坊进行交互,学习如何通过浏览器使用 Nethereum。 - - 查询帐户余额[C#](http://playground.nethereum.com/csharp/id/1001)[VB.NET](http://playground.nethereum.com/vb/id/2001) - - 查询 ERC20 智能合约余额[C#](http://playground.nethereum.com/csharp/id/1005)[VB.NET](http://playground.nethereum.com/vb/id/2004) - - 转账以太币至帐户 [C#](http://playground.nethereum.com/csharp/id/1003) [VB.NET](http://playground.nethereum.com/vb/id/2003) +- [演练场](http://playground.nethereum.com/) - 在浏览器中与以太坊交互并学习如何使用 Nethereum。 + - 查询帐户余额 [C#](http://playground.nethereum.com/csharp/id/1001) [VB.NET](http://playground.nethereum.com/vb/id/2001) + - 查询 ERC20 智能合约余额 [C#](http://playground.nethereum.com/csharp/id/1005) [VB.NET](http://playground.nethereum.com/vb/id/2004) + - 向帐户转账以太币 [C#](http://playground.nethereum.com/csharp/id/1003) [VB.NET](http://playground.nethereum.com/vb/id/2003) - ... 以及更多! -## 面向中等程度用户的文章 {#intermediate-articles} +## 中级文章 {#intermediate-articles} -- [Nethereum 练习册/样本列表](http://docs.nethereum.com/en/latest/Nethereum.Workbooks/docs/) +- [Nethereum 工作簿/示例列表](http://docs.nethereum.com/en/latest/Nethereum.Workbooks/docs/) - [部署你自己的开发测试链](https://github.com/Nethereum/Testchains) -- [Solidity 的 VSCode Codegen 插件](https://docs.nethereum.com/en/latest/nethereum-codegen-vscodesolidity/) -- [Unity 和以太坊:为何以及如何?](https://www.raywenderlich.com/5509-unity-and-ethereum-why-and-how) -- [为以太坊 dapp 创建 ASP.NET Core Web API](https://tech-mint.com/blockchain/create-asp-net-core-web-api-for-ethereum-dapps/) -- [使用 Nethereum Web3 来实现一个供应链追踪系统](http://blog.pomiager.com/post/using-nethereum-web3-to-implement-a-supply-chain-traking-system4) -- [Nethereum 区块处理](https://nethereum.readthedocs.io/en/latest/nethereum-block-processing-detail/),包含了[C# 操作样本](http://playground.nethereum.com/csharp/id/1025) -- [Nethereum Websocket Streaming](https://nethereum.readthedocs.io/en/latest/nethereum-subscriptions-streaming/) +- [适用于 Solidity 的 VSCode 代码生成插件](https://docs.nethereum.com/en/latest/nethereum-codegen-vscodesolidity/) +- [Unity 和以太坊:缘由与方法](https://www.raywenderlich.com/5509-unity-and-ethereum-why-and-how) +- [为以太坊去中心化应用程序创建 ASP.NET Core Web 应用程序接口](https://tech-mint.com/blockchain/create-asp-net-core-web-api-for-ethereum-dapps/) +- [使用 Nethereum Web3 实现供应链追踪系统](http://blog.pomiager.com/post/using-nethereum-web3-to-implement-a-supply-chain-traking-system4) +- [Nethereum 区块处理](https://nethereum.readthedocs.io/en/latest/nethereum-block-processing-detail/),附 [C# 演练场示例](http://playground.nethereum.com/csharp/id/1025) +- [Nethereum Websocket 流式传输](https://nethereum.readthedocs.io/en/latest/nethereum-subscriptions-streaming/) - [Kaleido 和 Nethereum](https://kaleido.io/kaleido-and-nethereum/) - [Quorum 和 Nethereum](https://github.com/Nethereum/Nethereum/blob/master/src/Nethereum.Quorum/README.md) -## 面向高等程度用户的使用模式 {#advanced-use-patterns} +## 高级使用模式 {#advanced-use-patterns} - [Azure Key Vault 和 Nethereum](https://github.com/Azure-Samples/bc-community-samples/tree/master/akv-nethereum) - [Nethereum.DappHybrid](https://github.com/Nethereum/Nethereum.DappHybrid) - [Ujo Nethereum 后端参考架构](https://docs.nethereum.com/en/latest/nethereum-ujo-backend-sample/) -## .NET 项目、工具和其他有趣内容 {#dot-net-projects-tools-and-other-fun-stuff} +## .NET 项目、工具及其他有趣内容 {#dot-net-projects-tools-and-other-fun-stuff} -- [Nethereum 训练场](http://playground.nethereum.com/) - _在浏览器中编译、创建和运行 Nethereum 代码片段_ -- [Nethereum Codegen Blazor](https://github.com/Nethereum/Nethereum.CodeGen.Blazor) - _在 Blazor 中具有 UI 的 Nethereum 代码生成_ -- [Nethereum Blazor](https://github.com/Nethereum/NethereumBlazor) - _.NET Wasm SPA 轻区块链浏览器和简单钱包_ -- [Wonka Business Rules Engine](https://docs.nethereum.com/en/latest/wonka/) - _业务规则引擎(同时适用于 .NET 平台和以太坊平台),本质上是由元数据驱动的_ -- [Nethermind](https://github.com/NethermindEth/nethermind) - _面向 Linux、Windows、MacOS 操作系统的 .NET Core 以太坊客户端_ -- [eth-utils](https://github.com/ethereum/eth-utils/) - _使用以太坊相关代码库的实用函数工具_ -- [TestChains](https://github.com/Nethereum/TestChains) - _预先配置的 .NET devchains,用于快速回应 (PoA)_ +- [Nethereum 演练场](http://playground.nethereum.com/) - _在浏览器中编译、创建并运行 Nethereum 代码片段_ +- [Nethereum Codegen Blazor](https://github.com/Nethereum/Nethereum.CodeGen.Blazor) - _带 Blazor 用户界面的 Nethereum 代码生成器_ +- [Nethereum Blazor](https://github.com/Nethereum/NethereumBlazor) - _一个 .NET Wasm SPA 轻量级区块链浏览器和简易钱包_ +- [Wonka 业务规则引擎](https://docs.nethereum.com/en/latest/wonka/) - _一种业务规则引擎(适用于 .NET 平台和以太坊平台),本质上是由元数据驱动的_ +- [Nethermind](https://github.com/NethermindEth/nethermind) - _一个适用于 Linux、Windows、MacOS 的 .NET Core 以太坊客户端_ +- [eth-utils](https://github.com/ethereum/eth-utils/) - _用于处理以太坊相关代码库的实用函数_ +- [TestChains](https://github.com/Nethereum/TestChains) - _预配置的 .NET 开发链,可实现快速响应 (PoA)_ -想要获取更多的资源? 请查看 [ethereum.org/developers](/developers/)。 +正在寻找更多资源? 请访问 [ethereum.org/developers](/developers/)。 ## .NET 社区贡献者 {#dot-net-community-contributors} -在 Nethereum,我们主要活跃于 [Gitter](https://gitter.im/Nethereum/Nethereum) 上,任何人都可以前来提问/回答问题,获得帮助或者前来逛逛。 可以随意在 [Nethereum GitHub 存储库](https://github.com/Nethereum)上提交拉取请求或者打开一个问题,或者仅仅浏览我们提供的许多小项目/示例项目。 你可以在 [Discord](https://discord.gg/jQPrR58FxX) 上找到我们! +在 Nethereum,我们主要在 [Gitter](https://gitter.im/Nethereum/Nethereum) 上交流,欢迎大家来提问、回答问题、获取帮助或者随便聊聊。 欢迎在 [Nethereum GitHub 代码库](https://github.com/Nethereum)提交 PR 或问题,或者浏览我们众多的附属/示例项目。 你也可以在 [Discord](https://discord.gg/jQPrR58FxX) 上找到我们! -如果你是 Nethermind 的新手并且需要入门帮助,请加入我们的 [Discord](http://discord.gg/PaCMRFdvWT)。 我们的开发人员随时准备回答你的问题。 不要犹豫,在 [Nethermind GitHub 存储库](https://github.com/NethermindEth/nethermind)上打开一个拉取请求或提出任何问题。 +如果你是 Nethermind 新手,需要入门帮助,请加入我们的 [Discord](http://discord.gg/PaCMRFdvWT)。 我们的开发人员随时准备回答你的问题。 欢迎在 [Nethermind GitHub 代码库](https://github.com/NethermindEth/nethermind)提交 PR 或问题。 ## 其他汇总列表 {#other-aggregated-lists} diff --git a/public/content/translations/zh/developers/docs/programming-languages/elixir/index.md b/public/content/translations/zh/developers/docs/programming-languages/elixir/index.md index 3300b4a247b..c1cd0ce994d 100644 --- a/public/content/translations/zh/developers/docs/programming-languages/elixir/index.md +++ b/public/content/translations/zh/developers/docs/programming-languages/elixir/index.md @@ -1,19 +1,19 @@ --- -title: 面向 Elixir 开发者的以太坊 -description: 了解如何使用基于 Elixir 的项目和工具为以太坊开发。 +title: "面向 Elixir 开发者的以太坊" +description: "了解如何使用基于 Elixir 的项目和工具为以太坊开发。" lang: zh incomplete: false --- 了解如何使用基于 Elixir 的项目和工具为以太坊开发。 -使用以太坊来创建去中心化应用程序(或称“dapp”),发挥加密货币和区块链技术的优势。 这些去中心化应用程序可以去信任,这意味着在部署到以太坊后,它们将始终按程序设定运行。 去中心化应用程序可以控制数字资产,从而创建新类型的金融应用程序。 它们可以是去中心化的,也即没有任何单一实体或个人能够控制它们,而且它们几乎是不可能被审查的。 +使用以太坊来创建去中心化应用程序,发挥加密货币和区块链技术的优势。 这些去中心化应用程序可以去信任,这意味着在部署到以太坊后,它们将始终按程序设定运行。 去中心化应用程序可以控制数字资产,从而创建新类型的金融应用程序。 它们可以是去中心化的,即没有任何单一实体或个人控制它们,而且它们几乎不可能被审查。 ## 从学习智能合约和 Solidity 语言入手 {#getting-started-with-smart-contracts-and-solidity} **迈出将 Elixir 与以太坊集成的第一步** -需要更基础的入门知识? 查看 [ethereum.org/learn](/learn/) 或 [ethereum.org/developers](/developers/)。 +想对以太坊有更加全面的认识? 查看 [ethereum.org/learn](/learn/) 或 [ethereum.org/developers](/developers/)。 - [区块链解析](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) - [了解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) @@ -49,7 +49,7 @@ incomplete: false - [exw3](https://github.com/hswick/exw3) - _用于 Elixir 的高级以太坊远程过程调用 (RPC) 客户端_ - [mana](https://github.com/mana-ethereum/mana) - _一个用 Elixir 编写的以太坊全节点实现_ -想要获取更多的资源? 访问[我们的开发者首页](/developers/)。 +正在寻找更多资源? 访问[我们的开发者首页](/developers/)。 ## Elixir 社区贡献者 {#elixir-community-contributors} diff --git a/public/content/translations/zh/developers/docs/programming-languages/golang/index.md b/public/content/translations/zh/developers/docs/programming-languages/golang/index.md index 0e2e3d57cd9..44cce44cc77 100644 --- a/public/content/translations/zh/developers/docs/programming-languages/golang/index.md +++ b/public/content/translations/zh/developers/docs/programming-languages/golang/index.md @@ -1,84 +1,84 @@ --- -title: 面向 Go 开发者的以太坊 -description: 学习如何使用基于 Go 的项目和工具参与以太坊的开发 +title: "面向 Go 开发者的以太坊" +description: "学习如何使用基于 Go 的项目和工具参与以太坊的开发" lang: zh incomplete: true --- -学习如何使用基于 Go 的项目和工具参与以太坊的开发 +了解如何使用基于 Go 的项目和工具为以太坊进行开发 使用以太坊创建去中心化应用程序(即"dapps")。 这些去中心化应用程序可被信任,意味着一旦被部署到以太坊上,它们将总是按既定程序运行。 它们是去中心化的,意味着它们运行在一个点对点网络中并且不存在单点故障。 不存在单一实体或者个人可以控制它们,它们也几乎不可能被审查。 它们可以通过控制数字资产来创建新的应用。 -## 智能合约和 Solidity 语言入门 {#getting-started-with-smart-contracts-and-solidity} +## 从学习智能合约和 Solidity 语言入手 {#getting-started-with-smart-contracts-and-solidity} **迈出集成 Go 与以太坊的第一步** -需要更基础的入门知识? 请查看 [ethereum.org/learn](/learn/) 或者 [ethereum.org/developers](/developers/)。 +想对以太坊有更加全面的认识? 查看 [ethereum.org/learn](/learn/) 或 [ethereum.org/developers](/developers/)。 -- [区块链详解](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) -- [理解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [区块链解析](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [了解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) - [编写你的第一个智能合约](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) -- [学习如何编写和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) -- [智能合约教程](https://github.com/ethereum/go-ethereum/wiki/Contract-Tutorial) +- [学习如何编译和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) +- [合约教程](https://github.com/ethereum/go-ethereum/wiki/Contract-Tutorial) ## 初学者文章和书籍 {#beginner-articles-and-books} -- [开始使用 Geth](https://medium.com/@tzhenghao/getting-started-with-geth-c1a30b8d6458) +- [Geth 入门](https://medium.com/@tzhenghao/getting-started-with-geth-c1a30b8d6458) - [使用 Golang 连接到以太坊](https://www.youtube.com/watch?v=-7uChuO_VzM) - [使用 Golang 部署以太坊智能合约](https://www.youtube.com/watch?v=pytGqQmDslE) -- [一步步教你测试和部署以太坊 Go 语言智能合约](https://hackernoon.com/a-step-by-step-guide-to-testing-and-deploying-ethereum-smart-contracts-in-go-9fc34b178d78) -- [电子书:使用 Go 开发以太坊](https://goethereumbook.org/) - _使用 Go 开发以太坊应用程序_ +- [在 Go 中测试和部署以太坊智能合约的分步指南](https://hackernoon.com/a-step-by-step-guide-to-testing-and-deploying-ethereum-smart-contracts-in-go-9fc34b178d78) +- [电子书:使用 Go 进行以太坊开发](https://goethereumbook.org/) - _使用 Go 开发以太坊应用_ -## 面向中等程度用户的文章和文档 {#intermediate-articles-and-docs} +## 中级文章和文档 {#intermediate-articles-and-docs} -- [Go 以太坊相关文档](https://geth.ethereum.org/docs/) - _官方以太坊 Golang 相关文档_ -- [Erigon 程序员指南](https://github.com/ledgerwatch/erigon/blob/devel/docs/programmers_guide/guide.md) - _图文指南,包括状态树、多重证明和交易处理_ +- [Go Ethereum 文档](https://geth.ethereum.org/docs/) - _以太坊官方 Golang 实现的文档_ +- [Erigon 程序员指南](https://github.com/ledgerwatch/erigon/blob/devel/docs/programmers_guide/guide.md) - _附图指南,包括状态树、多重证明和交易处理_ - [Erigon 和无状态以太坊](https://youtu.be/3-Mn7OckSus?t=394) - _2020 年以太坊社区会议 (EthCC 3)_ -- [Erigon:优化以太坊客户端](https://www.youtube.com/watch?v=CSpc1vZQW2Q) - _2018 年开发者大会 4_ -- [Go 以太坊 GoDoc](https://godoc.org/github.com/ethereum/go-ethereum) -- [在 Go 上使用 Geth 创建去中心化应用程序](https://kauri.io/#collections/A%20Hackathon%20Survival%20Guide/creating-a-dapp-in-go-with-geth/) -- [用 Golang 和 Geth 使用以太坊专用网络](https://myhsts.org/tutorial-learn-how-to-work-with-ethereum-private-network-with-golang-with-geth.php) +- [Erigon:优化以太坊客户端](https://www.youtube.com/watch?v=CSpc1vZQW2Q) - _2018 年以太坊开发者大会 4_ +- [Go Ethereum GoDoc](https://godoc.org/github.com/ethereum/go-ethereum) +- [使用 Geth 在 Go 中创建去中心化应用程序](https://kauri.io/#collections/A%20Hackathon%20Survival%20Guide/creating-a-dapp-in-go-with-geth/) +- [使用 Golang 和 Geth 在以太坊私有网络上工作](https://myhsts.org/tutorial-learn-how-to-work-with-ethereum-private-network-with-golang-with-geth.php) - [使用 Go 对以太坊上的 Solidity 合约进行单元测试](https://medium.com/coinmonks/unit-testing-solidity-contracts-on-ethereum-with-go-3cc924091281) -- [使用 Geth 作为库的快速参考](https://medium.com/coinmonks/web3-go-part-1-31c68c68e20e) +- [将 Geth 用作程序库的快速参考](https://medium.com/coinmonks/web3-go-part-1-31c68c68e20e) -## 面向高等程度用户的使用模式 {#advanced-use-patterns} +## 高级使用模式 {#advanced-use-patterns} -- [使用 GETH 模拟后端搭建](https://kauri.io/#collections/An%20ethereum%20test%20toolkit%20in%20Go/the-geth-simulated-backend/#_top) -- [基于以太坊和 Quorum 的区块链即服务应用程序](https://blockchain.dcwebmakers.com/blockchain-as-a-service-apps-using-ethereum-and-quorum.html) -- [以太坊区块链应用程序中的分布式存储星际文件系统和 Swarm](https://blockchain.dcwebmakers.com/work-with-distributed-storage-ipfs-and-swarm-in-ethereum.html) -- [移动客户端:各种库和 Inproc 以太坊节点](https://github.com/ethereum/go-ethereum/wiki/Mobile-Clients:-Libraries-and-Inproc-Ethereum-Nodes) -- [原生去中心化应用程序:到以太坊合约的 Go 绑定](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) +- [GETH 模拟后端](https://kauri.io/#collections/An%20ethereum%20test%20toolkit%20in%20Go/the-geth-simulated-backend/#_top) +- [使用以太坊和 Quorum 的区块链即服务应用程序](https://blockchain.dcwebmakers.com/blockchain-as-a-service-apps-using-ethereum-and-quorum.html) +- [以太坊区块链应用程序中的分布式存储 IPFS 和 Swarm](https://blockchain.dcwebmakers.com/work-with-distributed-storage-ipfs-and-swarm-in-ethereum.html) +- [移动客户端:程序库和 Inproc 以太坊节点](https://github.com/ethereum/go-ethereum/wiki/Mobile-Clients:-Libraries-and-Inproc-Ethereum-Nodes) +- [原生去中心化应用程序:以太坊合约的 Go 绑定](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) ## Go 项目和工具 {#go-projects-and-tools} - [Geth / Go Ethereum](https://github.com/ethereum/go-ethereum) - _以太坊协议的官方 Go 实现_ -- [Go Ethereum Code Analysis](https://github.com/ZtesoftCS/go-ethereum-code-analysis) - _审查和分析 Go 以太坊源代码_ -- [Erigon](https://github.com/ledgerwatch/erigon) - _Go 以太坊的更快衍生品,专注于归档节点_ -- [Golem](https://github.com/golemfactory/golem) - _Golem 正在创建一个算力全球市场_ -- [Quorum](https://github.com/jpmorganchase/quorum) - _支持数据隐私的许可型以太坊实现_ -- [Prysm](https://github.com/prysmaticlabs/prysm) - _以太坊 'Serenity' 2.0 Go 实现_ -- [Eth Tweet](https://github.com/yep/eth-tweet) - _去中心化 Twitter:运行在以太坊区块链上的微博客服务_ -- [Plasma MVP Golang](https://github.com/kyokan/plasma) — _Golang 实现以及最小可执行 Plasma 规范拓展_ -- [Open Ethereum Mining Pool](https://github.com/sammy007/open-ethereum-pool) - _以太坊开源矿池_ -- [Ethereum HD Wallet](https://github.com/miguelmota/go-ethereum-hdwallet) - _使用 Go 的以太坊硬件钱包衍生品_ +- [Go Ethereum 代码分析](https://github.com/ZtesoftCS/go-ethereum-code-analysis) - _Go Ethereum 源代码的审查和分析_ +- [Erigon](https://github.com/ledgerwatch/erigon) - _Go Ethereum 的更快衍生版本,专注于归档节点_ +- [Golem](https://github.com/golemfactory/golem) - _Golem 正在创建一个全球算力市场_ +- [Quorum](https://github.com/jpmorganchase/quorum) - _一种支持数据隐私的以太坊许可型实现_ +- [Prysm](https://github.com/prysmaticlabs/prysm) - _以太坊“宁静”2.0 Go 实现_ +- [Eth Tweet](https://github.com/yep/eth-tweet) - _去中心化推特:一个运行在以太坊区块链上的微博客服务_ +- [Plasma MVP Golang](https://github.com/kyokan/plasma) — _最小可行 Plasma 规范的 Golang 实现和扩展_ +- [开源以太坊矿池](https://github.com/sammy007/open-ethereum-pool) - _一个开源的以太坊矿池_ +- [以太坊 HD 钱包](https://github.com/miguelmota/go-ethereum-hdwallet) - _以太坊 HD 钱包的 Go 派生实现_ - [Multi Geth](https://github.com/multi-geth/multi-geth) - _支持多种以太坊网络_ -- [Geth Light Client](https://github.com/zsfelfoldi/go-ethereum/wiki/Geth-Light-Client) - _轻量级以太坊子协议的 Geth 实现_ -- [以太坊 Golang 软件开发工具包](https://github.com/everFinance/goether) - _Golang 中的简单以太坊钱包实现和实用程序_ -- [Covalent Golang 软件开发工具包](https://github.com/covalenthq/covalent-api-sdk-go) - _通过 Go 软件开发工具包高效访问多达 200 个区块链的区块链数据_ +- [Geth 轻客户端](https://github.com/zsfelfoldi/go-ethereum/wiki/Geth-Light-Client) - _轻以太坊子协议的 Geth 实现_ +- [以太坊 Golang 软件开发工具包](https://github.com/everFinance/goether) - _用 Golang 实现的一个简单以太坊钱包和实用工具_ +- [Covalent Golang 软件开发工具包](https://github.com/covalenthq/covalent-api-sdk-go) - _通过 Go 软件开发工具包高效访问 200 多个区块链的区块链数据_ -想要获取更多的资源? 请查看 [ethereum.org/developers](/developers/)。 +正在寻找更多资源? 查看 [ethereum.org/developers](/developers/) ## Go 社区贡献者 {#go-community-contributors} - [Geth Discord](https://discordapp.com/invite/nthXNEv) -- [Geth Gist](https://gitter.im/ethereum/go-ethereum) +- [Geth Gitter](https://gitter.im/ethereum/go-ethereum) - [Gophers Slack](https://invite.slack.golangbridge.org/) - [#ethereum 频道](https://gophers.slack.com/messages/C9HP1S9V2) - [StackExchange - 以太坊](https://ethereum.stackexchange.com/) - [Multi Geth Gitter](https://gitter.im/ethoxy/multi-geth) - [Ethereum Gitter](https://gitter.im/ethereum/home) -- [Geth light Client Gitter](https://gitter.im/ethereum/light-client) +- [Geth 轻客户端 Gitter](https://gitter.im/ethereum/light-client) ## 其他汇总列表 {#other-aggregated-lists} -- [强大的以太坊](https://github.com/btomashvili/awesome-ethereum) -- [Consensys:以太坊开发工具的权威清单](https://media.consensys.net/an-definitive-list-of-ethereum-developer-tools-2159ce865974) | [GitHub 源](https://github.com/ConsenSys/ethereum-developer-tools-list) +- [以太坊精选资源](https://github.com/btomashvili/awesome-ethereum) +- [Consensys:以太坊开发者工具权威列表](https://media.consensys.net/an-definitive-list-of-ethereum-developer-tools-2159ce865974) | [GitHub 源代码](https://github.com/ConsenSys/ethereum-developer-tools-list) diff --git a/public/content/translations/zh/developers/docs/programming-languages/index.md b/public/content/translations/zh/developers/docs/programming-languages/index.md index 0765816e715..8be865783c9 100644 --- a/public/content/translations/zh/developers/docs/programming-languages/index.md +++ b/public/content/translations/zh/developers/docs/programming-languages/index.md @@ -1,10 +1,11 @@ --- -title: 编程语言 -description: +title: "编程语言" +description: "探索各种编程语言的以太坊开发资源,包括 JavaScript、Python、Go、Rust 等等。" lang: zh --- -一个常见的误解是开发者必须编写[智能合约](/developers/docs/smart-contracts/)才能在以太坊上构建。 这是错误的。 以太坊网络及其社区的一个美好之处是你可以使用任意编程语言[参与](/community/)其中。 +一个常见的误解是开发者必须编写智能合约才能在以太坊上构建。 这是错误的。 +以太坊网络及其社区的一个美好之处是你可以使用任意编程语言参与其中。 以太坊及其社区拥抱开源。 你可以找到各种语言的社区项目 - 客户端实现、API、开发框架、测试工具。 @@ -12,19 +13,21 @@ lang: zh 选择你使用的编程语言以便查找项目、资源和虚拟社区: -- [面向 Dart 开发者的以太坊资源](/developers/docs/programming-languages/dart/) -- [面向 Delphi 开发者的以太坊资源](/developers/docs/programming-languages/delphi/) -- [面向 .NET 开发者的以太坊资源](/developers/docs/programming-languages/dot-net/) +- [面向 Dart 开发者的以太坊](/developers/docs/programming-languages/dart/) +- [面向 Delphi 开发者的以太坊](/developers/docs/programming-languages/delphi/) +- [面向 .NET 开发者的以太坊](/developers/docs/programming-languages/dot-net/) - [面向 Elixir 开发者的以太坊](/developers/docs/programming-languages/elixir/) -- [面向 Go 开发者的以太坊资源](/developers/docs/programming-languages/golang/) -- [面向 Java 开发者的以太坊资源](/developers/docs/programming-languages/java/) -- [面向 JavaScript 开发者的以太坊资源](/developers/docs/programming-languages/javascript/) -- [面向 Python 开发者的以太坊资源](/developers/docs/programming-languages/python/) -- [面向 Ruby 开发者的以太坊资源](/developers/docs/programming-languages/ruby/) -- [面向 Rust 开发者的以太坊资源](/developers/docs/programming-languages/rust/) +- [面向 Go 开发者的以太坊](/developers/docs/programming-languages/golang/) +- [面向 Java 开发者的以太坊](/developers/docs/programming-languages/java/) +- [面向 JavaScript 开发者的以太坊](/developers/docs/programming-languages/javascript/) +- [面向 Python 开发者的以太坊](/developers/docs/programming-languages/python/) +- [面向 Ruby 开发者的以太坊](/developers/docs/programming-languages/ruby/) +- [面向 Rust 开发者的以太坊](/developers/docs/programming-languages/rust/) ### 如果不支持我的语言怎么办 {#other-lang} -如果你想链接到资源或指向额外编程语言的虚拟社区,你可以通过[提出问题](https://github.com/ethereum/ethereum-org-website/issues/new/choose) 来申请新页面。 +如果你想为其他编程语言添加资源链接或指向某个虚拟社区,可以通过[提交问题](https://github.com/ethereum/ethereum-org-website/issues/new/choose)来申请新页面。 -如果只想使用当前不支持的语言 编写与区块链对接的代码,你可以使用 [JSON-RPC 接口](/developers/docs/apis/json-rpc/)连接以太坊网络。 任何可以使用 TCP/IP 的编程 语言都可以使用此接口。 +如果只想使用当前不支持的语言 +编写与区块链对接的代码,你可以使用 [JSON-RPC 接口](/developers/docs/apis/json-rpc/) 连接到以太坊网络。 任何可以使用 TCP/IP 的编程 +语言都可以使用此接口。 diff --git a/public/content/translations/zh/developers/docs/programming-languages/java/index.md b/public/content/translations/zh/developers/docs/programming-languages/java/index.md index 61f53467d81..3924d95609d 100644 --- a/public/content/translations/zh/developers/docs/programming-languages/java/index.md +++ b/public/content/translations/zh/developers/docs/programming-languages/java/index.md @@ -1,61 +1,62 @@ --- -title: 面向 Java 开发者的以太坊资源 -description: 学习如何使用并通过基于 Java 的项目及工具参与以太坊的开发 +title: "面向 Java 开发者的以太坊资源" +description: "学习如何使用并通过基于 Java 的项目及工具参与以太坊的开发" lang: zh incomplete: true --- -学习如何使用并通过基于 Java 的项目及工具参与以太坊的开发 +了解如何使用基于 Java 的项目和工具为以太坊开发 -使用以太坊来创建去中心化应用程序(或称“dapp”),发挥加密货币和区块链技术的优势。 这些去中心化应用程序可以是值得信赖的,也即一旦被部署到以太坊上,它们将总是按程序运行。 这些应用程序可以控制数字资产,以便创造新的金融应用; 它们可以是去中心化的,也即没有任何单一实体或个人能够控制它们,而且它们几乎是不可能被审查的。 +使用以太坊来创建去中心化应用程序,发挥加密货币和区块链技术的优势。 这些去中心化应用程序可被信任,意味着一旦被部署到以太坊上,它们将总是按既定程序运行。 这些应用程序可以控制数字资产并构建新的金融应用。 它们可以是去中心化的,即没有任何单一实体或个人控制它们,而且它们几乎不可能被审查。 -## 智能合约和 Solidity 语言入门 {#getting-started-with-smart-contracts-and-solidity} +## 从学习智能合约和 Solidity 语言入手 {#getting-started-with-smart-contracts-and-solidity} **迈出第一步,将 Java 与以太坊进行集成** -需要更基础的入门知识? 请查看 [ethereum.org/learn](/learn/) 或者 [ethereum.org/developers](/developers/)。 +想对以太坊有更加全面的认识? 查看 [ethereum.org/learn](/learn/) 或 [ethereum.org/developers.](/developers/)。 -- [区块链详解](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) -- [理解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [区块链解析](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [了解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) - [编写你的第一个智能合约](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) -- [学习如何编写和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) +- [学习如何编译和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) ## 使用以太坊客户端 {#working-with-ethereum-clients} 了解如何使用 [Web3J](https://github.com/web3j/web3j) 和 Hyperledger Besu 这两个领先的 Java 以太坊客户端。 -- [使用 Java 、Eclipse 和 Web3J 连接以太坊客户端](https://kauri.io/article/b9eb647c47a546bc95693acc0be72546/connecting-to-an-ethereum-client-with-java-eclipse-and-web3j) +- [使用 Java、Eclipse 和 Web3J 连接到以太坊客户端](https://kauri.io/article/b9eb647c47a546bc95693acc0be72546/connecting-to-an-ethereum-client-with-java-eclipse-and-web3j) - [使用 Java 和 Web3j 管理以太坊帐户](https://kauri.io/article/925d923e12c543da9a0a3e617be963b4/manage-an-ethereum-account-with-java-and-web3j) -- [从智能合约中生成 Java 包装器](https://kauri.io/article/84475132317d4d6a84a2c42eb9348e4b/generate-a-java-wrapper-from-your-smart-contract) -- [与以太坊智能合约互动](https://kauri.io/article/14dc434d11ef4ee18bf7d57f079e246e/interacting-with-an-ethereum-smart-contract-in-java) +- [从您的智能合约生成 Java 包装器](https://kauri.io/article/84475132317d4d6a84a2c42eb9348e4b/generate-a-java-wrapper-from-your-smart-contract) +- [与以太坊智能合约交互](https://kauri.io/article/14dc434d11ef4ee18bf7d57f079e246e/interacting-with-an-ethereum-smart-contract-in-java) - [监听以太坊智能合约事件](https://kauri.io/article/760f495423db42f988d17b8c145b0874/listening-for-ethereum-smart-contract-events-in-java) -- [使用 Besu (Pantheon), Linux 下的 Java 以太坊客户端](https://kauri.io/article/276dd27f1458443295eea58403fd6965/using-pantheon-the-java-ethereum-client-with-linux) -- [在 Java 集成测试中运行一个 Hyperledger Besu (Pantheon) 节点](https://kauri.io/article/7dc3ecc391e54f7b8cbf4e5fa0caf780/running-a-pantheon-node-in-java-integration-tests) -- [Web3j 备忘单](https://kauri.io/web3j-cheat-sheet-(java-ethereum)/5dfa1ea941ac3d0001ce1d90/c) +- [在 Linux 上使用 Java 以太坊客户端 Besu (Pantheon)](https://kauri.io/article/276dd27f1458443295eea58403fd6965/using-pantheon-the-java-ethereum-client-with-linux) +- [在 Java 集成测试中运行 Hyperledger Besu (Pantheon) 节点](https://kauri.io/article/7dc3ecc391e54f7b8cbf4e5fa0caf780/running-a-pantheon-node-in-java-integration-tests) +- [Web3j 备忘单](https://kauri.io/web3j-cheat-sheet-\(java-ethereum\)/5dfa1ea941ac3d0001ce1d90/c) + +了解如何使用 [ethers-kt](https://github.com/Kr1ptal/ethers-kt),一个与基于 EVM 的区块链交互的异步、高性能 Kotlin 程序库。 面向 Java 虚拟机和 Android 平台。 -学习如何使用 [ethers-kt](https://github.com/Kr1ptal/ethers-kt),一个用来同基于以太坊虚拟机的区块链互动的高性能异步 Kotlin 库。 面向 Java 虚拟机和 Android 平台。 - [转移 ERC20 代币](https://github.com/Kr1ptal/ethers-kt/blob/master/examples/src/main/kotlin/io/ethers/examples/abi/TransferERC20.kt) -- [带事件监听的 UniswapV2 Swap](https://github.com/Kr1ptal/ethers-kt/blob/master/examples/src/main/kotlin/io/ethers/examples/tokenswapwitheventlistening/TokenSwapWithEventListening.kt) -- [以太币 / ERC20 余额追踪器](https://github.com/Kr1ptal/ethers-kt/blob/master/examples/src/main/kotlin/io/ethers/examples/balancetracker/BalanceTracker.kt) +- [带事件监听的 UniswapV2 交换](https://github.com/Kr1ptal/ethers-kt/blob/master/examples/src/main/kotlin/io/ethers/examples/tokenswapwitheventlistening/TokenSwapWithEventListening.kt) +- [ETH / ERC20 余额跟踪器](https://github.com/Kr1ptal/ethers-kt/blob/master/examples/src/main/kotlin/io/ethers/examples/balancetracker/BalanceTracker.kt) -## 面向中等程度用户的文章 {#intermediate-articles} +## 中级文章 {#intermediate-articles} -- [使用星际文件系统在 Java 应用程序中管理存储](https://kauri.io/article/3e8494f4f56f48c4bb77f1f925c6d926/managing-storage-in-a-java-application-with-ipfs) +- [使用 IPFS 在 Java 应用中管理存储](https://kauri.io/article/3e8494f4f56f48c4bb77f1f925c6d926/managing-storage-in-a-java-application-with-ipfs) - [使用 Web3j 在 Java 中管理 ERC20 代币](https://kauri.io/article/d13e911bbf624108b1d5718175a5e0a0/manage-erc20-tokens-in-java-with-web3j) - [Web3j 交易管理器](https://kauri.io/article/4cb780bb4d0846438d11885a25b6d7e7/web3j-transaction-managers) -## 面向高等程度用户的使用模式 {#advanced-use-patterns} +## 高级使用模式 {#advanced-use-patterns} - [使用 Eventeum 构建 Java 智能合约数据缓存](https://kauri.io/article/fe81ee9612eb4e5a9ab72790ef24283d/using-eventeum-to-build-a-java-smart-contract-data-cache) ## Java 项目和工具 {#java-projects-and-tools} -- [Web3J(与以太坊客户端交互的库)](https://github.com/web3j/web3j) -- [ethers-kt(面向基于以太坊虚拟机区块链的高性能异步 Kotlin/Java/Android 库)](https://github.com/Kr1ptal/ethers-kt) -- [Eventeum(事件侦听器)](https://github.com/ConsenSys/eventeum) -- [Mahuta(IPFS 开发者工具)](https://github.com/ConsenSys/mahuta) +- [Web3J(与以太坊客户端交互的程序库)](https://github.com/web3j/web3j) +- [ethers-kt(面向基于 EVM 的区块链的异步、高性能 Kotlin/Java/Android 程序库。)](https://github.com/Kr1ptal/ethers-kt) +- [Eventeum(事件监听器)](https://github.com/ConsenSys/eventeum) +- [Mahuta(IPFS 开发工具)](https://github.com/ConsenSys/mahuta) -想要获取更多的资源? 请浏览 [ethereum.org/developers](/developers/)。 +正在寻找更多资源? 请查看 [ethereum.org/developers.](/developers/) ## Java 社区贡献者 {#java-community-contributors} diff --git a/public/content/translations/zh/developers/docs/programming-languages/javascript/index.md b/public/content/translations/zh/developers/docs/programming-languages/javascript/index.md index 37a56e5829a..b9817c80cc5 100644 --- a/public/content/translations/zh/developers/docs/programming-languages/javascript/index.md +++ b/public/content/translations/zh/developers/docs/programming-languages/javascript/index.md @@ -1,34 +1,35 @@ --- -title: 面向 JavaScript 开发者的以太坊资源 -description: 学习如何使用并通过基于 JavaScript 的项目及工具参与以太坊的开发。 +title: "面向 JavaScript 开发者的以太坊资源" +description: "学习如何使用并通过基于 JavaScript 的项目及工具参与以太坊的开发。" lang: zh --- -JavaScript是以太坊生态中最受欢迎的语言之一。 事实上,有一个 [团队](https://github.com/ethereumjs) 致力于尽可能多地在以太坊引入 JavaScript。 +JavaScript是以太坊生态中最受欢迎的语言之一。 事实上,有一个[团队](https://github.com/ethereumjs)致力于将尽可能多的以太坊功能引入 JavaScript。 -有机会在[堆栈的所有级别](/developers/docs/ethereum-stack/)使用 JavaScript(或接近)。 +你将有机会在[堆栈的各个层面](/developers/docs/ethereum-stack/)编写 JavaScript(或类似语言)。 -## Javascript 和以太坊的交互 {#interact-with-ethereum} +## 与以太坊交互 {#interact-with-ethereum} ### JavaScript API 库 {#javascript-api-libraries} -如果你想要写入 JavaScript 来查询区块链、发送交易等,则最方便的方法是使用 [JavaScript API 库](/developers/docs/apis/javascript/)。 这些 API 允许开发者轻松与[以太坊网络节点](/developers/docs/nodes-and-clients/)交互。 +如果你想要写入 JavaScript 来查询区块链、发送交易等,最方便的方法是使用 [JavaScript API 库](/developers/docs/apis/javascript/)。 这些 API 允许开发者轻松与[以太坊网络中的节点](/developers/docs/nodes-and-clients/)交互。 你可以使用这些库与以太坊上的智能合约交互,因此只需要使用 JavaScript 与既有合约交互就可以构建一个 dapp。 -**参阅:** +**参阅** -- [Web3.js](https://web3js.readthedocs.io/) -- [Ethers.js](https://docs.ethers.io/) _– 包含 JavaScript 和 TypeScript 的完整以太坊钱包的实现和工具。_ -- [viem](https://viem.sh) – 一个用于以太坊的 TypeScript 接口,提供与以太坊交互的底层无状态基元。 +- [Web3.js](https://web3js.readthedocs.io) +- [Ethers.js](https://ethers.org) – _包含用 JavaScript 和 TypeScript 实现的以太坊钱包和实用工具。_ +- [viem](https://viem.sh) – _一个用于以太坊的 TypeScript 接口,提供与以太坊交互的底层无状态基元。_ +- [Drift](https://ryangoree.github.io/drift/) – _一个 TypeScript 元库,内置缓存、挂钩和测试模拟功能,可跨多个 Web3 库轻松进行以太坊开发。_ ### 智能合约 {#smart-contracts} -作为 JavaScript 开发者,如果希望编写自己的智能合约,你可能想要了解 [Solidity](https://solidity.readthedocs.io)。 这是最受欢迎的智能合约语言,它在语法上类似于 JavaScript,可能会更容易学习。 +如果你是 JavaScript 开发者,并且想编写自己的智能合约,你可能需要熟悉 [Solidity](https://solidity.readthedocs.io)。 这是最受欢迎的智能合约语言,它在语法上类似于 JavaScript,可能会更容易学习。 -关于[智能合约](/developers/docs/smart-contracts/)的更多信息。 +更多关于[智能合约](/developers/docs/smart-contracts/)。 -## 理解协议 {#understand-the-protocol} +## 了解协议 {#understand-the-protocol} ### 以太坊虚拟机 {#the-ethereum-virtual-machine} @@ -40,34 +41,32 @@ JavaScript是以太坊生态中最受欢迎的语言之一。 事实上,有一 - 区块 - 区块链本身 - 交易 -- 更多... +- 以及更多... 这将有助于你理解像“一个帐户的数据结构是什么?”这样的问题。 如果你倾向于阅读代码,下面的 JavaScript 代码可以很好地成为通读文档的替代方案。 -**参阅 monorepo** -[`ethereumjs`](https://github.com/ethereumjs/ethereumjs-vm) +**查阅 EVM** +[`@ethereumjs/evm`](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/evm) ### 节点和客户端 {#nodes-and-clients} 目前正在开发的 Ethereumjs 客户端允许你发掘以太坊客户端如何使用你能理解的语言 (JavaScript) 工作! -它曾经在独立的[`存储库`](https://github.com/ethereumjs/ethereumjs-client)中托管,然而,后来作为一个包整合进了 EthereumVM monorepo。 +**查阅客户端** +[`@ethereumjs/client`](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/client) -**参阅客户端** -[`ethereumjs-client`](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/client) - -## 其它项目 {#other-projects} +## 其他项目 {#other-projects} 以太坊的 JavaScript 领域内还有许多其它东西: - 钱包工具库。 - 生成、导入和导出以太坊密钥的工具。 -- 一个 `merkle-patricia-tree` 的实现 - 一种在以太坊黄皮书中描述的数据结构。 +- `merkle-patricia-tree` 的一个实现 – 一种在以太坊黄皮书中描述的数据结构。 -可以在 [EthereumJS 存储库](https://github.com/ethereumjs)中深入了解你最感兴趣的内容 +前往 [EthereumJS 代码库](https://github.com/ethereumjs),深入研究你最感兴趣的内容。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ diff --git a/public/content/translations/zh/developers/docs/programming-languages/python/index.md b/public/content/translations/zh/developers/docs/programming-languages/python/index.md index f82619eca24..302f61aa41c 100644 --- a/public/content/translations/zh/developers/docs/programming-languages/python/index.md +++ b/public/content/translations/zh/developers/docs/programming-languages/python/index.md @@ -1,90 +1,99 @@ --- -title: 面向 Python 开发者的以太坊资源 -description: 学习如何使用并通过基于 Python 的项目及工具参与以太坊的开发 +title: "面向 Python 开发者的以太坊资源" +description: "学习如何使用并通过基于 Python 的项目及工具参与以太坊的开发" lang: zh incomplete: true --- -学习如何通过基于 Python 的项目和工具参与以太坊的开发 +了解如何使用基于 Python 的项目和工具为以太坊进行开发 -使用以太坊来创建去中心化应用程序 (或称“dapp”),发挥加密货币和区块链技术的优势。 这些 dapp 可以是值得信赖的,也即一旦被部署到以太坊上,它们将总是按程序运行。 这些应用程序可以控制数字资产,以便创造新的金融应用; 它们可以是去中心化的,也即没有任何单一实体或个人能够控制它们,而且它们几乎是不可能被审查的。 +使用以太坊来创建去中心化应用程序,发挥加密货币和区块链技术的优势。 这些去中心化应用程序可被信任,意味着一旦被部署到以太坊上,它们将总是按既定程序运行。 这些应用程序可以控制数字资产并构建新的金融应用。 它们可以是去中心化的,即没有任何单一实体或个人控制它们,而且它们几乎不可能被审查。 -## 智能合约和 Solidity 语言入门 {#getting-started-with-smart-contracts-and-solidity} +## 从学习智能合约和 Solidity 语言入手 {#getting-started-with-smart-contracts-and-solidity} **迈出第一步,将 Python 与以太坊集成** -需要更基础的入门知识? 请查看 [ethereum.org/learn](/learn/) 或者 [ethereum.org/developers](/developers/)。 +想对以太坊有更加全面的认识? 查看 [ethereum.org/learn](/learn/) 或 [ethereum.org/developers](/developers/)。 -- [区块链详解](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) -- [理解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [区块链解析](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [了解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) - [编写你的第一个智能合约](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) -- [学习如何编写和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) +- [学习如何编译和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) +- [2023 年 Python 在区块链领域的现状报告](https://tradingstrategy.ai/blog/the-state-of-python-in-blockchain-in-2023) ## 初学者文章 {#beginner-articles} -- [以太坊开发者指南 (Python)](https://snakecharmers.ethereum.org/a-developers-guide-to-ethereum-pt-1/) -- [2023 区块链报告中的 Python 状态](https://tradingstrategy.ai/blog/the-state-of-python-in-blockchain-in-2023) -- [基于 Vyper 的智能合约简介](https://kauri.io/#collections/Getting%20Started/an-introduction-to-smart-contracts-with-vyper/) -- [使用 Python 和 Brownie 部署你自己的 ERC20 代币](https://betterprogramming.pub/python-blockchain-token-deployment-tutorial-create-an-erc20-77a5fd2e1a58) -- [如何使用 Python Flask 开发 Ethereum 合约?](https://medium.com/coinmonks/how-to-develop-ethereum-contract-using-python-flask-9758fe65976e) -- [Web3.py 简介 · 面向 Python 开发者的以太坊资源](https://www.dappuniversity.com/articles/web3-py-intro) -- [如何通过 Python 和 web3.py 调用智能合约函数?](https://stackoverflow.com/questions/57580702/how-to-call-a-smart-contract-function-using-python-and-web3-py) +- [web3.py 概述](https://web3py.readthedocs.io/en/latest/overview.html) +- [以太坊 Python 生态系统概览](https://snakecharmers.ethereum.org/python-ecosystem/) +- [以太坊 (Python) 开发者指南](https://snakecharmers.ethereum.org/a-developers-guide-to-ethereum-pt-1/) +- [值得获奖:以太坊 Python 黑客松指南](https://snakecharmers.ethereum.org/prize-worthy/) +- [Vyper 智能合约简介](https://kauri.io/#collections/Getting%20Started/an-introduction-to-smart-contracts-with-vyper/) +- [如何使用 Python Flask 开发以太坊合约?](https://medium.com/coinmonks/how-to-develop-ethereum-contract-using-python-flask-9758fe65976e) +- [Web3.py 简介 · 面向 Python 开发者的以太坊教程](https://www.dappuniversity.com/articles/web3-py-intro) +- [如何使用 Python 和 web3.py 调用智能合约函数](https://stackoverflow.com/questions/57580702/how-to-call-a-smart-contract-function-using-python-and-web3-py) -## 面向中等程度用户的文章 {#intermediate-articles} +## 中级文章 {#intermediate-articles} +- [web3.py 之友:Ape 简介](https://snakecharmers.ethereum.org/intro-to-ape/) - [面向 Python 程序员的去中心化应用程序开发](https://levelup.gitconnected.com/dapps-development-for-python-developers-f52b32b54f28) - [创建 Python 以太坊接口:第 1 部分](https://hackernoon.com/creating-a-python-ethereum-interface-part-1-4d2e47ea0f4d) -- [基于 Python 的以太坊智能合约开发:完整(入门)教程](https://hackernoon.com/ethereum-smart-contracts-in-python-a-comprehensive-ish-guide-771b03990988) -- [使用 Brownie 和 Python 部署智能合约](https://dev.to/patrickalphac/using-brownie-for-to-deploy-smart-contracts-1kkp) -- [使用 Brownie 在 OpenSea 上创建非同质化代币](https://www.freecodecamp.org/news/how-to-make-an-nft-and-render-on-opensea-marketplace/) +- [Python 中的以太坊智能合约:一份(较)全面的指南](https://hackernoon.com/ethereum-smart-contracts-in-python-a-comprehensive-ish-guide-771b03990988) -## 面向高等程度用户的使用模式 {#advanced-use-patterns} +## 高级使用模式 {#advanced-use-patterns} +- [web3.py 模式:实时事件订阅](https://snakecharmers.ethereum.org/subscriptions/) +- [web3.py 模式:WebSocketProvider](https://snakecharmers.ethereum.org/websocketprovider/) - [使用 Python 编译、部署和调用以太坊智能合约](https://yohanes.gultom.id/2018/11/28/compiling-deploying-and-calling-ethereum-smartcontract-using-python/) - [使用 Slither 分析 Solidity 智能合约](https://kauri.io/#collections/DevOps/analyze-solidity-smart-contracts-with-slither/#analyze-solidity-smart-contracts-with-slither) -- [Blockchain Fintech 教程:使用 Python 借贷和借贷](https://blog.chain.link/blockchain-fintech-defi-tutorial-lending-borrowing-python/) +- [区块链金融科技教程:使用 Python 实现借贷](https://blog.chain.link/blockchain-fintech-defi-tutorial-lending-borrowing-python/) + +## 已存档的文章 + +- [使用 Python 和 Brownie 部署你自己的 ERC20 代币](https://betterprogramming.pub/python-blockchain-token-deployment-tutorial-create-an-erc20-77a5fd2e1a58) +- [使用 Brownie 和 Python 部署智能合约](https://dev.to/patrickalphac/using-brownie-for-to-deploy-smart-contracts-1kkp) +- [使用 Brownie 在 OpenSea 上创建 NFT](https://www.freecodecamp.org/news/how-to-make-an-nft-and-render-on-opensea-marketplace/) ## Python 项目和工具 {#python-projects-and-tools} ### 活跃: {#active} -- [Web3.py](https://github.com/ethereum/web3.py) - _用于与以太坊交互的 Python 库_ -- [Vyper](https://github.com/ethereum/vyper/) - _一种适用于以太坊虚拟机的 Python 智能合约语言_ -- [Ape](https://github.com/ApeWorX/ape) - _面向 Pythonista、数据科学家和安全专业人员的智能合约开发工具_ +- [Web3.py](https://github.com/ethereum/web3.py) - _用于与以太坊交互的 Python 程序库_ +- [Vyper](https://github.com/ethereum/vyper/) - _适用于 EVM 的 Python 风格智能合约语言_ +- [Ape](https://github.com/ApeWorX/ape) - _面向 Python 爱好者、数据科学家和安全专业人士的智能合约开发工具_ - [py-evm](https://github.com/ethereum/py-evm) - _以太坊虚拟机的实现_ -- [eth-tester](https://github.com/ethereum/eth-tester) - _用于测试以太坊应用程序的工具_ -- [eth-utils](https://github.com/ethereum/eth-utils/) - _使用以太坊相关代码库的实用程序函数_ -- [py-solc-x](https://pypi.org/project/py-solc-x/) - _适用于 solc Solidity 编译器(支持 0.5.x)的 Python 装饰器_ -- [pymaker](https://github.com/makerdao/pymaker) - _面向 Maker 合约的 Python 应用程序接口_ -- [siwe](https://github.com/signinwithethereum/siwe-py) - _面向 Python 的以太坊登录服务 (siwe)_ -- [用于以太坊集成的 Web3 去中心化金融](https://github.com/tradingstrategy-ai/web3-ethereum-defi) - _一个 Python 包,具有适用于 ERC-20、Uniswap 和其他流行项目的现成集成_ -- [Wake](https://getwake.io) - _用于合约测试、模糊测试、部署、漏洞扫描和代码导航的一体化 Python 框架(语言服务器 - [Solidity 工具](https://marketplace.visualstudio.com/items?itemName=AckeeBlockchain.tools-for-solidity))_ +- [eth-tester](https://github.com/ethereum/eth-tester) - _用于测试基于以太坊的应用程序的工具_ +- [eth-utils](https://github.com/ethereum/eth-utils/) - _用于处理以太坊相关代码库的实用函数_ +- [py-solc-x](https://pypi.org/project/py-solc-x/) - _solc solidity 编译器的 Python 包装器,支持 0.5.x 版本_ +- [pymaker](https://github.com/makerdao/pymaker) - _用于 Maker 合约的 Python API_ +- [siwe](https://github.com/signinwithethereum/siwe-py) - _Python 版通过以太坊登录 (siwe)_ +- [用于以太坊集成的 Web3 DeFi](https://github.com/tradingstrategy-ai/web3-ethereum-defi) - _一个 Python 包,为 ERC-20、Uniswap 和其他热门项目提供了现成的集成_ +- [Wake](https://getwake.io) - _用于合约测试、模糊测试、部署、漏洞扫描和代码导航的一体化 Python 框架(语言服务器 - [Solidity 工具](https://marketplace.visualstudio.com/items?itemName=AckeeBlockchain.tools-for-solidity))_ -### 已归档/不再维护: {#archived--no-longer-maintained} +### 已存档/不再维护: {#archived--no-longer-maintained} -- [Trinity](https://github.com/ethereum/trinity) - _以太坊的 Python 客户端_ -- [Mamba](https://github.com/arjunaskykok/mamba) - _一个用 Vyper 语言编写、编译和部署智能合约的框架_ -- [Brownie](https://github.com/eth-brownie/brownie) - _一个用于部署、测试以太坊智能合约并与之交互的 Python 框架_ -- [pydevp2p](https://github.com/ethereum/pydevp2p) - _使用 Python 实现 P2P 协议栈_ -- [py-wasm](https://github.com/ethereum/py-wasm) - _使用 Python 实现的 Web 汇编解释器_ +- [Trinity](https://github.com/ethereum/trinity) - _以太坊 Python 客户端_ +- [Mamba](https://github.com/arjunaskykok/mamba) - _用于编写、编译和部署以 Vyper 语言编写的智能合约的框架_ +- [Brownie](https://github.com/eth-brownie/brownie) - _用于部署、测试以太坊智能合约并与之交互的 Python 框架_ +- [pydevp2p](https://github.com/ethereum/pydevp2p) - _以太坊 P2P 堆栈的实现_ +- [py-wasm](https://github.com/ethereum/py-wasm) - _web assembly 解释器的 Python 实现_ -想要获取更多的资源? 请查看 [ethereum.org/developers](/developers/)。 +正在寻找更多资源? 请访问 [ethereum.org/developers](/developers/)。 ## 使用 Python 工具的项目 {#projects-using-python-tooling} 以下基于以太坊的项目使用本页提到的工具。 相关的开源代码库可作为一个很好的参考,例如代码和最佳做法。 -- [Yearn Finance](https://yearn.finance/) 和 [Yearn Vault Contracts 库](https://github.com/yearn/yearn-vaults) -- [Curve](https://curve.fi/) 和 [Curve 智能合约库](https://github.com/curvefi/curve-contract) -- [BadgerDAO](https://badger.com/) 和 [使用 Brownie 工具链的智能合约](https://github.com/Badger-Finance/badger-system) -- [Sushiswap](https://sushi.com/) 使用 [Python 来管理和部署他们的归属合约](https://github.com/sushiswap/sushi-vesting-protocols) -- 因 Alpha Homora 而知名的 [Alpha Finance](https://alphafinance.io/) 使用 [Brownie 来测试和部署他们的智能合约](https://github.com/AlphaFinanceLab/alpha-staking-contract) +- [Yearn Finance](https://yearn.finance/) 和 [Yearn Vault 合约代码库](https://github.com/yearn/yearn-vaults) +- [Curve](https://www.curve.finance/) 和 [Curve 智能合约代码库](https://github.com/curvefi/curve-contract) +- [BadgerDAO](https://badger.com/) 和[使用 Brownie 工具链的智能合约](https://github.com/Badger-Finance/badger-system) +- [Sushi](https://sushi.com/) 使用 [Python 管理和部署其归属合约](https://github.com/sushiswap/sushi-vesting-protocols) +- [Alpha Finance](https://alphafinance.io/)(因 Alpha Homora 而闻名)使用 [Brownie 来测试和部署智能合约](https://github.com/AlphaFinanceLab/alpha-staking-contract) ## Python 社区讨论 {#python-community-contributors} -- [以太坊 Python 社区 Discord](https://discord.gg/9zk7snTfWe),适合讨论 Web3.py 和其他 Python 框架 -- [Vyper Discord](https://discord.gg/SdvKC79cJk),适合讨论 Vyper 智能合约编程 +- [以太坊 Python 社区 Discord](https://discord.gg/9zk7snTfWe),用于讨论 Web3.py 和其他 Python 框架 +- [Vyper Discord](https://discord.gg/SdvKC79cJk),用于讨论 Vyper 智能合约编程 ## 其他汇总列表 {#other-aggregated-lists} -Vyper 维基百科包含[丰富的 Vyper 资源列表](https://github.com/vyperlang/vyper/wiki/Vyper-tools-and-resources) \ No newline at end of file +Vyper Wiki 有一个[非常棒的 Vyper 资源列表](https://github.com/vyperlang/vyper/wiki/Vyper-tools-and-resources) \ No newline at end of file diff --git a/public/content/translations/zh/developers/docs/programming-languages/ruby/index.md b/public/content/translations/zh/developers/docs/programming-languages/ruby/index.md index f8f4e4a6b25..ea7ff59d907 100644 --- a/public/content/translations/zh/developers/docs/programming-languages/ruby/index.md +++ b/public/content/translations/zh/developers/docs/programming-languages/ruby/index.md @@ -1,60 +1,60 @@ --- -title: 面向 Ruby 开发者的以太坊资源 -description: 了解如何使用基于 Ruby 的项目和工具为以太坊进行开发。 +title: "面向 Ruby 开发者的以太坊资源" +description: "了解如何使用基于 Ruby 的项目和工具为以太坊进行开发。" lang: zh incomplete: false --- -了解如何使用基于 Ruby 的项目和工具为以太坊进行开发。 +了解如何使用基于 Ruby 的项目和工具为以太坊开发。 使用以太坊来创建去中心化应用程序,发挥加密货币和区块链技术的优势。 这些去中心化应用程序可以去信任,这意味着在部署到以太坊后,它们将始终按程序设定运行。 去中心化应用程序可以控制数字资产,从而创建新类型的金融应用程序。 它们可以是去中心化的,即没有任何单一实体或个人控制它们,而且它们几乎不可能被审查。 -## 智能合约和 Solidity 语言入门 {#getting-started-with-smart-contracts-and-solidity} +## 从学习智能合约和 Solidity 语言入手 {#getting-started-with-smart-contracts-and-solidity} **迈出将 Ruby 与以太坊集成的第一步** -需要更基础的入门知识? 请查看 [ethereum.org/learn](/learn/) 或 [ethereum.org/developers](/developers/)。 +想对以太坊有更加全面的认识? 查看 [ethereum.org/learn](/learn/) 或 [ethereum.org/developers](/developers/)。 -- [区块链详解](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) -- [理解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [区块链解析](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [了解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) - [编写你的第一个智能合约](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) -- [学习如何编写和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) +- [学习如何编译和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) ## 初学者文章 {#beginner-articles} -- [终于明白以太坊帐户了](https://dev.to/q9/finally-understanding-ethereum-accounts-1kpe) -- [使用 MetaMask 对 Rails 用户进行最终身份验证](https://dev.to/q9/finally-authenticating-rails-users-with-metamask-3fj) +- [透彻理解以太坊帐户](https://dev.to/q9/finally-understanding-ethereum-accounts-1kpe) +- [使用 MetaMask 对 Rails 用户进行身份验证](https://dev.to/q9/finally-authenticating-rails-users-with-metamask-3fj) - [如何使用 Ruby 连接到以太坊网络](https://www.quicknode.com/guides/web3-sdks/how-to-connect-to-the-ethereum-network-using-ruby) -- [如何使用 Ruby 生成新的以太坊地址](https://www.quicknode.com/guides/web3-sdks/how-to-generate-a-new-ethereum-address-in-ruby) +- [如何在 Ruby 中生成新的以太坊地址](https://www.quicknode.com/guides/web3-sdks/how-to-generate-a-new-ethereum-address-in-ruby) -## 面向中等程度用户的文章 {#intermediate-articles} +## 中级文章 {#intermediate-articles} -- [用 Ruby 编写的区块链应用程序](https://www.nopio.com/blog/blockchain-app-ruby/) -- [使用 Ruby 连接到以太坊并执行智能合约](https://titanwolf.org/Network/Articles/Article?AID=87285822-9b25-49d5-ba2a-7ad95fff7ef9) +- [使用 Ruby 开发的区块链应用程序](https://www.nopio.com/blog/blockchain-app-ruby/) +- [使用连接到以太坊的 Ruby 来执行智能合约](https://titanwolf.org/Network/Articles/Article?AID=87285822-9b25-49d5-ba2a-7ad95fff7ef9) ## Ruby 项目和工具 {#ruby-projects-and-tools} -### 活跃资源 {#active} +### 激活 {#active} -- [eth.rb](https://github.com/q9f/eth.rb) - _Ruby 库和远程过程调用客户端,用于处理以太坊帐户、消息和交易_ +- [eth.rb](https://github.com/q9f/eth.rb) - _用于处理以太坊帐户、消息和交易的 Ruby 程序库和 RPC 客户端_ - [keccak.rb](https://github.com/q9f/keccak.rb) - _以太坊使用的 Keccak (SHA3) 哈希_ -- [siwe-ruby](https://github.com/signinwithethereum/siwe-ruby) - _使用 Ruby 实现 Sign-In with Ethereum_ -- [siwe-rails](https://github.com/signinwithethereum/siwe-rails) - _添加 SIWE 本地登录路由的 Rails gem_ -- [siwe-rails-examples](https://github.com/signinwithethereum/siwe-rails-examples) - _使用 Ruby on Rails 的 SIWE 示例(含自定义控制器)_ -- [omniauth-siwe](https://github.com/signinwithethereum/omniauth-siwe) - _面向 Sign In With Ethereum (SIWE) 的 OmniAuth 策略_ -- [omniauth-nft](https://github.com/valthon/omniauth-nft) - _面向通过非同质化代币所有权进行身份验证的 OmniAuth 策略_ -- [ethereum-on-rails](https://github.com/q9f/ethereum-on-rails) - _Ethereum on Rails 模板,允许连接 MetaMask 到 Ruby on Rails_ +- [siwe-ruby](https://github.com/signinwithethereum/siwe-ruby) - _“通过以太坊登录”的 Ruby 实现_ +- [siwe-rails](https://github.com/signinwithethereum/siwe-rails) - _添加 SIWE 本地登录路由的 Rails Gem_ +- [siwe-rails-examples](https://github.com/signinwithethereum/siwe-rails-examples) - _使用带自定义控制器的 Ruby on Rails 的 SIWE 示例_ +- [omniauth-siwe](https://github.com/signinwithethereum/omniauth-siwe) - _用于“通过以太坊登录 (SIWE)”的 OmniAuth 策略_ +- [omniauth-nft](https://github.com/valthon/omniauth-nft) - _通过 NFT 所有权进行身份验证的 OmniAuth 策略_ +- [ethereum-on-rails](https://github.com/q9f/ethereum-on-rails) - _允许将 MetaMask 连接到 Ruby on Rails 的 Ethereum on Rails 模板_ -### 已存档/停止维护的资源 {#archived--no-longer-maintained} +### 存档/已不再维护 {#archived--no-longer-maintained} -- [web3-eth](https://github.com/spikewilliams/vtada-ethereum) - _用 Ruby 调用以太坊节点的远程过程调用方法_ -- [ethereum_tree](https://github.com/longhoangwkm/ethereum_tree) - _用于根据 BIP32 标准从分层确定性钱包生成以太币地址的 Ruby 库_ -- [etherlite](https://github.com/budacom/etherlite) - _Ruby on Rails 的以太坊集成_ -- [ethereum.rb](https://github.com/EthWorks/ethereum.rb) - _使用 JSON-RPC 接口发送交易、创建合约并与之交互的 Ruby 以太坊客户端以及可使用以太坊节点的有用工具包_ -- [omniauth-ethereum.rb](https://github.com/q9f/omniauth-ethereum.rb) - _实现面向 OmniAuth 的以太坊提供商策略_ +- [web3-eth](https://github.com/spikewilliams/vtada-ethereum) - _使用 Ruby 调用以太坊节点的 RPC 方法_ +- [ethereum_tree](https://github.com/longhoangwkm/ethereum_tree) - _根据 BIP32 标准从分层确定性钱包生成 ETH 地址的 Ruby 程序库_ +- [etherlite](https://github.com/budacom/etherlite) - _用于 Ruby on Rails 的以太坊集成_ +- [ethereum.rb](https://github.com/EthWorks/ethereum.rb) - _使用 JSON-RPC 接口发送交易、创建合约并与之交互的 Ruby 以太坊客户端,以及与以太坊节点协作的实用工具包_ +- [omniauth-ethereum.rb](https://github.com/q9f/omniauth-ethereum.rb) - _为 OmniAuth 实现以太坊提供商策略_ -正在寻找更多资源? 请查看[我们的开发者之家](/developers/)。 +正在寻找更多资源? 访问[我们的开发者首页](/developers/)。 ## Ruby 社区贡献者 {#ruby-community-contributors} -[Ethereum Ruby Telegram 组](https://t.me/ruby_eth)主持着一个快速发展的社区,是讨论上述任何项目和相关主题的专用资源。 +[以太坊 Ruby Telegram 小组](https://t.me/ruby_eth) 是一个快速发展的社区,也是专门讨论上述任何项目及相关主题的专用资源。 diff --git a/public/content/translations/zh/developers/docs/programming-languages/rust/index.md b/public/content/translations/zh/developers/docs/programming-languages/rust/index.md index f00082189c4..8678e998e21 100644 --- a/public/content/translations/zh/developers/docs/programming-languages/rust/index.md +++ b/public/content/translations/zh/developers/docs/programming-languages/rust/index.md @@ -1,63 +1,65 @@ --- -title: 面向 Rust 开发者的以太坊 -description: 学习如何使用并通过基于 rust 的项目及工具参与以太坊的开发 +title: "面向 Rust 开发者的以太坊" +description: "学习如何使用并通过基于 rust 的项目及工具参与以太坊的开发" lang: zh incomplete: true --- -学习如何通过基于 Rust 的项目和工具参与以太坊的开发 +了解如何使用基于 Rust 的项目和工具为以太坊进行开发 -使用以太坊来创建去中心化应用程序(或称“dapp”),发挥加密货币和区块链技术的优势。 这些 dapp 可以是值得信赖的,也即一旦被部署到以太坊上,它们将总是按程序运行。 这些应用程序可以控制数字资产,以便创造新的金融应用; 它们可以是去中心化的,也即没有任何单一实体或个人能够控制它们,而且它们几乎是不可能被审查的。 +使用以太坊来创建去中心化应用程序,发挥加密货币和区块链技术的优势。 这些去中心化应用程序可被信任,意味着一旦被部署到以太坊上,它们将总是按既定程序运行。 这些应用程序可以控制数字资产,以便创造新的金融应用; 它们可以是去中心化的,即没有任何单一实体或个人控制它们,而且它们几乎不可能被审查。 -## 智能合约和 Solidity 语言入门 {#getting-started-with-smart-contracts-and-solidity} +## 从学习智能合约和 Solidity 语言入手 {#getting-started-with-smart-contracts-and-solidity} **迈出第一步,将 Rust 与以太坊进行集成** -需要更基础的入门知识? 请查看 [ethereum.org/learn](/learn/) 或者 [ethereum.org/developers](/developers/)。 +想对以太坊有更加全面的认识? 查看 [ethereum.org/learn](/learn/) 或 [ethereum.org/developers](/developers/)。 -- [区块链详解](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) -- [理解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) +- [区块链解析](https://kauri.io/article/d55684513211466da7f8cc03987607d5/blockchain-explained) +- [了解智能合约](https://kauri.io/article/e4f66c6079e74a4a9b532148d3158188/ethereum-101-part-5-the-smart-contract) - [编写你的第一个智能合约](https://kauri.io/article/124b7db1d0cf4f47b414f8b13c9d66e2/remix-ide-your-first-smart-contract) -- [学习如何编写和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) +- [学习如何编译和部署 Solidity](https://kauri.io/article/973c5f54c4434bb1b0160cff8c695369/understanding-smart-contract-compilation-and-deployment) ## 初学者文章 {#beginner-articles} -- [Rust 以太坊客户端](https://openethereum.github.io/) \* **注意 OpenEthereum [已被废弃](https://medium.com/openethereum/gnosis-joins-erigon-formerly-turbo-geth-to-release-next-gen-ethereum-client-c6708dd06dd)并已停止维护。** 请谨慎使用,最好切换至其他客户端实现。 +- [Rust 以太坊客户端](https://openethereum.github.io/) \* \*\*请注意,OpenEthereum [已被弃用](https://medium.com/openethereum/gnosis-joins-erigon-formerly-turbo-geth-to-release-next-gen-ethereum-client-c6708dd06dd)且不再进行维护。\*\*请谨慎使用,最好切换到另一个客户端实现。 - [使用 Rust 向以太坊发送交易](https://kauri.io/#collections/A%20Hackathon%20Survival%20Guide/sending-ethereum-transactions-with-rust/) -- [如何用 Rust Wasm 为 Kovan 编写合约的分步教程](https://github.com/paritytech/pwasm-tutorial) +- [关于如何用 Rust Wasm 为 Kovan 编写合约的详细教程](https://github.com/paritytech/pwasm-tutorial) -## 面向中等程度用户的文章 {#intermediate-articles} +## 中级文章 {#intermediate-articles} -## 面向高等程度用户的使用模式 {#advanced-use-patterns} +## 高级使用模式 {#advanced-use-patterns} -- [pwasm_ethereum 外部库与类以太坊网络交互](https://github.com/openethereum/pwasm-ethereum) -- [使用 JavaScript 和 Rust 搭建去中心化聊天室](https://medium.com/perlin-network/build-a-decentralized-chat-using-javascript-rust-webassembly-c775f8484b52) -- [使用 Vue.js 和 Rust 构建一个去中心化待办事项应用程序](https://medium.com/@jjmace01/build-a-decentralized-todo-app-using-vue-js-rust-webassembly-5381a1895beb) +- [pwasm_ethereum 外部函数程序库,用于和类以太坊网络交互](https://github.com/openethereum/pwasm-ethereum) -- [使用 Rust 构建区块链](https://blog.logrocket.com/how-to-build-a-blockchain-in-rust/) +- [使用 JavaScript 和 Rust 构建去中心化聊天应用](https://medium.com/perlin-network/build-a-decentralized-chat-using-javascript-rust-webassembly-c775f8484b52) + +- [使用 Vue.js 和 Rust 构建去中心化待办事项应用程序](https://medium.com/@jjmace01/build-a-decentralized-todo-app-using-vue-js-rust-webassembly-5381a1895beb) + +- [用 Rust 构建区块链](https://blog.logrocket.com/how-to-build-a-blockchain-in-rust/) ## Rust 项目和工具 {#rust-projects-and-tools} -- [pwasm-ethereum](https://github.com/paritytech/pwasm-ethereum) - _与类似以太坊的网络交互的外部帐户集合_ -- [Lighthouse](https://github.com/sigp/lighthouse) - _以太坊快速共识层客户端_ -- [ Ethereum WebAssembly](https://ewasm.readthedocs.io/en/mkdocs/) - _使用 WebAssembly 的确定性子集对以太坊智能合约执行层建议的重新设计_ -- [oasis_std](https://docs.rs/oasis-std/latest/oasis_std/index.html) - _OASIS 应用程序接口参考_ -- [Solaris](https://github.com/paritytech/sol-rs) - _使用本机 Parity 客户端以太坊虚拟机的 Solidity 智能合约单元测试工具。_ -- [SputnikVM](https://github.com/rust-blockchain/evm) - _以太坊虚拟机的 Rust 实现_ -- [Wavelet](https://wavelet.perlin.net/docs/smart-contracts) - _Rust 语言的 Wavelet 智能合约_ -- [Foundry](https://github.com/foundry-rs/foundry) - _以太坊应用程序开发工具包_ -- [Alloy](https://alloy.rs) - _高性能、严格测试且文档完备的程序库,用于与以太坊和其他基于以太坊虚拟机的链交互。_ -- [Ethers_rs](https://github.com/gakonst/ethers-rs) - _以太坊库和钱包的实现_ -- [SewUp](https://github.com/second-state/SewUp) - _一个帮助用户用 Rust 语言构建以太坊 Webassembly 合约的库,正如在公共后端中开发一样_ +- [pwasm-ethereum](https://github.com/paritytech/pwasm-ethereum) - _用于和类以太坊网络交互的外部函数集合_ +- [Lighthouse](https://github.com/sigp/lighthouse) - _快速的以太坊共识层客户端_ +- [Ethereum WebAssembly](https://ewasm.readthedocs.io/en/mkdocs/) - _使用 WebAssembly 的确定性子集对以太坊智能合约执行层进行的重新设计提案_ +- [oasis_std](https://docs.rs/oasis-std/latest/oasis_std/index.html) - _OASIS API 参考_ +- [Solaris](https://github.com/paritytech/sol-rs) - _使用原生 Parity 客户端 EVM 的 Solidity 智能合约单元测试工具。_ +- [SputnikVM](https://github.com/rust-blockchain/evm) - _Rust 实现的以太坊虚拟机_ +- [Wavelet](https://wavelet.perlin.net/docs/smart-contracts) - _用 Rust 编写的 Wavelet 智能合约_ +- [Foundry](https://github.com/foundry-rs/foundry) - _用于开发以太坊应用的工具包_ +- [Alloy](https://alloy.rs) - _用于与以太坊和其他基于 EVM 的链进行交互的高性能、经过良好测试且文档齐全的程序库。_ +- [Ethers_rs](https://github.com/gakonst/ethers-rs) - _以太坊程序库和钱包实现_ +- [SewUp](https://github.com/second-state/SewUp) - _一个可帮助你使用 Rust 构建以太坊 WebAssembly 合约的库,就像在通用后端中开发一样_ - [Substreams](https://github.com/streamingfast/substreams) - _并行化区块链数据索引技术_ -- [Reth](https://github.com/paradigmxyz/reth) - Reth 即 Rust 以太坊的简称,是新的以太坊全节点实现 -- [Awesome Ethereum Rust](https://github.com/Vid201/awesome-ethereum-rust) - _ 以太坊生态系统中用 Rust 编写的项目精选集合_ +- [Reth](https://github.com/paradigmxyz/reth) Reth (Rust Ethereum 的简称) 是一个新的以太坊全节点实现 +- [Awesome Ethereum Rust](https://github.com/Vid201/awesome-ethereum-rust) - _以太坊生态系统中用 Rust 编写的项目精选集合_ -想要获取更多的资源? 请查看 [ethereum.org/developers](/developers/)。 +正在寻找更多资源? 请查看 [ethereum.org/developers.](/developers/) ## Rust 社区贡献者 {#rust-community-contributors} -- [Ethereum WebAssembly](https://gitter.im/ewasm/Lobby) +- [以太坊 WebAssembly](https://gitter.im/ewasm/Lobby) - [Oasis Gitter](https://gitter.im/Oasis-official/Lobby) - [Parity Gitter](https://gitter.im/paritytech/parity) - [Enigma](https://discord.gg/SJK32GY) diff --git a/public/content/translations/zh/developers/docs/scaling/index.md b/public/content/translations/zh/developers/docs/scaling/index.md index 30bd8ce377e..bce2406d1c6 100644 --- a/public/content/translations/zh/developers/docs/scaling/index.md +++ b/public/content/translations/zh/developers/docs/scaling/index.md @@ -1,6 +1,6 @@ --- -title: 扩容 -description: 介绍以太坊社区目前正在开发的不同扩容选择。 +title: "扩容" +description: "介绍以太坊社区目前正在开发的不同扩容选择。" lang: zh sidebarDepth: 3 --- @@ -9,105 +9,105 @@ sidebarDepth: 3 随着以太坊使用人数增加,区块链已经达到了一定的容量限制。 这提高了网络使用成本,从而导致需要“扩容解决方案”。 目前正在研究、测试和执行多种解决方案,这些方案采取不同的办法来实现类似的目标。 -可扩展性的主要目标是,在不牺牲去中心化或安全性的情况下提高交易速度(更快的最终确定性)和交易吞吐量(每秒更高的交易数量)(详情请参阅[以太坊愿景](/roadmap/vision/))。 在第一层以太坊区块链上,高需求导致交易速度减慢和[燃料价格](/developers/docs/gas/)难以持续。 提高网络速度和吞吐量是有意义地大规模采用以太坊的基础。 +可扩展性的主要目标是在不牺牲去中心化或安全性的前提下,提高交易速度(更快的最终确定性)和交易吞吐量(更高的每秒交易笔数)。 在 Layer 1 以太坊区块链上,高需求会导致交易速度减慢和难以承受的[燃料价格](/developers/docs/gas/)。 提高网络速度和吞吐量是有意义地大规模采用以太坊的基础。 虽然速度和吞吐量很重要,但实现这些目标的扩容解决方案必须保持去中心化和安全性。 降低节点运营商的进入门槛,对于防止向不安全的中心化计算能力发展至关重要。 -从概念上说,我们首先将扩容分为链上扩容和链外扩容两类。 +从概念上,我们首先将扩容分为链上扩容和链外扩容两类。 ## 前提条件 {#prerequisites} 你应对所有基础性课题有很好的了解。 实施扩容解决方案是一项先进的任务,因为该技术没有经过多少实践检验,还在进一步研发中。 -## 链上扩容 {#on-chain-scaling} +## 链上扩容 {#onchain-scaling} -链上扩容需要更改以太坊协议(一层网络[主网](/glossary/#mainnet))。 长期以来,区块链分片有望扩展以太坊。 分片就是将区块链拆分成单独的部分(分片),并由部分验证者进行验证。 然而,二层网络卷叠扩容方案已取而代之,成为主要的扩容技术。 更加经济的向以太坊区块添加数据的新方式旨在让卷叠方案对用户经济划算,它的出现无疑为这一形势增添了助力。 +链上扩容需要更改以太坊协议(Layer 1 [主网](/glossary/#mainnet))。 长期以来,区块链分片有望扩展以太坊。 分片就是将区块链拆分成单独的部分(分片),并由部分验证者进行验证。 然而,二层网络卷叠扩容方案已取而代之,成为主要的扩容技术。 更加经济的向以太坊区块添加数据的新方式旨在让卷叠方案对用户经济划算,它的出现无疑为这一形势增添了助力。 ### 分片 {#sharding} -分片是拆分数据库的过程。 部分验证者将负责单独的分片,而不是跟踪整个以太坊。 分片包含在以太坊[路线图](/roadmap/)上由来已久,并且曾计划于合并到权益证明之前上线。 然而,[二层网络卷叠](#layer-2-scaling)的快速发展和 [Danksharding](/roadmap/danksharding) 的发明(将卷叠数据的二进制大对象添加以太坊区块中,并且验证者可以非常高效地进行验证),让以太坊社区青睐以卷叠为中心的扩容方案,而不是分片扩容方案。 这也将有助于保持以太坊的共识逻辑更简单。 +分片是拆分数据库的过程。 部分验证者将负责单独的分片,而不是跟踪整个以太坊。 分片在以太坊的[路线图](/roadmap/)上已存在很长时间,并且曾计划在转向权益证明的合并之前发布。 然而,[Layer 2 卷叠](#layer-2-scaling)的快速发展和 [Danksharding](/roadmap/danksharding)(将卷叠数据的二进制大对象添加到以太坊区块,可由验证者高效验证)的发明,已使以太坊社区更青睐以卷叠为中心的扩容方案,而非分片扩容。 这也将有助于保持以太坊的共识逻辑更简单。 -## 链下扩容 {#off-chain-scaling} +## 链下扩容 {#offchain-scaling} -链下解决方案与一层网络主网分开实现,它们无需更改现有以太坊协议。 部分解决方案称为“二层网络”解决方案,它们直接从一层网络以太坊共识中获得安全性,例如[乐观卷叠](/developers/docs/scaling/optimistic-rollups/)、[零知识卷叠](/developers/docs/scaling/zk-rollups/)或[状态通道](/developers/docs/scaling/state-channels/)。 其他解决方案涉及创建独立于主网获取安全性的各种形式的新链,例如[侧链](#sidechains)、[Validium](#validium) 或 [Plasma 链](#plasma)。 这些解决方案与主网进行通信,但为了实现各种不同目标,它们获得安全性的方式也有所不同。 +链下解决方案与第一阶段主网分开,无需更改现有以太坊协议。 一些被称为“Layer 2”的解决方案直接从 Layer 1 以太坊共识中获得安全性,例如[乐观卷叠](/developers/docs/scaling/optimistic-rollups/)、[零知识卷叠](/developers/docs/scaling/zk-rollups/)或[状态通道](/developers/docs/scaling/state-channels/)。 其他解决方案涉及创建独立于主网获取安全性的各种形式的新链,例如[侧链](#sidechains)、[validium](#validium) 或 [Plasma 链](#plasma)。 这些解决方案与主网进行通信,但为了实现各种不同目标,它们获得安全性的方式也有所不同。 -### 二层扩容 {#layer-2-scaling} +### Layer 2 扩容 {#layer-2-scaling} -此类链下解决方案的安全性来自以太坊主网。 +以太坊主网负责确保此类链下解决方案的安全。 二层网络是一种统称,用来描述那些通过在以太坊主网(一层网络)下处理交易,同时利用主网强大的去中心化安全模型来帮助扩展你的应用程序的解决方案。 当网络繁忙时,交易速度会受到影响,这可能使某些类型的去中心化应用程序的用户体验变差。 而且,随着网络越来越繁忙,由于交易发送者的目标是超出对方的出价,燃料价格也随之上升。 这可能会让以太坊的使用成本非常高。 -大多数二层网络解决方案均围绕着一个服务器或服务器群集,其中每一种都可以称为节点、验证者、运营商、排序者、区块生产者或类似术语。 根据实现情况,这些二层网络的节点可由使用它们的个人、企业或实体运行,或者由第三方运营商或一大群个人(与主网相似)运行。 一般而言,交易会提交给二层网络节点,而非直接提交给一层网络(主网)。 对于部分解决方案,二层网络实例会将它们分组,然后锚定到一层网络,之后它们受一层网络保护且不能更改。 对于不同的二层网络技术和实现而言,如何做到这一点,细节方面差异很大。 +大多数二层网络解决方案均围绕着一个服务器或服务器群集,其中每一种都可以称为节点、验证者、运营商、排序者、区块生产者或类似术语。 根据实现情况,这些二层网络的节点可由使用它们的个人、企业或实体运行,或者由第三方运营商或一大群个人(与主网相似)运行。 一般而言,交易会提交给二层网络节点,而非直接提交给一层网络(主网)。 对于部分解决方案,第二阶段网络会通过实例将它们分组,然后锚定到第一阶段网络,之后它们受第一阶段网络保护且不能更改。 对于不同的二层网络技术和实现而言,如何做到这一点,细节方面差异很大。 某个特定的二层网络实例可能是开放的,由许多应用程序共享,也可能由一个项目部署,专供支持该项目的应用程序。 #### 为什么需要第二层? {#why-is-layer-2-needed} - 每秒增加交易量会大大提高用户体验,并减少以太坊主网上的网络拥塞情况。 -- 卷叠就是将多个交易打包到一个交易中,然后发到以太坊主网上,这为用户减少了燃料费用。以太坊将更具包容性,任何人都可以用得起以太坊。 +- 交易被汇总到发送至以太坊主网的单笔交易中,从而为用户降低了燃料费,使以太坊更具包容性,让世界各地的人们都可以访问。 - 关于可扩容性的任何更新都不应以分散安全性为代价 - 第二层建立在以太坊的基础上。 -- 有一些特定应用的第二层网络,在大规模处理资产时有它们自己的效率。 +- 有一些特定于应用程序的 Layer 2 网络,它们在处理大规模资产时能够发挥其独特的效率优势。 -[关于二层网络的更多信息](/layer-2/)。 +[关于 Layer 2 的更多信息](/layer-2/) -#### 卷叠 {#rollups} +#### Rollup {#rollups} 卷叠在一层网络外执行交易,并在达成共识时,在一层网络公开数据。 由于交易数据包含在一层网络区块中,因此可以通过原生的以太坊安全性来保证卷叠的安全性。 有两种具有不同安全模型的卷叠: -- **乐观卷叠**:假设交易在默认情况下有效,并且在遇到挑战的情况下只通过[**欺诈证明**](/glossary/#fraud-proof)运行计算。 [关于乐观卷叠的更多信息](/developers/docs/scaling/optimistic-rollups/)。 -- **零知识卷叠**:在链下运行计算并向链上提交[**有效性证明**](/glossary/#validity-proof)。 [关于零知识卷叠的更多信息](/developers/docs/scaling/zk-rollups/)。 +- **乐观卷叠**:默认假定交易有效,仅在有质疑时才通过[**欺诈证明**](/glossary/#fraud-proof)运行计算。 [关于乐观卷叠的更多信息](/developers/docs/scaling/optimistic-rollups/) +- **零知识卷叠**:在链下运行计算,并向主链提交[**有效性证明**](/glossary/#validity-proof)。 [关于零知识卷叠的更多信息](/developers/docs/scaling/zk-rollups/) #### 状态通道 {#channels} -状态通道采用多签合约,使参与者能够在链下快速自由地进行交易,然后再与主网落实最终确定性。 这将最大限度地减少网络拥塞、费用和延迟。 现在有两种通道:状态通道和支付通道。 +状态通道采用多签合约,使参与者能够在链下快速自由地进行交易,然后再和主网落实并最终确定。 这将最大限度减少网络拥塞、费用和延迟。 目前有两种通道:状态通道和支付通道。 了解更多关于[状态通道](/developers/docs/scaling/state-channels/)的信息。 ### 侧链 {#sidechains} -侧链是与主网并行运行且兼容以太坊虚拟机的独立区块链。 它们通过双向桥接与以太坊兼容,按照自行选择的共识规则和区块参数运行。 +侧链是与主网并行运行的、兼容 EVM 的独立区块链。 它们通过双向链桥与以太坊兼容,并按照自行选择的共识规则和区块参数运行。 -了解更多有关[侧链](/developers/docs/scaling/sidechains/)的信息。 +了解更多关于[侧链](/developers/docs/scaling/sidechains/)的信息。 -### 以太坊 Plasma 扩容解决方案 {#plasma} +### Plasma {#plasma} -Plasma 是一条独立的区块链,锚定至以太坊主链,并使用欺诈证明(如[乐观卷叠](/developers/docs/scaling/optimistic-rollups/))来仲裁争议。 +Plasma 链是一条独立的区块链,锚定在以太坊主链上,并使用欺诈证明(类似[乐观卷叠](/developers/docs/scaling/optimistic-rollups/))来仲裁争议。 了解更多关于 [Plasma](/developers/docs/scaling/plasma/) 的信息。 ### Validium {#validium} -Validium 链使用诸如零知识卷叠之类的有效性证明,但数据未存储在一层网络以太坊主链上。 这会导致每条 Validium 链每秒处理 10000 笔交易,并且可以并行运行多条链。 +Validium 链使用诸如零知识卷叠之类的有效性证明,但数据未存储在一层网络以太坊主链上。 这让每条 Validium 链每秒可以处理 10,000 笔交易,并且可以并行运行多条链。 -了解关于 [Validium](/developers/docs/scaling/validium/) 的更多信息。 +了解更多关于 [Validium](/developers/docs/scaling/validium/) 的信息。 ## 为何需要如此多扩容解决方案? {#why-do-we-need-these} -- 多重解决方案有助于减少网络任意部分的总体阻塞情况,也可防止单点故障。 +- 多种解决方案有助于减少网络任何部分的总体拥堵情况,并可防止单点故障。 - 整体大于各部分的总和。 不同的解决方案可以同时存在,并且可以协同工作,对未来的交易速度和吞吐量产生指数效应。 - 并非所有解决方案都需要直接利用以太坊共识算法,替代办法或许能带来难以获得的好处。 -- 一种扩容方案不足以完全满足[以太坊愿景](/roadmap/vision/)。 ## 更愿意通过视频学习? {#visual-learner} -_请注意,视频中的解释使用“二层网络”这一术语指代所有链下扩容解决方案,而我们通常所说的“二层网络”是指通过一层网络主网共识获得安全性的链下解决方案。_ +_注意,视频中的解释使用“Layer 2”一词来指代所有链下扩容解决方案,而我们所说的“Layer 2”是指通过 Layer 1 主网共识来获得其安全性的链下解决方案。_ -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [以卷叠为中心的以太坊路线图](https://ethereum-magicians.org/t/a-rollup-centric-ethereum-roadmap/4698) _Vitalik Buterin_ -- [有关以太坊第二层扩容解决方案的最新分析](https://www.l2beat.com/) -- [评估以太坊第二层扩容解决方案:一个比较框架](https://medium.com/matter-labs/evaluating-ethereum-l2-scaling-solutions-a-comparison-framework-b6b2f410f955) -- [卷叠不完全指南](https://vitalik.eth.limo/general/2021/01/05/rollup.html) -- [以太坊赋能的零知识卷叠:强者](https://hackmd.io/@canti/rkUT0BD8K) -- [“乐观卷叠”对比“零知识卷叠”](https://limechain.tech/blog/optimistic-rollups-vs-zk-rollups/) -- [为什么卷叠 + 数据分片是高可扩展性的唯一可持续的解决办法](https://polynya.medium.com/why-rollups-data-shards-are-the-only-sustainable-solution-for-high-scalability-c9aabd6fbb48) -- [什么类型的三层网络有意义?](https://vitalik.eth.limo/general/2022/09/17/layer_3.html) -- [数据可用性或:卷叠如何学会停止担忧并爱上以太坊](https://ethereum2077.substack.com/p/data-availability-in-ethereum-rollups) +- [以卷叠为中心的以太坊路线图](https://ethereum-magicians.org/t/a-rollup-centric-ethereum-roadmap/4698)_Vitalik Buterin_ +- [以太坊 Layer 2 扩容解决方案的最新分析](https://www.l2beat.com/) +- [评估以太坊 Layer 2 扩容解决方案:一个比较框架](https://medium.com/matter-labs/evaluating-ethereum-l2-scaling-solutions-a-comparison-framework-b6b2f410f955) +- [Rollup 不完全指南](https://vitalik.eth.limo/general/2021/01/05/rollup.html) +- [以太坊驱动的 ZK-Rollup:世界顶尖](https://hackmd.io/@canti/rkUT0BD8K) +- [乐观 Rollup 与 ZK Rollup 对比](https://limechain.tech/blog/optimistic-rollups-vs-zk-rollups/) +- [为什么卷叠 + 数据分片是实现高可扩展性的唯一可持续解决方案](https://polynya.medium.com/why-rollups-data-shards-are-the-only-sustainable-solution-for-high-scalability-c9aabd6fbb48) +- [什么样的 Layer 3 才合理?](https://vitalik.eth.limo/general/2022/09/17/layer_3.html) +- [数据可用性,或:卷叠如何学会不再担忧并爱上以太坊](https://web.archive.org/web/20250515194659/https://web.archive.org/web/20241108192208/https://research.2077.xyz/data-availability-or-how-rollups-learned-to-stop-worrying-and-love-ethereum) +- [以太坊 Rollup 实用指南](https://web.archive.org/web/20241108192208/https://research.2077.xyz/the-practical-guide-to-ethereum-rollups) -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ diff --git a/public/content/translations/zh/developers/docs/scaling/optimistic-rollups/index.md b/public/content/translations/zh/developers/docs/scaling/optimistic-rollups/index.md index 771c3795bff..7096e1b6706 100644 --- a/public/content/translations/zh/developers/docs/scaling/optimistic-rollups/index.md +++ b/public/content/translations/zh/developers/docs/scaling/optimistic-rollups/index.md @@ -1,24 +1,24 @@ --- -title: 乐观卷叠 -description: 乐观卷叠简介 — 以太坊社区使用的一种扩容解决方案 +title: "乐观卷叠" +description: "乐观卷叠简介 — 以太坊社区使用的一种扩容解决方案" lang: zh --- -乐观卷叠是二层网络 (L2) 协议,该协议旨在扩展以太坊基础层的吞吐量。 它们通过在链下处理交易来减少以太坊主链上的计算量,从而显著提高处理速度。 与其他扩容解决方案(例如[侧链](/developers/docs/scaling/sidechains/))不同,乐观卷叠从主网(通过在链上发布交易结果)或从 [Plasma 链](/developers/docs/scaling/plasma/)(该链还使用欺诈证明验证以太坊上的交易,但将交易数据存储在其他地方)获取安全性。 +乐观卷叠是二层网络 (L2) 协议,该协议旨在扩展以太坊基础层的吞吐量。 它们通过在链下处理交易来减少以太坊主链上的计算量,从而显著提高处理速度。 与其他扩容解决方案(例如 [sidechains](/developers/docs/scaling/sidechains/))不同,乐观卷叠通过在链上发布交易结果从主网获取安全性,或者从 [plasma chains](/developers/docs/scaling/plasma/) 获取安全性,后者也使用欺诈证明验证以太坊上的交易,但将交易数据存储在其他地方。 -由于计算是使用以太坊时缓慢而昂贵的部分,因此乐观卷叠可以提供高达 10-100 倍的可扩展性改进。 乐观卷叠还会将交易以 `calldata` 或 [blob](/roadmap/danksharding/) 的形式写入以太坊,从而降低用户的燃料成本。 +由于计算是使用以太坊时缓慢而昂贵的部分,因此乐观卷叠可以提供高达 10-100 倍的可扩展性改进。 乐观卷叠还会将交易以 `calldata` 或在 [blobs](/roadmap/danksharding/) 中的形式写入以太坊,从而为用户降低燃料成本。 ## 前提条件 {#prerequisites} -你应该已经阅读并理解关于[以太坊扩容](/developers/docs/scaling/)和[二层网络](/layer-2/)的页面。 +你应该已经阅读并理解我们的[以太坊扩容](/developers/docs/scaling/)和[二层网络](/layer-2/)页面。 ## 什么是乐观卷叠? {#what-is-an-optimistic-rollup} -乐观卷叠是一种扩容以太坊的方法,涉及将计算和状态存储移至链下。 乐观卷叠在以太坊之外执行交易,但将交易数据以 `calldata` 或[二进制大对象](/roadmap/danksharding/)的形式发布到主网。 +乐观卷叠是一种扩容以太坊的方法,涉及将计算和状态存储移至链下。 乐观卷叠在以太坊之外执行交易,但将交易数据以 `calldata` 或 [二进制大对象](/roadmap/danksharding/) 的形式发布到主网。 乐观卷叠运营商将多个链下交易大批量捆绑在一起,然后再提交到以太坊。 这种方法可以将固定成本分散到每批中的多笔交易中,从而降低最终用户的费用。 乐观卷叠还使用压缩技术来减少发布在以太坊上的数据量。 -乐观卷叠被认为是“乐观的”,因为它们假设链下交易是有效的,并且不发布推送到链上的交易批次的有效性证明。 这一点将乐观卷叠与[零知识卷叠](/developers/docs/scaling/zk-rollups)区分开来,后者会发布链下交易的加密[有效性证明](/glossary/#validity-proof)。 +乐观卷叠被认为是“乐观的”,因为它们假设链下交易是有效的,并且不发布推送到链上的交易批次的有效性证明。 这一点将乐观卷叠与发布链下交易的加密[有效性证明](/glossary/#validity-proof)的[零知识卷叠](/developers/docs/scaling/zk-rollups)区分开来。 相反,乐观卷叠依赖于欺诈证明方案来检测交易计算不正确的情况。 在以太坊上提交卷叠批次后,有一个时间窗口(称为挑战期),在此期间任何人都可以通过计算[欺诈证明](/glossary/#fraud-proof)来挑战卷叠交易的结果。 @@ -28,17 +28,17 @@ lang: zh ## 乐观卷叠如何与以太坊交互? {#optimistic-rollups-and-Ethereum} -乐观卷叠是为了在以太坊上运行而构建的[链下扩容解决方案](/developers/docs/scaling/#off-chain-scaling)。 每个乐观卷叠都由部署在以太坊网络上的一组智能合约管理。 乐观卷叠在以太坊主链之外处理交易,但将链下交易(批量)发布到链上的卷叠合约。 和以太坊区块链一样,此交易记录是不可变的,并形成了“乐观卷叠链”。 +乐观卷叠是为在以太坊上运行而构建的[链下扩容解决方案](/developers/docs/scaling/#offchain-scaling)。 每个乐观卷叠都由部署在以太坊网络上的一组智能合约管理。 乐观卷叠在以太坊主链之外处理交易,但将链下交易(批量)发布到链上的卷叠合约。 和以太坊区块链一样,此交易记录是不可变的,并形成了“乐观卷叠链”。 乐观卷叠的架构包括以下部分: **链上合约**:乐观卷叠的操作由在以太坊上运行的智能合约控制。 这包括存储卷叠区块、监控卷叠状态更新以及跟踪用户存款的合约。 在这个意义上,以太坊充当乐观卷叠的基础层或“一层网络”。 -**链下虚拟机 (VM)**:虽然管理乐观卷叠协议的合约在以太坊上运行,但卷叠协议在[以太坊虚拟机](/developers/docs/evm/)之外的另一个虚拟机上执行计算和状态存储。 应用程序在链下虚拟机上驻留并且状态更改在其上执行;链下虚拟机作为乐观卷叠的上层或“二层网络”。 +**链下虚拟机 (VM)**:虽然管理乐观卷叠协议的合约在以太坊上运行,但该卷叠协议在[以太坊虚拟机](/developers/docs/evm/)之外的另一个虚拟机上执行计算和状态存储。 应用程序在链下虚拟机上驻留并且状态更改在其上执行;链下虚拟机作为乐观卷叠的上层或“二层网络”。 由于乐观卷叠旨在运行为以太坊虚拟机编写或编译的程序,因此链下虚拟机包含许多以太坊虚拟机设计规范。 此外,链上计算的欺诈证明允许以太坊网络强制执行在链下虚拟机中计算的状态更改的有效性。 -乐观卷叠被描述为“混合扩容解决方案”,因为虽然它们作为单独的协议存在,但它们的安全属性源自以太坊。 除了其他方面,以太坊还能保证卷叠的链下计算的正确性以及计算所依据的数据的可用性。 这使得乐观卷叠比不依赖以太坊获取安全性的纯链下扩容协议(例如,[侧链](/developers/docs/scaling/sidechains/))更安全。 +乐观卷叠被描述为“混合扩容解决方案”,因为虽然它们作为单独的协议存在,但它们的安全属性源自以太坊。 除了其他方面,以太坊还能保证卷叠的链下计算的正确性以及计算所依据的数据的可用性。 这使得乐观卷叠比不依赖以太坊获取安全性的纯链下扩容协议(例如[侧链](/developers/docs/scaling/sidechains/))更安全。 乐观卷叠在以下方面依赖于以太坊的主要协议: @@ -46,9 +46,9 @@ lang: zh 如前所述,乐观卷叠将交易数据以 `calldata` 或[二进制大对象](/roadmap/danksharding/)的形式发布到以太坊。 由于卷叠链的执行基于提交的交易,任何人都可以使用此信息(锚定在以太坊的基础层)来执行卷叠的状态并验证状态转换的正确性。 -[数据可用性](/developers/docs/data-availability/)至关重要,因为如果不能访问状态数据,挑战者就不能构造欺诈证明来质疑无效的卷叠操作。 有了以太坊提供的数据可用性,就降低了卷叠运营商逃脱恶意行为(例如,提交无效区块)的风险。 +[数据可用性](/developers/docs/data-availability/)至关重要,因为如果无法访问状态数据,挑战者就无法构建欺诈证明来对无效的卷叠操作提出异议。 有了以太坊提供的数据可用性,就降低了卷叠运营商逃脱恶意行为(例如,提交无效区块)的风险。 -### 抗审查 {#censorship-resistance} +### 抗审查性 {#censorship-resistance} 乐观卷叠也依赖以太坊来抵抗审查。 在乐观卷叠中,中心化实体(运营商)负责处理交易并将卷叠区块提交给以太坊。 这其中有一些含义: @@ -76,7 +76,7 @@ lang: zh 用户向“运营商”提交交易,“运营商”则是乐观卷叠上负责处理交易的节点。 运营商也称为“验证者”或“聚合者”,负责聚合交易、压缩底层数据,并在以太坊上发布区块。 -尽管任何人都可以成为验证者,但乐观卷叠验证者就像[权益证明系统](/developers/docs/consensus-mechanisms/pos/)一样,必须在生成区块之前提供保证金。 如果验证者发布了无效的区块或扩建了原有但无效的区块(即使他们的区块是有效的),此保证金可能被罚没。 通过这种方式,乐观卷叠利用加密经济激励措施来确保验证者诚实行事。 +尽管任何人都可以成为验证者,但乐观卷叠验证者必须在生成区块之前提供保证金,就像[权益证明系统](/developers/docs/consensus-mechanisms/pos/)一样。 如果验证者发布了无效的区块或扩建了原有但无效的区块(即使他们的区块是有效的),此保证金可能被罚没。 通过这种方式,乐观卷叠利用加密经济激励措施来确保验证者诚实行事。 乐观卷叠链上的其他验证者应该使用他们的卷叠状态副本来执行提交的交易。 如果验证者的最终状态与运营商提议的状态不同,他们可以发起挑战并计算欺诈证明。 @@ -84,17 +84,17 @@ lang: zh 排序者与常规卷叠运营商不同,因为他们对交易的排序有更大的控制力。 此外,排序者具有卷叠链的优先访问权,并且是唯一被授权向链上合约提交交易的实体。 来自非排序者节点或普通用户的交易只是在一个单独的收件箱中排队,直到排序者将它们纳入一个新批次中。 -#### 提交卷叠区块到以太坊 {#submitting-blocks-to-ethereum} +#### 将卷叠区块提交至以太坊 {#submitting-blocks-to-ethereum} 如前所述,乐观卷叠的运营商将链下交易捆绑成一个批次,并将其发送到以太坊进行公证。 此过程涉及压缩与交易相关的数据并将其以 `calldata` 或二进制大对象的形式发布在以太坊上。 -`calldata` 是智能合约中不可修改、非持久的区域,其行为与[内存](/developers/docs/smart-contracts/anatomy/#memory)非常相似。 而 `calldata` 作为区块链的[历史日志](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html?highlight=memory#logs)部分,不会存储为以太坊状态的一部分。 由于 `calldata` 不触及以太坊状态的任何部分,因此它比链上存储数据的状态更便宜。 +`calldata` 是智能合约中一个不可修改、非持久的区域,其行为与[内存](/developers/docs/smart-contracts/anatomy/#memory)非常相似。 虽然 `calldata` 作为区块链[历史日志](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html?highlight=memory#logs)的一部分持久保存在链上,但它不作为以太坊状态的一部分进行存储。 由于 `calldata` 不触及以太坊状态的任何部分,因此它比链上存储数据的状态更便宜。 `calldata` 关键字也在 Solidity 中用于在执行时将参数传递给智能合约函数。 `calldata` 识别在交易期间被调用的函数,并以任意字节序列的形式保存函数的输入。 在乐观卷叠的上下文中,`calldata` 用于将压缩的交易数据发送到链上合约。 卷叠运营商通过调用卷叠合约中所需的函数并将压缩数据作为函数参数传递来添加新批次。 使用 `calldata` 可以降低用户费用,因为卷叠产生的大部分成本来自链上存储数据。 -以下是一个卷叠批量提交的[示例](https://etherscan.io/tx/0x9102bfce17c58b5fc1c974c24b6bb7a924fb5fbd7c4cd2f675911c27422a5591),以展示此概念的工作原理。 排序者调用 `appendSequencerBatch()` 方法并使用 `calldata` 将压缩的交易数据作为输入传递。 +以下是卷叠批次提交的[一个示例](https://eth.blockscout.com/tx/0x9102bfce17c58b5fc1c974c24b6bb7a924fb5fbd7c4cd2f675911c27422a5591),用于说明这个概念的工作原理。 排序者调用 `appendSequencerBatch()` 方法,并使用 `calldata` 将压缩的交易数据作为输入进行传递。 一些卷叠现在使用二进制大对象将批量交易发布到以太坊。 @@ -102,15 +102,15 @@ lang: zh ### 状态承诺 {#state-commitments} -在任何时间点,乐观卷叠状态(帐户、余额、合约代码等)都被组织为 [Merkle 树](/whitepaper/#merkle-trees),也称为“状态树”。 此 Merkle 树的根(状态根)引用卷叠的最新状态,经过哈希处理并存储在卷叠合约中。 链上的每个状态转换都会产生一个新的卷叠状态,运营商通过计算新的状态根来提交该状态。 +在任何时间点,乐观卷叠的状态(帐户、余额、合约代码等) 被组织成一个称为“状态树”的[默克尔树](/whitepaper/#merkle-trees)。 此 Merkle 树的根(状态根)引用卷叠的最新状态,经过哈希处理并存储在卷叠合约中。 链上的每个状态转换都会产生一个新的卷叠状态,运营商通过计算新的状态根来提交该状态。 运营商在发布批次时需要同时提交旧状态根和新状态根。 如果旧状态根与链上合约中的现有状态根匹配,则后者被丢弃并替换为新状态根。 -卷叠运营商还需要为交易批次本身提交 Merkle 根。 这允许任何人通过提供 [Merkle 证明](/developers/tutorials/merkle-proofs-for-offline-data-integrity/)来证明交易包含在批次中(在 L1 上)。 +卷叠运营商还需要为交易批次本身提交 Merkle 根。 这允许任何人通过提供[默克尔证明](/developers/tutorials/merkle-proofs-for-offline-data-integrity/)来证明交易包含在批次中(在 L1 上)。 状态承诺,尤其是状态根,对于证明乐观卷叠中的状态变化的正确性是必要的。 卷叠合约在发布后立即接受来自运营商的新状态根,但稍后可以删除无效的状态根以将卷叠恢复到正确的状态。 -### 欺诈证明 {#fraud-proving} +### 欺诈证明过程 {#fraud-proving} 如前所述,乐观卷叠允许任何人在不提供有效性证明的情况下发布区块。 然而,为了确保链保持安全,乐观卷叠指定了一个时间窗口,在此期间任何人都可以对状态转换提出异议。 因此,卷叠块被称为“断言”,因为任何人都可以挑战它们的有效性。 @@ -148,31 +148,31 @@ lang: zh ### L1/L2 互操作性 {#l1-l2-interoperability} -乐观卷叠旨在与以太坊主网互操作,并允许用户在 L1 和 L2 之间传递消息和任意数据。 它们还与以太坊虚拟机兼容,因此你可以将现有的[去中心化应用程序](/developers/docs/dapps/)移植到乐观卷叠或使用以太坊开发工具创建新的去中心化应用程序。 +乐观卷叠旨在与以太坊主网互操作,并允许用户在 L1 和 L2 之间传递消息和任意数据。 它们还与 EVM 兼容,因此你可以将现有的[去中心化应用程序](/developers/docs/dapps/)移植到乐观卷叠,或使用以太坊开发工具创建新的去中心化应用程序。 -#### 1. 资产转移 {#asset-movement} +#### 1. 资产移动 {#asset-movement} ##### 进入卷叠 -为了使用乐观卷叠,用户将以太币、ERC-20 代币和其他可接受的资产存入 L1 上卷叠的[链桥](/developers/docs/bridges/)合约中。 链桥合约会将交易中继到 L2,在那里铸造等量的资产并发送到用户在乐观卷叠中选择的地址。 +要使用乐观卷叠,用户需要将 ETH、ERC-20 代币和其他接受的资产存入 L1 上的卷叠[链桥](/developers/docs/bridges/)合约中。 链桥合约会将交易中继到 L2,在那里铸造等量的资产并发送到用户在乐观卷叠中选择的地址。 -用户生成的交易(如 L1 > L2 存款)通常会排队,直到排序者将它们重新提交到卷叠合约。 但是,为了保持抗审查能力,如果交易延迟超过允许的最大时间,乐观卷叠允许用户直接向链上卷叠合约提交交易。 +用户生成的交易(如 L1 > L2 存款)通常会排队,直到排序者将其重新提交到卷叠合约。 但是,为了保持抗审查能力,如果交易延迟超过允许的最大时间,乐观卷叠允许用户直接向链上卷叠合约提交交易。 一些乐观卷叠采用更直接的方法来防止排序者审查用户。 在这里,一个区块由自前一个区块以来提交给 L1 合约的所有交易(例如存款)以及卷叠链上已处理的交易共同定义。 如果排序者忽略 L1交易,它将发布(可证明)错误的状态根;因此,一旦用户生成的消息被发布在 L1 上,排序者就不能将其延迟。 ##### 退出卷叠 -由于欺诈证明方案,从乐观卷叠中取款到以太坊更加困难。 如果用户发起一个 L2 > L1 交易以提取在 L1 上托管的资金,他们必须等到挑战期(大约持续 7 天)过去。 然而,退出过程本身相当简单。 +由于欺诈证明方案,从乐观卷叠中取款到以太坊更加困难。 如果用户发起 L2 > L1 交易来提取在 L1 上托管的资金,他们必须等到大约七天的挑战期结束。 然而,退出过程本身相当简单。 在 L2 卷叠上发起取款请求后,该交易被纳入下一批,同时用户在卷叠上的资产被销毁。 一旦批次在以太坊上发布,用户就可以计算一个 Merkle 证明来验证他们的退出交易是否包含在区块中。 然后便是等待延迟期过后完成 L1 上的交易并将资金提取到主网的问题了。 -为了避免在向以太坊取款前等待一周,乐观卷叠用户可以聘请**流动性提供者** (LP)。 流动性提供者承担待处理的 L2 取款的所有权,并在 L1 上向用户付款(以换取费用)。 +为避免在向以太坊提取资金前等待一周,乐观卷叠用户可以采用**流动性提供者** (LP)。 流动性提供者承担待处理的 L2 取款的所有权,并在 L1 上向用户付款(以换取费用)。 流动性提供者可以在释放资金之前检查用户取款请求的有效性(通过自行执行链)。 这样他们就可以保证交易最终会得到确认(即,去信任确定性)。 -#### 2. 以太坊虚拟机兼容性 {#evm-compatibility} +#### 2. EVM 兼容性 {#evm-compatibility} -对于开发者而言,乐观卷叠的优势在于它们与[以太坊虚拟机 (EVM)](/developers/docs/evm/) 的兼容性(或者更好的是,等效性)。 与以太坊虚拟机兼容的卷叠符合[以太坊黄皮书](https://ethereum.github.io/yellowpaper/paper.pdf)中的规范,并在字节码级别支持以太坊虚拟机。 +对于开发者而言,乐观卷叠的优势在于它们与[以太坊虚拟机 (EVM)](/developers/docs/evm/) 的兼容性,或者更确切地说,等效性。 与 EVM 兼容的卷叠符合[以太坊黄皮书](https://ethereum.github.io/yellowpaper/paper.pdf)中的规范,并在字节码级别支持 EVM。 乐观卷叠中的以太坊虚拟机兼容性具有以下好处: @@ -190,50 +190,50 @@ ii. 使用乐观卷叠的开发者和项目团队可以利用以太坊的基础 一个跨链合约调用的例子是前文所述的代币存款。 L1 上的合约托管用户的代币,并向配对的 L2 合约发送消息,以在卷叠中铸造等量的代币。 -由于跨链消息调用会导致合约执行,因此发送者通常需要支付用于计算的[燃料成本](/developers/docs/gas/)。 建议设置较高的燃料限制,以防止交易在目标链上失败。 代币桥梁场景就是一个很好的例子;如果交易的 L1 端(存入代币)有效,但 L2 端(铸造新代币)由于燃料不足而失败,则存款将无法收回。 +由于跨链消息调用会导致合约执行,因此发送方通常需要支付计算的[燃料成本](/developers/docs/gas/)。 建议设置较高的燃料限制,以防止交易在目标链上失败。 代币桥梁场景就是一个很好的例子;如果交易的 L1 端(存入代币)有效,但 L2 端(铸造新代币)由于燃料不足而失败,则存款将无法收回。 -最后,我们应该注意到,合约之间的 L2 > L1 消息调用需要考虑延迟(L1 > L2 调用通常在几分钟后执行)。 这是因为从乐观卷叠发送到主网的消息在挑战窗口到期之前无法执行。 +最后,我们应该注意,合约之间的 L2 > L1 消息调用需要考虑延迟(L1 > L2 调用通常在几分钟后执行)。 这是因为从乐观卷叠发送到主网的消息在挑战窗口到期之前无法执行。 ## 乐观卷叠费用如何运作? {#how-do-optimistic-rollup-fees-work} -乐观卷叠使用类似于以太坊的燃料费方案来表示用户为每笔交易支付的费用。 乐观卷叠收取的费用取决于以下组成部分: +乐观卷叠使用类似于以太坊的燃料费方案来表示用户为每笔交易支付的费用。 乐观卷叠收取的费用取决于以下几个部分: -1. **状态写入**:乐观卷叠将交易数据和区块头(由前一个区块头哈希、状态根、批处理根组成)作为 `blob`,即二进制大对象,发布到以太坊。 [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) 引入了在链上纳入数据的高成本效益解决方案。 `blob` 是一个允许卷叠将压缩状态的转换数据发布到以太坊一层网络的新交易字段。 与永驻链上的 `calldata` 不同,二进制大对象的生命周期很短,在 [4096 个时段](https://github.com/ethereum/consensus-specs/blob/81f3ea8322aff6b9fb15132d050f8f98b16bdba4/configs/mainnet.yaml#L147)(大约 18 天)后即可从客户端删除。 通过使用二进制大对象发布批量压缩交易,乐观卷叠可以大幅降低向一层网络写入交易的成本。 +1. **状态写入**:乐观卷叠将交易数据和区块头(由前一个区块头的哈希、状态根、批处理根组成)作为 `blob`(即“二进制大对象”)发布到以太坊。 [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) 引入了一种在链上包含数据且经济高效的解决方案。 `blob` 是一个新的交易字段,允许卷叠将压缩的状态转换数据发布到以太坊 L1。 与永久保留在链上的 `calldata` 不同,blob 是短暂存在的,并且可以在 [4096 个时段](https://github.com/ethereum/consensus-specs/blob/81f3ea8322aff6b9fb15132d050f8f98b16bdba4/configs/mainnet.yaml#L147)(约 18 天)后从客户端中修剪。 通过使用二进制大对象发布批量压缩交易,乐观卷叠可以大幅降低向一层网络写入交易的成本。 -2. **使用的二进制大对象燃料**:二进制大对象携带的交易采用类似于 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 中引入的动态费用机制。 第三类型交易的燃料费考虑了二进制大对象的基础费,后者由网络根据二进制大对象空间需求和所发送交易的二进制大对象空间使用情况来决定。 +2. **使用的二进制大对象燃料**:携带二进制大对象的交易采用一种类似于 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 引入的动态费用机制。 第三类型交易的燃料费考虑了二进制大对象的基础费,后者由网络根据二进制大对象空间需求和所发送交易的二进制大对象空间使用情况来决定。 -3. **二层网络运营商费用**:这是支付给卷叠节点的金额,用来补偿处理交易时产生的计算成本,很像以太坊上的燃料费用。 由于二层网络处理能力更强,并且不会出现网络拥塞迫使以太坊上的验证者优先处理费用更高的交易,卷叠节点收取的交易费更低。 +3. **L2 运营商费用**:这是支付给卷叠节点的金额,作为处理交易所产生计算成本的补偿,与以太坊上的燃料费非常相似。 由于二层网络处理能力更强,并且不会出现网络拥塞迫使以太坊上的验证者优先处理费用更高的交易,卷叠节点收取的交易费更低。 -乐观卷叠应用了多种机制来降低用户的费用,包括批量交易和压缩 `calldata` 以降低数据发布成本。 你可以查看 [L2 费用跟踪器](https://l2fees.info/),实时了解使用基于以太坊的乐观卷叠的成本。 +乐观卷叠采用多种机制为用户降低费用,包括对交易进行批处理和压缩 `calldata` 来降低数据发布成本。 你可以查看 [L2 费用跟踪器](https://l2fees.info/),实时了解使用基于以太坊的乐观卷叠需要多少成本。 ## 乐观卷叠如何扩容以太坊? {#scaling-ethereum-with-optimistic-rollups} 如前所述,乐观卷叠在以太坊上发布压缩的交易数据以保证数据可用性。 压缩链上发布的数据的能力对于通过乐观卷叠扩容以太坊的吞吐量至关重要。 -以太坊主链限制了区块可以容纳的数据量,以燃料单位计量([平均区块大小](/developers/docs/blocks/#block-size)为 1500 万燃料)。 虽然这限制了每笔交易可以使用多少燃料,但也意味着我们可以通过减少与交易相关的数据来增加每个区块处理的交易,直接提高了可扩展性。 +以太坊主链对区块可容纳的数据量设置了限制,以燃料为单位([平均区块大小](/developers/docs/blocks/#block-size)为 1500 万燃料)。 虽然这限制了每笔交易可以使用多少燃料,但也意味着我们可以通过减少与交易相关的数据来增加每个区块处理的交易,直接提高了可扩展性。 -乐观卷叠使用多种技术来实现交易数据压缩并提高每秒交易量速率。 例如,这篇[文章](https://vitalik.eth.limo/general/2021/01/05/rollup.html)将基本用户交易(发送以太币)在主网上生成的数据量与相同交易在卷叠上生成的数据量进行了比较: +乐观卷叠使用多种技术来实现交易数据压缩并提高每秒交易量速率。 例如,这篇[文章](https://vitalik.eth.limo/general/2021/01/05/rollup.html)比较了一笔基本用户交易(发送以太币)在主网上生成的数据与同一笔交易在卷叠上生成的数据: -| 参数 | 以太坊 (L1) | 卷叠 (L2) | -| --------- | ----------------- | ---------- | -| Nonce | ~3 | 0 | -| Gasprice | ~8 | 0-0.5 | -| Gas | 3 | 0-0.5 | -| To | 21 | 4 | -| Value | 9 | ~3 | -| Signature | ~68 (2 + 33 + 33) | ~0.5 | -| From | 0(从签名中恢复) | 4 | -| **总计** | **~112 字节** | **~12 字节** | +| 参数 | 以太坊 (L1) | 卷叠 (L2) | +| -------- | ---------------------------------------------------- | ------------------------------------ | +| Nonce | ~3 | 0 | +| Gasprice | ~8 | 0-0.5 | +| 燃料 | 3 | 0-0.5 | +| To | 21 | 4 | +| Value | 9 | ~3 | +| 签名 | ~68 (2 + 33 + 33) | ~0.5 | +| From | 0(从签名中恢复) | 4 | +| **总计** | **~112 字节** | **~12 字节** | 对这些数字进行一些粗略的计算有助于显示乐观卷叠提供的可扩展性改进: -1. 每个区块的目标大小是 1500 万燃料,验证一个字节的数据需要 16 个燃料。 将平均区块大小除以 16 燃料(15,000,000/16),表明一般区块可以容纳 **937,500 字节的数据**。 -2. 如果一个基本卷叠交易使用 12 个字节,那么以太坊区块平均可以处理 **78,125 个卷叠交易** (937,5000/12) 或 **39 个卷叠批次**(如果每个批次平均包含 2,000 个交易)。 -3. 如果每 15 秒在以太坊上产生一个新区块,那么卷叠的处理速度将大致达到**每秒 5,208 次交易**。 这是通过将以太坊区块可以容纳的基本卷叠交易数量 (**78,125**) 除以平均区块时间 (**15 秒**) 得出的。 +1. 每个区块的目标大小是 1500 万燃料,验证一个字节的数据需要 16 个燃料。 将平均区块大小除以 16 燃料 (15,000,000/16),结果表明平均一个区块可以容纳 **937,500 字节的数据**。 +2. 如果一笔基本的卷叠交易使用 12 字节,那么一个普通的以太坊区块可以处理 **78,125 笔卷叠交易** (937,500/12) 或 **39 个卷叠批次**(如果每个批次平均包含 2,000 笔交易)。 +3. 如果以太坊每 15 秒产生一个新区块,那么该卷叠的处理速度大约为**每秒 5,208 笔交易**。 这是通过将一个以太坊区块可以容纳的基本卷叠交易数量(**78,125**)除以平均出块时间(**15 秒**)计算得出的。 -这是一个比较乐观的估计,因为乐观卷叠交易不可能包含以太坊上的整个区块。 但是,它可以大致了解乐观卷叠可以为以太坊用户提供多少可扩展性收益(当前实现可提供高达 2,000 交易每秒的速率)。 +这是一个比较乐观的估计,因为乐观卷叠交易不可能包含以太坊上的整个区块。 然而,这可以让我们大致了解乐观卷叠能为以太坊用户带来多大的可扩展性收益(目前的实现方案最高可达 2,000 TPS)。 -在以太坊上引入[数据分片](/roadmap/danksharding/)有望提高乐观卷叠的可扩展性。 由于卷叠交易必须与其他非卷叠交易共享区块空间,因此它们的处理能力受到以太坊主链上的数据吞吐量的限制。 Danksharding 使用更经济的非永久型“二进制大对象”存储,而弃用昂贵的永久型 `CALLDATA`,这将增加二层网络链上用于发布每个区块中数据的空间。 +在以太坊上引入[数据分片](/roadmap/danksharding/)有望提高乐观卷叠的可扩展性。 由于卷叠交易必须与其他非卷叠交易共享区块空间,因此它们的处理能力受到以太坊主链上的数据吞吐量的限制。 Danksharding 将增加 L2 链每个区块可用于发布数据的空间,它使用更便宜、非永久性的“blob”存储,而不是昂贵、永久性的 `CALLDATA`。 ### 乐观卷叠的优缺点 {#optimistic-rollups-pros-and-cons} @@ -247,7 +247,7 @@ ii. 使用乐观卷叠的开发者和项目团队可以利用以太坊的基础 | 乐观卷叠依赖于精心设计的加密经济激励措施来提高链上的安全性。 | 卷叠必须在链上发布所有交易数据,这会增加成本。 | | 与以太坊虚拟机和 Solidity 的兼容性允许开发者将以太坊原生智能合约移植到卷叠或使用现有工具来创建新的去中心化应用程序。 | | -### 乐观卷叠的直观解释 {#optimistic-video} +### 乐观卷叠的视频解说 {#optimistic-video} 更愿意通过视频学习? 观看 Finematics 解说乐观卷叠: @@ -255,9 +255,11 @@ ii. 使用乐观卷叠的开发者和项目团队可以利用以太坊的基础 ## 阅读关于乐观卷叠的更多信息 -- [乐观卷叠如何工作(完整指南)](https://www.alchemy.com/overviews/optimistic-rollups) +- [乐观卷叠如何运作(完整指南)](https://www.alchemy.com/overviews/optimistic-rollups) - [什么是区块链卷叠? 技术介绍](https://www.ethereum-ecosystem.com/blog/what-is-a-blockchain-rollup-a-technical-introduction) -- [Arbitrum 基本指南](https://www.bankless.com/the-essential-guide-to-arbitrum) -- [乐观卷叠究竟如何工作?](https://www.paradigm.xyz/2021/01/how-does-optimism-s-rollup-really-work) -- [深入研究乐观虚拟机](https://medium.com/ethereum-optimism/ovm-deep-dive-a300d1085f52) +- [Arbitrum 基础指南](https://www.bankless.com/the-essential-guide-to-arbitrum) +- [以太坊卷叠实用指南](https://web.archive.org/web/20241108192208/https://research.2077.xyz/the-practical-guide-to-ethereum-rollups) +- [以太坊 L2 欺诈证明的现状](https://web.archive.org/web/20241124154627/https://research.2077.xyz/the-state-of-fraud-proofs-in-ethereum-l2s) +- [Optimism 的卷叠到底是如何运作的?](https://www.paradigm.xyz/2021/01/how-does-optimism-s-rollup-really-work) +- [OVM 深度解析](https://medium.com/ethereum-optimism/ovm-deep-dive-a300d1085f52) - [什么是乐观虚拟机?](https://www.alchemy.com/overviews/optimistic-virtual-machine) diff --git a/public/content/translations/zh/developers/docs/scaling/plasma/index.md b/public/content/translations/zh/developers/docs/scaling/plasma/index.md index d4666ae981d..52ac1fbe465 100644 --- a/public/content/translations/zh/developers/docs/scaling/plasma/index.md +++ b/public/content/translations/zh/developers/docs/scaling/plasma/index.md @@ -1,12 +1,12 @@ --- -title: Plasma 链 -description: 这是一篇来源于以太坊社区的关于使用 plasma 来实现扩容解决方案的介绍文章 +title: "Plasma 链" +description: "这是一篇来源于以太坊社区的关于使用 plasma 来实现扩容解决方案的介绍文章" lang: zh incomplete: true sidebarDepth: 3 --- -Plasma 链是一个锚定到以太坊主网的独立区块链,但却在链下执行交易,有自己的区块验证机制。 Plasma 链有时被称作“子”链,其本质是以太坊主网的较小副本。 Plasma 链使用[欺诈证明](/glossary/#fraud-proof)(如[乐观卷叠](/developers/docs/scaling/optimistic-rollups/))来仲裁争议。 +Plasma 链是一个锚定到以太坊主网的独立区块链,但却在链下执行交易,而且有自己的区块验证机制。 Plasma 链有时被称作“子”链,其本质是以太坊主网的较小副本。 Plasma 链使用[欺诈证明](/glossary/#fraud-proof)(类似于[乐观卷叠](/developers/docs/scaling/optimistic-rollups/))来裁决争议。 利用 Merkle 树可以创建这些链的无限堆栈,可以从父链(包括以太坊主网)分流带宽。 然而,虽然这些链从以太坊获取一些安全性(通过欺诈证明),但其安全性和效率受到若干设计限制的影响。 @@ -16,17 +16,17 @@ Plasma 链是一个锚定到以太坊主网的独立区块链,但却在链下 ## 什么是 Plasma? -Plasma 是一个用于改善以太坊这类公共区块链的可扩展性的框架。 正如原 [Plasma 白皮书](http://plasma.io/plasma.pdf)中所述,Plasma 链是在另一个区块链之上构建的,该区块链被称为“根链”。 每个“子链”都从根链延伸而来,通常由部署在母链上的智能合约进行管理。 +Plasma 是一个用于改善以太坊这类公共区块链的可扩展性的框架。 正如最初的 [Plasma 白皮书](http://plasma.io/plasma.pdf) 所述,Plasma 链构建于另一个区块链(称为“根链”)之上。 每个“子链”都从根链延伸而来,通常由部署在母链上的智能合约进行管理。 -Plasma 合约除了其他功能之外,还有一项功能是作为[链梁](/developers/docs/bridges/),让用户可以在以太坊主网和 plasma 链之间转移资产。 虽然这使它们类似于[侧链](/developers/docs/scaling/sidechains/),但 plasma 链至少在某种程度上受益于以太坊主网的安全性。 这一点不同于单独负责其安全性的侧链。 +Plasma 合约的功能之一是作为[链桥](/developers/docs/bridges/),允许用户在以太坊主网和 Plasma 链之间转移资产。 虽然这使它们类似于[侧链](/developers/docs/scaling/sidechains/),但 Plasma 链至少在某种程度上受益于以太坊主网的安全性。 这一点不同于单独负责其安全性的侧链。 ## Plasma 如何工作? Plasma 框架的基本组成部分包括: -### 链下计算 {#off-chain-computation} +### 脱链计算 {#offchain-computation} -以太坊的当前处理速度限制为每秒 ~15-20 个交易,降低了短期内处理更多用户的扩容可能性。 这个问题之所以存在,主要是因为以太坊的[共识机制](/developers/docs/consensus-mechanisms/) 需要许多对等节点来验证对区块链状态的每次更新。 +以太坊的当前处理速度限制为每秒 ~15-20 个交易,降低了短期内处理更多用户的扩容可能性。 这个问题之所以存在,主要是因为以太坊的[共识机制](/developers/docs/consensus-mechanisms/)需要许多对等节点来验证对区块链状态的每次更新。 尽管以太坊的共识机制对于安全性来说是必要的,但它可能并不适用于所有用例。 例如,由于双方之间存在某种信任,Alice 可能不需要每天向 Bob 支付一杯由整个以太坊网络验证的咖啡。 @@ -38,23 +38,23 @@ Plasma 假设以太坊主网不需要验证所有交易。 相反,我们可以 虽然 Plasma 在链下执行交易,但它们是在以太坊主执行层上结算的,否则,Plasma 链无法从以太坊的安全保证中受益。 但是在不知道 Plasma 链状态的情况下完成链下交易会破坏安全模型并让无效交易扩散。 这就是为什么运营商,即负责在 Plasma 链上生产区块的实体,需要定期在以太坊上发布“状态承诺”。 -[承诺方案](https://en.wikipedia.org/wiki/Commitment_scheme)是一种加密技术,用于承诺价值或声明而不向另一方透露。 承诺是“有约束力的”,因为一旦你承诺了,就不能改变价值或声明。 Plasma 中的状态承诺采用“Merkle 根”的形式(源自 [Merkle 树](/whitepaper/#merkle-trees)),运营商每隔一段时间将其发送到以太坊链上的 Plasma 合约。 +[承诺方案](https://en.wikipedia.org/wiki/Commitment_scheme)是一种加密技术,用于承诺某个值或声明,而无需向另一方披露。 承诺是“有约束力的”,因为一旦你承诺了,就不能改变价值或声明。 Plasma 中的状态承诺采用“默克尔根”(源自[默克尔树](/whitepaper/#merkle-trees))的形式,运营商会定期将其发送到以太坊链上的 Plasma 合约。 -Merkle 根是能够压缩大量信息的密码原语。 Merkle 根(在此情况下也称为“区块根”)可以代表区块中的所有交易。 Merkle 根还可以更容易地验证一小部分数据是否是较大数据集的一部分。 例如,用户可以生成 [Merkle 证明](/developers/tutorials/merkle-proofs-for-offline-data-integrity/#main-content)来证明交易包含在特定的区块中。 +Merkle 根是能够压缩大量信息的密码原语。 Merkle 根(在此情况下也称为“区块根”)可以代表区块中的所有交易。 Merkle 根还可以更容易地验证一小部分数据是否是较大数据集的一部分。 例如,用户可以生成[默克尔证明](/developers/tutorials/merkle-proofs-for-offline-data-integrity/#main-content),以证明特定区块中包含某笔交易。 -Merkle 根对于向以太坊提供有关链下状态的信息非常重要。 你可以将 Merkle 根视为“保存点”:运营商表示,“这是 Plasma 链在 x 时间点的状态,这是 Merkle 根作为证明。” 运营商使用 Merkle 根对 Plasma 链的_当前状态_进行承诺,这就是为什么它被称为“状态承诺”。 +Merkle 根对于向以太坊提供有关链下状态的信息非常重要。 你可以将 Merkle 根视为“保存点”:运营商表示,“这是 Plasma 链在 x 时间点的状态,这是 Merkle 根作为证明。” 运营商使用默克尔根对 Plasma 链的_当前状态_进行承诺,这就是它被称为“状态承诺”的原因。 -### 入口和出口 {#entries-and-exits} +### 进入和退出 {#entries-and-exits} 为了让以太坊用户利用 Plasma,需要有一种机制在主网和 Plasma 链之间转移资金。 但是,我们不能随意将以太币发送到 Plasma 链上的地址 — 这些链是不兼容的,因此交易要么失败,要么导致资金损失。 Plasma 使用在以太坊上运行的主合约来处理用户的入口和出口。 该主合约还负责跟踪状态承诺(前面已解释)并通过欺诈证明惩罚不诚实行为(稍后将详细介绍)。 -#### 进入 plasma 链 {#entering-the-plasma-chain} +#### 进入 Plasma 链 {#entering-the-plasma-chain} 要进入 Plasma 链,Alice(用户)必须在 Plasma 合约中存入以太币或任何 ERC-20 代币。 监视合约存款的 Plasma 运营商重新创建与 Alice 的初始存款相等的金额,并将其释放到她在 Plasma 链上的地址。 Alice 需要证明在子链上收到资金,然后才能使用这些资金进行交易。 -#### 退出 plasma 链 {#exiting-the-plasma-chain} +#### 退出 Plasma 链 {#exiting-the-plasma-chain} 由于几个原因,退出 plasma 链比进入它更复杂。 最大的问题是,虽然以太坊有关于 Plasma 链状态的信息,但它无法验证信息是否真实。 恶意用户可能会做出不正确的断言(“我有 1000 个以太币”)并提供虚假证据来支持该声明而侥幸逃脱。 @@ -62,9 +62,9 @@ Plasma 使用在以太坊上运行的主合约来处理用户的入口和出口 但是,通常情况下,用户是诚实的,并对他们拥有的资金做出正确的声明。 在这种情况下,Alice 将通过向 Plasma 合约提交交易,在根链(以太坊)上发起取款请求。 -她还必须提供 Merkle 证明,验证在 Plasma 链上创建她的资金的交易是否包含在区块中。 这对于 Plasma 的迭代是必要的,例如[最小可行 Plasma](https://www.learnplasma.org/en/learn/mvp.html) 使用[未花费的交易输出 (UTXO)](https://en.wikipedia.org/wiki/Unspent_transaction_output) 模型。 +她还必须提供 Merkle 证明,验证在 Plasma 链上创建她的资金的交易是否包含在区块中。 对于 Plasma 的迭代(例如使用[未使用交易输出 (UTXO)](https://en.wikipedia.org/wiki/Unspent_transaction_output) 模型的 [Plasma MVP](https://www.learnplasma.org/en/learn/mvp.html)),这是必需的。 -其他的,如 [Plasma Cash](https://www.learnplasma.org/en/learn/cash.html),将资金表示为[非同质化代币](/developers/docs/standards/tokens/erc-721/),而不是未花费的交易输出。 在这种情况下,取款需要证明 Plasma 链上代币的所有权。 这是通过提交涉及代币的两个最新交易并提供 Merkle 证明来验证这些交易是否包含在区块中来完成的。 +其他迭代(例如 [Plasma Cash](https://www.learnplasma.org/en/learn/cash.html))则将资金表示为[非同质化代币](/developers/docs/standards/tokens/erc-721/),而不是 UTXO。 在这种情况下,取款需要证明 Plasma 链上代币的所有权。 这是通过提交涉及代币的两个最新交易并提供 Merkle 证明来验证这些交易是否包含在区块中来完成的。 用户还必须在取款请求中添加保证金,作为诚实行为的保证。 如果挑战者证明 Alice 的取款请求无效,她的保证金将被罚没,其中一部分作为奖励交给挑战者。 @@ -72,7 +72,7 @@ Plasma 使用在以太坊上运行的主合约来处理用户的入口和出口 ### 争议仲裁 {#dispute-arbitration} -与任何区块链一样,Plasma 链需要一种机制确保交易的完整性,防止参与者的恶意行为(例如,资金双重支付)。 为此,plasma 链使用欺诈证明来仲裁有关状态转换有效性的争议并惩罚不良行为。 欺诈证明可作为一种机制,Plasma 子链通过它向父链或根链提出申诉。 +与任何区块链一样,Plasma 链需要一种机制来保障交易的完整性,以防参与者恶意行事(例如,双重支付资金)。 为此,plasma 链使用欺诈证明来仲裁有关状态转换有效性的争议并惩罚不良行为。 欺诈证明可作为一种机制,Plasma 子链通过它向父链或根链提出申诉。 欺诈证明只是声称特定状态转换无效。 例如,如果用户 (Alice) 尝试两次花费相同的资金。 也许她在与 Bob 的交易中花费了未花费的交易输出,并希望在另一笔交易中花费相同的未花费的交易输出(现在是 Bob 的)。 @@ -80,17 +80,17 @@ Plasma 使用在以太坊上运行的主合约来处理用户的入口和出口 如果 Bob 挑战成功,Alice 的取款请求将被取消。 但是,这种方法依赖于 Bob 监视链中取款请求的能力。 如果 Bob 离线,那么一旦挑战期过去,Alice 就可以处理恶意取款。 -## plasma 中的大规模退出问题 {#the-mass-exit-problem-in-plasma} +## Plasma 中的大规模退出问题 {#the-mass-exit-problem-in-plasma} -当大量用户试图同时退出 Plasma 链时,就会出现大规模退出问题。 为什么会出现这个问题与 Plasma 的最大问题之一有关:**数据不可用**。 +当大量用户试图同时退出 Plasma 链时,就会出现大规模退出问题。 之所以存在这个问题,是因为 Plasma 最大的问题之一:**数据不可用**。 数据可用性是验证提议区块的信息是否实际发布在区块链网络上的能力。 如果生产者自己发布区块但保留用于创建区块的数据,则该区块是“不可用的”。 -如果节点要能够下载区块并验证交易的有效性,区块必须是可用的。 区块链通过强制区块生产者在链上发布所有交易数据来确保数据可用性。 +如果节点要能够下载区块并验证交易的有效性,区块必须是可用的。 区块链通过强制区块生产者在链上发布所有交易数据来确保数据可用。 数据可用性还有助于保护建立在以太坊基础层之上的链下扩容协议。 通过强制这些链上的运营商在以太坊上发布交易数据,任何人都可以通过构建引用正确链状态的欺诈证明来挑战无效区块。 -Plasma 链主要存储与运营商的交易数据,**不在主网上发布任何数据**(即,除了定期状态承诺之外)。 这意味着如果用户需要创建欺诈证明来挑战无效交易,他们必须依靠运营商提供区块数据。 如果该系统有效,则用户始终可以使用欺诈证明来保护资金。 +Plasma 链主要将交易数据存储在运营商处,**并且不会在主网上发布任何数据**(除了定期的状态承诺)。 这意味着如果用户需要创建欺诈证明来挑战无效交易,他们必须依靠运营商提供区块数据。 如果该系统有效,则用户始终可以使用欺诈证明来保护资金。 当运营商(而不仅仅是任何用户)是恶意行为的一方时,问题就开始了。 由于运营商完全控制区块链,他们更有动力更大规模地推进无效状态转换,例如窃取 Plasma 链上属于用户的资金。 @@ -98,7 +98,7 @@ Plasma 链主要存储与运营商的交易数据,**不在主网上发布任 因此,最乐观的解决方案是尝试从 Plasma 链上“大规模退出”用户。 大规模退出减缓了恶意运营商窃取资金的计划,并为用户提供了一定程度的保护。 取款请求根据每个未花费的交易输出(或代币)的创建时间排序,防止恶意运营商抢先运行诚实用户。 -尽管如此,我们仍然需要一种方法来验证大规模退出期间取款请求的有效性,以防止机会主义个人在处理无效退出的混乱中获利。 解决方案很简单:要求用户发布**链的最后一个有效状态**,以退出他们的资金。 +尽管如此,我们仍然需要一种方法来验证大规模退出期间取款请求的有效性,以防止机会主义个人在处理无效退出的混乱中获利。 解决方案很简单:要求用户发布最后一个**有效的链上状态**以提取他们的资金。 但是这种方法仍然存在问题。 例如,如果 plasma 链上的所有用户都需要退出(在恶意运营商的情况下是可能的),那么 plasma 链的整个有效状态必须立即转储到以太坊的基础层。 由于 Plasma 链的任意大小(高吞吐量 = 更多数据)和以太坊处理速度的限制,这不是一个理想的解决方案。 @@ -114,21 +114,21 @@ Plasma 链主要存储与运营商的交易数据,**不在主网上发布任 | 通过将计算和存储转移到链下来减少以太坊主网的负载。 | 为了等待挑战期,提款会延迟几天。 对于同质化资产,流动性提供者可以缓解这种情况,但存在相关的资本成本。 | | | 如果太多用户同时尝试退出,可能会导致以太坊主网堵塞。 | -## Plasma 与第 2 层网络扩容协议 {#plasma-vs-layer-2} +## Plasma 与二层网络扩容协议 {#plasma-vs-layer-2} -虽然 Plasma 曾被视为对以太坊有用的扩容解决方案,但后来它被弃用,取而代之的是[二层网络 (L2) 扩容协议](/layer-2/)。 二层网络扩容解决方案解决了 Plasma 的几个问题: +虽然 Plasma 曾被认为是以太坊有用的扩容解决方案,但后来被弃用,转而支持[二层 (L2) 扩容协议](/layer-2/)。 二层网络扩容解决方案解决了 Plasma 的几个问题: ### 效率 {#efficiency} -[零知识卷叠](/developers/docs/scaling/zk-rollups)为在链下处理的每批交易的有效性生成加密证明。 这样可以防止用户(和运营商)推进的无效状态转换,因而不再需要挑战期和退出游戏。 这也意味着用户不必通过定期关注链来保护其资金安全。 +[零知识卷叠](/developers/docs/scaling/zk-rollups)会为每批脱链处理的交易生成有效性加密证明。 这样可以防止用户(和运营商)推进的无效状态转换,因而不再需要挑战期和退出游戏。 这也意味着用户不必通过定期关注链来保护其资金安全。 -### 支持智能合约 {#support-for-smart-contracts} +### 对智能合约的支持 {#support-for-smart-contracts} Plasma 框架的另一个问题是[无法支持以太坊智能合约的执行](https://ethresear.ch/t/why-smart-contracts-are-not-feasible-on-plasma/2598/4)。 因此,Plasma 的大多数实现主要是用于简单的支付或 ERC-20 代币交换。 -相反,乐观卷叠与[以太坊虚拟机](/developers/docs/evm/)兼容,并且可以运行以太坊原生[智能合约](/developers/docs/smart-contracts/),使其成为扩展[去中心化应用程序](/developers/docs/dapps/)的有用且_安全_的解决方案。 同样,正在计划[创建以太坊虚拟机的零知识实现 (zkEVM)](https://ethresear.ch/t/a-zk-evm-specification/11549),让零知识卷叠能够处理任意逻辑并执行智能合约。 +相反,乐观卷叠与[以太坊虚拟机](/developers/docs/evm/)兼容,可以运行以太坊原生[智能合约](/developers/docs/smart-contracts/),使其成为扩容[去中心化应用程序](/developers/docs/dapps/)的一个有用且_安全_的解决方案。 同样,目前正在计划[创建 EVM 的零知识实现 (zkEVM)](https://ethresear.ch/t/a-zk-evm-specification/11549),这将允许 ZK-rollups 处理任意逻辑并执行智能合约。 -### 数据不可用 {#data-unavailability} +### 数据不可用性 {#data-unavailability} 如前所述,Plasma 存在数据可用性问题。 如果恶意运营商在 Plasma 链上推进了无效转换,用户将无法挑战它,因为运营商可以扣留创建欺诈证明所需的数据。 卷叠强制运营商在以太坊上发布交易数据,允许任何人验证链的状态并在必要时创建欺诈证明,从而解决了这个问题。 @@ -144,7 +144,8 @@ Plasma、侧链、分片技术有一定的相似度,因为它们都以某种 ### Plasma 与侧链 {#plasma-vs-sidechains} -[侧链](/developers/docs/scaling/sidechains/)是一条独立运行的区块链,通过双向桥梁连接到以太坊主网。 [桥梁](/bridges/)允许用户在两条区块链之间兑换代币以便在侧链进行交易,这缓解了以太坊主网上的拥塞并提升了可扩展性。 侧链采用独立的共识机制,它们通常比以太坊主网小得多。 因此,将资产桥接到这些区块链会增加风险;由于侧链模型中缺少从以太坊主网继承的安全保障,在侧链受到攻击时用户会面临资金损失的风险。 +[侧链](/developers/docs/scaling/sidechains/)是独立运行的区块链,通过双向链桥连接到以太坊主网。 [链桥](/bridges/)允许用户在两个区块链之间交换代币,以便在侧链上进行交易,从而减少以太坊主网的拥堵并提高可扩展性。 +侧链采用独立的共识机制,它们通常比以太坊主网小得多。 因此,将资产桥接到这些区块链会增加风险;由于侧链模型中缺少从以太坊主网继承的安全保障,在侧链受到攻击时用户会面临资金损失的风险。 相反,Plasma 链的安全性源自以太坊主网。 这让它们明显比侧链更安全。 侧链和 Plasma 链都可以采用不同的共识协议。但区别是 Plasma 链在以太坊主网上发布每个区块的默克尔根。 区块根是小段信息,可用来验证在 Plasma 链上进行的交易相关信息。 如果 Plasma 链遭到攻击,用户可以用适当的证据安全地将资金撤回到主网。 @@ -156,20 +157,20 @@ Plasma 链和分片链都定期向以太坊主网发布加密证明。 但是, Plasma 不同于此,因为主网只接收最少量的子链状态信息。 这意味着主网无法有效验证子链上进行的交易,降低了交易的安全性。 -**注意**:以太坊区块链分片已经不再包含在路线图中。 它已被卷叠及 [Danksharding](/roadmap/danksharding) 扩容方案所取代。 +**注意**:以太坊区块链分片已不在路线图上。 它已被通过卷叠和 [Danksharding](/roadmap/danksharding) 进行扩容所取代。 ### 使用 Plasma {#use-plasma} 许多项目提供 Plasma 实现,你可以将它们集成到自己的去中心化应用程序中: -- [Polygon](https://polygon.technology/)(原 Matic Network) +- [Polygon](https://polygon.technology/)(前身为 Matic Network) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [学习 Plasma](https://www.learnplasma.org/en/) -- [关于何为“共享安全”以及它为何如此重要的简单提示](https://old.reddit.com/r/ethereum/comments/sgd3zt/a_quick_reminder_of_what_shared_security_means/) -- [侧链、Plasma 与分片](https://vitalik.eth.limo/general/2019/06/12/plasma_vs_sharding.html) -- [了解 Plasma(第一部分):基础知识](https://www.theblockcrypto.com/amp/post/10793/understanding-plasma-part-1-the-basics) -- [Plasma 的一生](https://medium.com/dragonfly-research/the-life-and-death-of-plasma-b72c6a59c5ad#) +- [快速回顾“共享安全”的含义及其重要性](https://old.reddit.com/r/ethereum/comments/sgd3zt/a_quick_reminder_of_what_shared_security_means/) +- [侧链、Plasma 与分片之比较](https://vitalik.eth.limo/general/2019/06/12/plasma_vs_sharding.html) +- [了解 Plasma,第 1 部分:基础知识](https://www.theblockcrypto.com/amp/post/10793/understanding-plasma-part-1-the-basics) +- [Plasma 的兴衰](https://medium.com/dragonfly-research/the-life-and-death-of-plasma-b72c6a59c5ad#) -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ diff --git a/public/content/translations/zh/developers/docs/scaling/sidechains/index.md b/public/content/translations/zh/developers/docs/scaling/sidechains/index.md index 2fea96dd9fe..aaed9b9015e 100644 --- a/public/content/translations/zh/developers/docs/scaling/sidechains/index.md +++ b/public/content/translations/zh/developers/docs/scaling/sidechains/index.md @@ -1,13 +1,13 @@ --- -title: 侧链 -description: 介绍侧链 —— 以太坊社区目前正在使用的一种扩容方案。 +title: "侧链。" +description: "介绍侧链 —— 以太坊社区目前正在使用的一种扩容方案。" lang: zh sidebarDepth: 3 --- 侧链是独立于以太坊运行的独立区块链,通过双向桥梁与以太坊主网连接。 侧链可以有单独的区块参数和[共识算法](/developers/docs/consensus-mechanisms/),它们通常是为高效处理交易而设计的。 但是,使用侧链需要权衡取舍,因为它们未继承以太坊的安全属性。 与[二层网络扩容解决方案](/layer-2/)不同,侧链不会将状态变化和交易数据发布到以太坊主网。 -侧链还在一定程度上牺牲了去中心化或安全性来实现高吞吐量([可扩展性三难困境](https://vitalik.eth.limo/general/2021/05/23/scaling.html))。 然而,正如其升级[愿景声明](/roadmap/vision/)中所述,以太坊致力于在不影响去中心化和安全性的情况下扩容。 +侧链还在一定程度上牺牲了去中心化或安全性来实现高吞吐量([可扩展性三难困境](https://vitalik.eth.limo/general/2021/05/23/scaling.html))。 然而,以太坊致力于在不影响去中心化和安全性的情况下实现扩容。 ## 侧链如何运作? {#how-do-sidechains-work} @@ -19,7 +19,7 @@ sidebarDepth: 3 - [权威证明](/developers/docs/consensus-mechanisms/poa/) - [委托权益证明](https://en.bitcoin.it/wiki/Delegated_proof_of_stake) -- [拜占庭容错算法](https://decrypt.co/resources/byzantine-fault-tolerance-what-is-it-explained)。 +- [拜占庭容错](https://decrypt.co/resources/byzantine-fault-tolerance-what-is-it-explained)。 与以太坊一样,侧链也有验证并处理交易、生成区块以及存储区块链状态的验证节点。 验证者还负责维护整个网络的共识,并保护网络免受恶意攻击。 @@ -29,23 +29,23 @@ sidebarDepth: 3 虽然这样做有一些好处,但会对网络去中心化和安全性产生严重影响。 较快的出区块时间和较大的区块大小这样的区块参数,增加了运行全节点的难度,让一些“超级节点”负责保护区块链的安全。 在这种情况下,验证者串通或恶意接管区块链的可能性增加。 -为了使区块链在不损害去中心化的情况下扩容,必须所有人都可以运行节点,而不一定限于拥有专用硬件的各方。 这就是我们一直都在努力确保每个人都能在以太坊网络上[运行全节点](/developers/docs/nodes-and-clients/#why-should-i-run-an-ethereum-node)的原因。 +为了使区块链在不损害去中心化的情况下扩容,必须所有人都可以运行节点,而不一定限于拥有专用硬件的各方。 这就是为什么我们正在努力确保每个人都可以在以太坊网络上[运行全节点](/developers/docs/nodes-and-clients/#why-should-i-run-an-ethereum-node)。 -### 以太坊虚拟机兼容性 {#evm-compatibility} +### EVM 兼容性 {#evm-compatibility} -一些侧链与以太坊虚拟机兼容,并且能够执行为[以太坊虚拟机 (EVM) ](/developers/docs/evm/)开发的合约。 兼容以太坊虚拟机的侧链支持用 [Solidity 编写](/developers/docs/smart-contracts/languages/)的智能合约,也支持其他以太坊虚拟机智能合约语言,这意味着为以太坊主网编写的智能合约也将在兼容以太坊虚拟机的侧链上有效。 +一些侧链与 EVM 兼容,能够执行为[以太坊虚拟机 (EVM)](/developers/docs/evm/) 开发的合约。 兼容 EVM 的侧链支持[用 Solidity 编写的](/developers/docs/smart-contracts/languages/)智能合约,以及其他 EVM 智能合约语言,这意味着为以太坊主网编写的智能合约也将在兼容 EVM 的侧链上有效。 这意味着,如果想在侧链上使用你的[去中心化应用程序](/developers/docs/dapps/),只需将你的[智能合约](/developers/docs/smart-contracts/)部署到该侧链即可。 侧链的外观、给人的感受和行为与主链相似,你仍然用 Solidity 编写合约,并通过侧链远程过程调用与侧链交互。 -由于侧链与以太坊虚拟机兼容,因而被视为对以太坊原生去中心化应用程序有效的[扩容解决方案](/developers/docs/scaling/)。 去中心化应用程序部署到侧链上后,用户可以获得更低的燃料费用和更快的交易速度,尤其是在主网拥塞的情况下。 +由于侧链与 EVM 兼容,因而被视为对以太坊原生去中心化应用程序有效的[扩容解决方案](/developers/docs/scaling/)。 去中心化应用程序部署到侧链上后,用户可以获得更低的燃料费用和更快的交易速度,尤其是在主网拥塞的情况下。 然而,正如前文所述,使用侧链需认真权衡其利弊。 每个侧链负责其自身安全性,没有继承以太坊的安全属性。 这增加了发生恶意行为的可能性,可能会影响到你的用户或使他们的资金面临风险。 -### 资产转移 {#asset-movement} +### 资产移动 {#asset-movement} -为了使一条独立区块链成为以太坊主网的侧链,区块链必须能支持资产在它与以太坊主网之间转移。 这种与以太坊的互操作性是使用区块链桥梁实现的。 [桥梁](/bridges/)使用部署在以太坊主网和侧链上的智能合约控制两者之间的资金桥接。 +为了使一条独立区块链成为以太坊主网的侧链,区块链必须能支持资产在它与以太坊主网之间转移。 这种与以太坊的互操作性是使用区块链桥梁实现的。 [链桥](/bridges/)使用部署在以太坊主网和侧链上的智能合约来控制两者之间的资金桥接。 -虽然桥梁可以帮助用户在以太坊和侧链之间转移资金,但实体资产不会在两条链之间移动。 而是采用通常与铸币和销毁相关的机制跨链转移价值。 更多关于[桥梁如何运作](/developers/docs/bridges/#how-do-bridges-work)的信息。 +虽然桥梁可以帮助用户在以太坊和侧链之间转移资金,但实体资产不会在两条链之间移动。 而是采用通常与铸币和销毁相关的机制跨链转移价值。 关于[链桥如何运作](/developers/docs/bridges/#how-do-bridges-work)的更多信息。 ## 侧链的优缺点 {#pros-and-cons-of-sidechains} @@ -62,12 +62,12 @@ sidebarDepth: 3 - [Polygon PoS](https://polygon.technology/solutions/polygon-pos) - [Skale](https://skale.network/) -- [Gnosis Chain(原 xDai)](https://www.gnosischain.com/) +- [Gnosis Chain (前身为 xDai)](https://www.gnosischain.com/) - [Loom Network](https://loomx.io/) - [Metis Andromeda](https://www.metis.io/) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [通过侧链扩展以太坊去中心化应用程序](https://medium.com/loom-network/dappchains-scaling-ethereum-dapps-through-sidechains-f99e51fff447) _2018 年 2 月 8 日 - Georgios Konstantopoulos_ +- [通过侧链扩容以太坊去中心化应用程序](https://medium.com/loom-network/dappchains-scaling-ethereum-dapps-through-sidechains-f99e51fff447)_2018 年 2 月 8 日 - Georgios Konstantopoulos_ -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ diff --git a/public/content/translations/zh/developers/docs/scaling/state-channels/index.md b/public/content/translations/zh/developers/docs/scaling/state-channels/index.md index 10aa4172b11..0907b8837ca 100644 --- a/public/content/translations/zh/developers/docs/scaling/state-channels/index.md +++ b/public/content/translations/zh/developers/docs/scaling/state-channels/index.md @@ -1,6 +1,6 @@ --- -title: 状态通道 -description: 介绍状态通道和支付通道,作为以太坊社区目前使用的扩容解决方案。 +title: "状态通道" +description: "介绍状态通道和支付通道,作为以太坊社区目前使用的扩容解决方案。" lang: zh sidebarDepth: 3 --- @@ -31,7 +31,7 @@ sidebarDepth: 3 账本余额的更新(即支付渠道的状态)需要渠道中所有各方的批准。 通道更新在所有通道参与者签署后被视为最终确定,这和以太坊上的交易非常相似。 -支付通道是最早的扩容解决方案之一,旨在最大限度减少简单用户交互(例如,以太币转账、原子交换、小额支付)中的高成本链上活动。 通道参与者相互之间可以进行不限金额的即时、无费用交易,只要他们的转账净总额不超过存入的代币。 +支付通道是最早的扩容解决方案之一,旨在最大限度减少简单用户交互(例如,ETH 转账、原子交换、小额支付)中的高成本链上活动。 通道参与者相互之间可以进行不限金额的即时、无费用交易,只要他们的转账净总额不超过存入的代币。 ## 状态通道 {#state-channels} @@ -41,21 +41,21 @@ sidebarDepth: 3 但是,除了保存用户的余额外,通道还会跟踪合约存储的当前状态(即合约变量的值)。 -这使两个用户之间在链下执行智能合约成为可能。 在这种情况下,智能合约内部状态的更新只需由创建通道的对等方批准即可。 +这使得用户间可在链下执行智能合约。 在这种情况下,智能合约内部状态的更新只需由创建通道的对等方批准即可。 -虽然这解决了前文描述的可扩展性问题,但它对安全性有影响。 在以太坊上,以太坊状态转换的有效性是按照网络的共识协议强制执行的。 因此,不可能对智能合约状态提出无效更新,或者修改智能合约的执行。 +虽然这解决了前文描述的可扩展性问题,但它对安全性有影响。 在以太坊网络中,状态转换的有效性由网络的共识协议保障。 因此,不可能对智能合约状态提出无效更新,或者修改智能合约的执行。 状态通道没有同样的安全保障。 在某种程度上,状态通道是主网的缩小版。 由于执行规则的参与者有限,发生恶意行为(例如,提出无效的状态更新)的可能性增加。 状态通道的安全性源自基于[欺诈证明](/glossary/#fraud-proof)的争议仲裁系统。 ## 状态通道如何运作 {#how-state-channels-work} -状态通道中的活动基本上是一系列涉及用户和区块链系统的交互。 用户大多数情况下在链下相互交流,只有在开启通道、关闭通道或解决参与者之间的潜在争议时才会与底层区块链交互。 +状态通道中的活动基本上是一系列涉及用户和区块链系统的交互。 用户主要在链下进行通信,并仅与底层区块链交互以开启通道、关闭通道或解决参与者之间潜在的争议。 以下部分概述了状态通道的基本工作流程: ### 开启通道 {#opening-the-channel} -开启通道需要参与者将资金存入主网上的智能合约。 存款还可以用作虚拟标签,因此参与者可以自由交易,而无需立即结算付款。 只有当通道在链上最终确定时,各方才会相互结算并提取各自标签的余额。 +开启通道需要参与者将资金存入主网上的智能合约。 存款还可以用作虚拟标签,因此参与者可以自由交易,而无需立即结算付款。 只有当通道在链上完成最终确认后,参与者才会相互结算并提取各自账户剩余的余额。 这笔存款还可以作为保证金,保证每个参与者诚信行事。 如果在争议解决阶段判定存款人犯有恶意行为,合约将罚没他们的存款。 @@ -73,13 +73,13 @@ sidebarDepth: 3 - 触发状态转换的交易(例如,Alice 向 Bob 发送 5 个以太币) -通道中的状态更新不会像用户在主网上交互时那样在链上广播,这与状态通道最大限度减少链上足迹的目标一致。 只要参与者一致同意状态更新,它们就与以太坊交易一样最终确定。 如果出现争议,参与者只需依赖主网的共识。 +通道中的状态更新不会像用户在主网上交互时那样在链上广播,这符合状态通道最小化链上占用空间的目标。 只要参与者一致同意状态更新,它们就与以太坊交易一样最终确定。 如果出现争议,参与者只需依赖主网的共识。 ### 关闭通道 {#closing-the-channel} -要关闭状态通道,需要将各方一致同意的通道最终状态提交至链上智能合约。 状态更新中引用的详细信息包括每个参与者所实施行为的次数和获准交易的列表。 +关闭状态通道需提交该通道的最终达成共识的状态至链上智能合约。 状态更新中引用的详细信息包括每个参与者所实施行为的次数和获准交易的列表。 -在验证状态更新有效(即,已由所有各方签署)后,智能合约最终确定通道状态并根据通道结果分配锁定的资金。 链下进行的支付被应用到以太坊状态,每个参与者都会收到其剩余部分的锁定资金。 +在验证状态更新有效(即,已由所有各方签署)后,智能合约最终确定通道状态并根据通道结果分配锁定的资金。 链下的支付最终会反映到以太坊系统状态中,每位参与者都能取回其锁定资金的剩余部分。 上述场景代表了成功案例下的情况。 有时,用户可能无法达成一致并最终确定通道状态(失败案例)。 失败案例可能包括以下任何一种情况: @@ -87,7 +87,7 @@ sidebarDepth: 3 - 参与者拒绝共同签署有效的状态更新 -- 参与者试图通过向链上合约提出旧的状态更新来最终确定通道状态 +- 参与者通过向链上合约提交陈旧的状态更新来试图确定最终通道 - 参与者提出无效的状态转换供其他人签署 @@ -95,25 +95,25 @@ sidebarDepth: 3 ### 解决争议 {#settling-disputes} -通常,通道中的各方事先同意关闭通道并共同签署最后一个状态转换,然后将其提交到智能合约。 一旦更新在链上获得批准,链下智能合约的执行就会结束,参与者会带着他们的资金退出通道。 +通常,通道中的各方事先同意关闭通道并共同签署最后一个状态转换,然后将其提交到智能合约。 一旦状态更新在链上被确认,链下智能合约的执行即终止,参与者带着各自应得的资金退出通道。 -但是,一方可以提交链上请求以结束智能合约的执行并最终确定通道状态 — 而无需等待对方的批准。 如果出现上述任何破坏共识的情况,任何一方都可以触发链上合约以关闭通道并分配资金。 这样就实现了**去信任**,确保诚实的参与方可以随时撤出他们的存款,无论另一方的行为如何。 +然而,一方可以通过链上提交请求,单方面终止智能合约执行并完成通道结算——而无需等待对方批准。 若发生任何前述破坏共识的情形,任一参与方均可触发链上合约强制关闭通道并完成资金分配。 这样就实现了**去信任**,确保诚实的参与方可以随时撤出他们的存款,无论另一方的行为如何。 -要处理通道退出,用户必须将应用程序的最后一次有效状态更新提交至链上合约。 如果该状态更新得到证实(即,带有所有参与方的签名),那么资金就会按照有利于它们的方式重新分配。 +为执行通道退出流程,用户需向链上合约提交应用的最后一次有效状态更新。 如果该状态更新得到证实(即,带有所有参与方的签名),那么资金就会按照有利于它们的方式重新分配。 -但是,执行单用户退出请求会有延迟。 如果关闭通道的请求获得一致批准,则会立即执行链上退出交易。 +但是,执行单用户退出请求会有延迟。 若状态通道关闭请求获得全体一致同意,则链上退出交易将立即执行。 -由于存在欺诈行为的可能性,延迟在单用户退出中开始发挥作用。 例如,通道参与者可能尝试通过在链上提交较早的状态更新来最终确定以太坊上的通道状态。 +由于存在欺诈行为的可能性,延迟在单用户退出中开始发挥作用。 例如,在以太坊上,通道参与者可能尝试通过提交较旧的状态更新至链上,来非法完成通道结算以图谋不当利益。 -作为一种对策,状态通道允许诚实用户通过在链上提交最新的有效通道状态来挑战无效的状态更新。 状态通道的设计使得一致同意的较新状态更新优先于较早的状态更新。 +作为防御机制,状态通道允许诚实的用户通过将通道的最新有效状态提交到链上,来挑战无效状态更新行为。 状态通道的设计使得一致同意的较新状态更新优先于较早的状态更新。 -一旦某个对等方触发了链上争议解决系统,另一方需要在一定时限内(称为挑战窗口)做出响应。 这样用户就可以挑战退出交易,尤其是在另一方应用过时更新的情况下。 +一旦一方触发链上争议解决系统,另一方必须在规定时间内(称为挑战窗口)作出回应。 这样用户就可以挑战退出交易,尤其是在另一方应用过时更新的情况下。 -不管是哪种情况,通道用户总是拥有强大的最终确定性保障:如果他们拥有的状态转换已由所有成员签署并且是最新的更新,那么它便与常规链上交易具有相同的最终确定性。 他们仍必须在链上挑战另一方,但唯一可能的结果是最终确定他们所拥有的最新有效状态。 +无论何种情形,通道用户始终享有强大的最终性保障:只要其掌管的状态转移版本经所有参与方签名且为最新更新,则该状态在链上合约中的法律效力与常规链上交易完全等同。 尽管他们仍需通过链上合约挑战对方作恶行为,但这场对抗最终的唯一可预见结果是链上完成最终有效状态的结算。 ### 状态通道如何与以太坊交互? {#how-do-state-channels-interact-with-ethereum} -尽管状态通道是以链下协议的形式存在,但仍具有链上部分:开启通道时部署在以太坊上的智能合约。 该合约负责控制存入通道的资产,验证状态更新,并对参与者之间的争议进行仲裁。 +尽管状态通道在设计上属于链下协议,但它必须依赖链上组件——即用户在开启通道时部署在以太坊上的智能合约。 该合约负责控制存入通道的资产,验证状态更新,并对参与者之间的争议进行仲裁。 与[二层网络](/layer-2/)扩容解决方案不同,状态通道不会向主网发布交易数据或状态确认。 然而,它们与主网的联系比[侧链](/developers/docs/scaling/sidechains/)更紧密,这使得它们更加安全。 @@ -133,19 +133,19 @@ sidebarDepth: 3 由通道用户共同签署的状态更新被认为与链上交易一样有效。 尽管如此,所有通道内活动只有在以太坊上关闭通道时才能获得真正的最终确定性。 -在乐观情况下,双方可以合作、签署最终状态更新并在链上提交以关闭通道,然后根据通道的最终状态分配资金。 在悲观情况下,若有人试图通过在链上发布不正确的状态更新进行欺骗,双方的交易在挑战窗口结束之前不会最终确定。 +在乐观情况下,双方可以合作、签署最终状态更新并在链上提交以关闭通道,然后根据通道的最终状态分配资金。 在悲观情形下,若某一通道参与方试图通过链上提交“错误状态更新”进行欺诈,其对应的交易并不会立刻上链确认,而是必须等待挑战窗口结束后才能确定是否采纳。 ## 虚拟状态通道 {#virtual-state-channels} -状态通道的简易实现是在两个用户希望在链下执行应用程序时部署新合约。 这不仅不可行,而且否定了状态通道的成本效益(链上交易成本可能迅速增加)。 +状态通道的简易实现是在两个用户希望在链下执行应用程序时部署新合约。 这不仅行不通,而且还否定了状态通道的成本效益(链上交易成本会迅速增加)。 为了解决这个问题,人们创建了“虚拟通道”。 与需要链上交易才能开启和终止的常规通道不同,虚拟通道可以在不与主链交互的情况下开启、执行和最终确定。 甚至可以使用这种方法在链下解决争议。 -该系统依赖于所谓的“账本通道”(已在链上获得资金)的存在。 双方之间的虚拟通道可以建立在现有账本通道之上,并由账本通道的所有者作为中间人。 +该系统依赖于所谓的账本通道,这些通道已在链上完成注资(即资金已被锁定在以太坊智能合约中)。 双方之间的虚拟通道可以建立在现有账本通道之上,并由账本通道的所有者作为中间人。 每条虚拟通道中的用户通过一个新的合约实例进行交互,账本通道能够支持多个合约实例。 账本通道的状态还包含多个合约存储状态,允许在链下于不同用户之间并行执行应用程序。 -就像常规通道一样,用户交换状态更新以推进状态机。 除非出现争议,否则仅在开启或终止通道时才必须联系中间人。 +就像常规通道一样,用户交换状态更新以推进状态机。 除非出现争议,中间人仅需在开启或终止通道时被调用,日常链下交互无需其参与。 ### 虚拟支付通道 {#virtual-payment-channels} diff --git a/public/content/translations/zh/developers/docs/scaling/validium/index.md b/public/content/translations/zh/developers/docs/scaling/validium/index.md index eef58dd0131..2e1ef8e9459 100644 --- a/public/content/translations/zh/developers/docs/scaling/validium/index.md +++ b/public/content/translations/zh/developers/docs/scaling/validium/index.md @@ -1,25 +1,25 @@ --- title: Validium -description: 介绍 Validium - 以太坊社区目前使用的一种扩容解决方案。 +description: "介绍 Validium - 以太坊社区目前使用的一种扩容解决方案。" lang: zh sidebarDepth: 3 --- -Validium 是一种[扩容解决方案](/developers/docs/scaling/),使用[零知识卷叠](/developers/docs/scaling/zk-rollups/)等有效性证明来执行交易的完整性,但它不在以太坊主网上存储交易数据。 虽然链下数据可用性是一种折衷方案,但它可以显著提升可扩展性(Validium 每秒可以处理[约 9000 笔交易,甚至更多](https://blog.matter-labs.io/zkrollup-vs-validium-starkex-5614e38bc263))。 +Validium 是一种[扩容解决方案](/developers/docs/scaling/),它使用像 [ZK 卷叠](/developers/docs/scaling/zk-rollups/)这样的有效性证明来强制执行交易的完整性,但不在以太坊主网上存储交易数据。 虽然链下数据可用性会引入一些权衡,但它可以极大地提高可扩展性(Validium 每秒可以处理[约 9,000 笔或更多笔交易](https://blog.matter-labs.io/zkrollup-vs-validium-starkex-5614e38bc263))。 ## 前提条件 {#prerequisites} -你应该已经阅读并理解关于[以太坊扩容](/developers/docs/scaling/)和[二层网络](/layer-2)的页面。 +你应该已经阅读并理解我们关于[以太坊扩容](/developers/docs/scaling/)和[二层网络](/layer-2)的页面。 ## 什么是 Validium? {#what-is-validium} -Validium 是使用链下数据可用性和计算的扩展解决方案,旨在通过在以太坊主网外处理交易来提高吞吐量。 与零知识卷叠(ZK 卷叠)一样,Validium 发布[零知识证明](/glossary/#zk-proof)以便在以太坊上验证链下交易。 这样可以防止无效的状态转换并增强 Validium 链的安全保障。 +Validium 是使用链下数据和计算结果的扩容解决方案,旨在通过在以太坊主网外处理交易来提高吞吐量。 与零知识卷叠 (ZK-rollups) 一样,validium 会发布[零知识证明](/glossary/#zk-proof)以在以太坊上验证链下交易。 这样可以防止无效的状态转换并增强 Validium 链的安全保障。 -这些“有效性证明”可以有 ZK-SNARK(零知识简洁非交互式知识论证)或 ZK-STARK(零知识可扩展透明知识论证)等形式。 更多关于[零知识证明](https://consensys.net/blog/blockchain-explained/zero-knowledge-proofs-starks-vs-snarks/)的信息。 +这些“有效性证明”可以有 ZK-SNARK(零知识简洁非交互式知识论证)或 ZK-STARK(零知识可扩展透明知识论证)等形式。 更多关于[零知识证明](https://consensys.net/blog/blockchain-explained/zero-knowledge-proofs-starks-vs-snarks/)。 -属于 Validium 用户的资金由以太坊上的智能合约控制。 恰如零知识卷叠一样,Validium 几乎可以提供即时提款;在主网上验证提款请求的有效性证明后,用户可以通过提供[默克尔证明](/developers/tutorials/merkle-proofs-for-offline-data-integrity/)提取资金。 默克尔证明验证用户的提款交易是否包含在经过验证的交易批次中,从而允许链上合约处理提款。 +属于 Validium 用户的资金由以太坊上的智能合约控制。 Validium 提供近乎即时的提款,与 ZK 卷叠非常相似;一旦提款请求的有效性证明在主网上得到验证,用户就可以通过提供[默克尔证明](/developers/tutorials/merkle-proofs-for-offline-data-integrity/)来提取资金。 默克尔证明用于验证用户的提款交易是否包含在经过验证的交易批次中,从而允许链上合约处理提款。 -但是,Validium 用户可以冻结他们的资金并限制提款。 如果 Validium 链上的数据可用性管理器不给用户提供链下状态数据,就会发生这种情况。 如果无法访问交易数据,用户将无法计算证明资金所有权和执行提款所需的默克尔证明。 +但是,Validium 用户可以冻结他们的资金并限制提款。 如果 Validium 链的数据管理员不给用户提供链下数据,就会发生这种情况。 如果无法访问交易数据,用户将无法计算证明资金所有权和执行提款所需的默克尔证明。 这是 Validium 和零知识卷叠之间的主要区别,它们在数据可用性范围内的位置不同。 两种解决方案处理数据存储的方式不同,这会对安全性和去信任产生影响。 @@ -27,27 +27,27 @@ Validium 是使用链下数据可用性和计算的扩展解决方案,旨在 Validium 是建立在现有以太坊链上的扩容协议。 虽然它在链下执行交易,但 Validium 链由部署在主网上的一系列智能合约管理,包括: -1. **验证者合约**:验证者合约验证 Validium 运营商在进行状态更新时所提交证明的有效性。 该合约包括证明链下交易正确性的有效性证明和验证链下交易数据存在的数据可用性证明。 +1. **验证者合约**:验证者合约在进行状态更新时,会验证 validium 运营商提交的证明的有效性。 该合约包括证明链下交易正确性的有效性证明和验证链下交易数据存在的数据可用性证明。 -2. **主合约**:主合约存储区块生产者提交的状态承诺(默克尔根),并在链上验证有效性证明后更新 Validium 的状态。 该合约还处理 Validium 链上的存款和提款。 +2. **主合约**:主合约存储区块生产者提交的状态承诺(默克尔根),并在有效性证明在链上得到验证后,更新 validium 的状态。 该合约还处理 Validium 链上的存款和提款。 Validium 还依赖以太坊主链实现: ### 结算 {#settlement} -在父链验证其有效性之前,无法完全确认在 Validium 上执行的交易。 所有在 Validium 上进行的业务最终都必须在主网上结算。 以太坊区块链还为 Validium 用户提供了“结算保障”,这意味着一旦提交到链上,链下交易就不能逆转或改变。 +在父链验证其有效性之前,无法完全确认在 Validium 上执行的交易。 所有在 Validium 上进行的业务最终都必须在主网上结算。 以太坊区块链还为 Validium 用户提供了“结算保障”,这意味着一旦提交到链上,链下交易就不能更改。 -### 安全性 {#security} +### 安全 {#security} -作为结算层的以太坊也保证 Validium 上状态转换的有效性。 在 Validium 链上执行的链下交易通过以太坊基础层上的智能合约进行验证。 +作为结算层的以太坊也保证 Validium 上状态转换的有效性。 在 Validium 链上执行的链下交易通过以太坊基础阶段的智能合约进行验证。 -如果链上验证者合约断定证明无效,则交易被拒绝。 这意味着运营商必须满足以太坊协议执行的有效性条件,然后才能更新 Validium 的状态。 +如果链上合约验证者断定证明无效,则交易会被拒绝。 这意味着运营商必须满足以太坊协议执行的有效性条件,然后才能更新 Validium 的状态。 ## Validium 如何运作? {#how-does-validium-work} ### 交易 {#transactions} -用户向运营商提交交易,运营商是负责在 Validium 链上执行交易的节点。 一些 Validium 可能采用单个运营商来执行链,或者依靠[权益证明 (PoS)](/developers/docs/consensus-mechanisms/pos/) 机制轮换运营商。 +用户向运营商提交交易,运营商是负责在 Validium 链上执行交易的节点。 一些 validium 可能会使用单一运营商来执行链,或依靠[权益证明 (PoS)](/developers/docs/consensus-mechanisms/pos/) 机制来轮换运营商。 运营商将交易聚合成一个批次并发送到证明线路进行证明。 证明线路接受交易批次(及其他相关数据)作为输入,并输出验证操作正确执行的有效性证明。 @@ -55,11 +55,11 @@ Validium 还依赖以太坊主链实现: Validium 的状态被哈希处理成默克尔树,其根存储在以太坊的主合约中。 默克尔根又称为状态根,作为对 Validium 上当前帐户状态和余额的加密承诺。 -要执行状态更新,运营商必须(在执行交易后)计算一个新的状态根并将提交给链上合约。 如果有效性证明得到证实,提出的状态被接受,Validium 切换到新的状态根。 +要更新状态,运营商必须(在执行交易后)计算并提出一个新的状态根并提交给链上合约。 如果有效性证明得到证实,提出的状态被接受,Validium 切换到新的状态根。 ### 存款和提款 {#deposits-and-withdrawals} -用户通过在链上合约中存入以太币(或任何与以太坊意见征求兼容的代币),将资金从以太坊转移到 Validium。 该合约将存款事件转发到链下 Validium,并向用户在 Validium 上的地址存入与其存款相同的金额。 运营商还将此存款交易添加到新批次中。 +用户通过在链上合约中存入以太币(或任何与以太坊兼容的代币)将资金从以太坊转移到 Validium。 该合约将存款事件转发到链下 Validium,并向用户在 Validium 上的地址存入与其存款相同的金额。 运营商还将此存款交易添加到新批次中。 要将资金转移回主网,Validium 用户发起提款交易并将其提交给运营商,后者验证提款请求并将其包含在批次中。 在用户能够退出系统前,他们在 Validium 链上的资产也被销毁。 一旦与该批次相关的有效性证明得到验证,用户就可以调用主合约来提取剩余的初始存款。 @@ -69,97 +69,98 @@ Validium 的状态被哈希处理成默克尔树,其根存储在以太坊的 执行一批交易后,运营商向验证者合约提交相关有效性证明,并向主合约提出新的状态根。 如果证明是有效的,则主合约更新 Validium 的状态并最终确定批次中交易的结果。 -与零知识卷叠不同,Validium 上的区块生产者不需要发布交易批次的交易数据(仅发布区块头)。 这使得 Validium 成为一个纯粹的链下扩容协议,而不是在以太坊主链(例如 `calldata`)上发布状态数据的“混合”扩容协议(即[二层网络](/layer-2/))。 +与零知识卷叠不同,Validium 上的区块生产者不需要发布交易批次的交易数据(仅发布区块头)。 这使得 validium 成为一种纯粹的链下扩容协议,而不是“混合”扩容协议(即[二层网络](/layer-2/)),后者使用 blob 数据、calldata 或两者的组合在以太坊主链上发布状态数据。 ### 数据可用性 {#data-availability} -如上所述,Validium 利用一个链下数据可用性模型,运营商通过该模型将所有交易数据存储在以太坊主网之外。 Validium 的低链上数据足迹提升了可扩展性(吞吐量不受以太坊数据处理能力的限制),并降低了用户费用(发布 `calldata` 的成本降低)。 +如上所述,Validium 会使用链下数据可用性模型,而运营商通过该模型将所有交易数据存储在以太坊主网之外。 Validium 的低链上数据占用提高了可扩展性 (吞吐量不受以太坊数据处理能力的限制),并降低了用户费用 (在链上发布数据的成本更低)。 然而,链下数据可用性带来了一个问题:创建或验证默克尔证明所需的数据可能不可用。 这意味着如果运营商采取恶意行为,用户可能无法从链上合约中提取资金。 各种 Validium 解决方案试图通过以去中心化的方式存储状态数据来解决这个问题。 即,强制区块生产者将底层数据发送给“数据可用性管理器”,这些管理器负责存储链下数据并在用户请求时提供给用户。 -Validium 中的数据可用性管理器通过签署每个 Validium 批次来证明链下交易数据的可用性。 这些签名构成了一种“可用性证明”,链上验证者合约在批准状态更新之前对其进行检查。 +Validium 中的数据可用性管理器通过签署每个 Validium 批次来证明链下交易数据的可用性。 这些签名构成了一种“可用性证明”,而链上合约验证者在批准状态更新之前会对其进行检查。 Validium 的数据可用性管理方法不同。 一些依赖受信任方存储状态数据,而另一些则使用随机指定的验证者。 #### 数据可用性委员会 (DAC) {#data-availability-committee} -为了保证链下数据的可用性,一些 Validium 解决方案指定了一组受信任的实体(统称为数据可用性委员会 (DAC))来存储状态副本并提供数据可用性证明。 由于成员较少,数据可用性委员会更容易实施并且需要较少的协调。 +为了保证链下数据的可用性,一些 Validium 解决方案指定了一组受信任的实体,统称为数据可用性委员会 (DAC)来存储状态副本并提供数据可用性证明。 由于成员较少,数据可用性委员会更容易实施并且需要较少的协调。 -但是,用户必须信任数据可用性委员会,才能在需要时(例如用于生成默克尔证明)获得数据。 数据可用性委员会的成员有可能[被恶意行为者入侵](https://notes.ethereum.org/DD7GyItYQ02d0ax_X-UbWg?view),然后会扣留链下数据。 +但是,用户必须信任数据可用性委员会,才能在需要时(例如用于生成默克尔证明)获得数据。 数据可用性委员会的成员有可能会[被恶意行为者攻破](https://notes.ethereum.org/DD7GyItYQ02d0ax_X-UbWg?view),然后扣留链下数据。 -[更多关于 Validium 中数据可用性委员会的信息](https://medium.com/starkware/data-availability-e5564c416424)。 +[更多关于 validium 中的数据可用性委员会](https://medium.com/starkware/data-availability-e5564c416424)。 -#### 绑定数据可用性 {#bonded-data-availability} +#### 质押数据可用性 {#bonded-data-availability} 其他 Validium 要求负责存储离线数据的参与者在承担其角色之前在智能合约中质押(即锁定)代币。 这种质押作为“保证金”,保证数据可用性管理者之间采取的诚实行为并减少信任假设。 如果这些参与者不能证明数据的可用性,那么保证金就会被惩没。 -在绑定数据可用性方案中,任何人在提供要求的质押后,都可以指定其保存链下数据。 这扩大了合格数据可用性管理者池,削弱了对数据可用性委员会 (DAC) 造成影响的中心化。 更重要的是,这种方法依赖于加密经济激励措施防止恶意活动,这比指定受信任方在 Validium 中保护离线数据要安全得多。 +在联结数据可用性方案中,任何人在满足要求的质押后,都可能被指定保存链下数据。 这扩大了合格数据可用性管理者池,削弱了对数据可用性委员会 (DAC) 造成影响的中心化。 更重要的是,这种方法依赖于加密经济激励措施防止恶意活动,这比指定受信任方在 Validium 中保护离线数据要安全得多。 -[更多关于 Validium 中绑定数据可用性的信息](https://blog.matter-labs.io/zkporter-a-breakthrough-in-l2-scaling-ed5e48842fbf)。 +[更多关于 validium 中的质押数据可用性](https://blog.matter-labs.io/zkporter-a-breakthrough-in-l2-scaling-ed5e48842fbf)。 -## Volitions 和 Validium {#volitions-and-validium} +## Volition 和 validium {#volitions-and-validium} Validium 提供了诸多好处,但也进行了折衷(最值得注意的是数据可用性)。 但是,与许多扩容解决方案一样,Validium 适合特定的用例,这就是 Volitions 方案出现的原因。 -Volitions 结合了零知识卷叠和 Validium 链,它允许用户在两种扩容解决方案之间切换。 使用 Volitions,用户可以利用 Validium 的链下数据可用性进行某些交易,同时可以在需要时自由地切换到链上数据可用性解决方案(零知识卷叠)。 这实质上使用户可以根据他们的独特情况自由地进行权衡取舍。 +Volitions 结合了零知识卷叠和 Validium 链,它允许用户在两种扩容解决方案之间切换。 使用 Volitions,用户可以利用 Validium 的链下数据进行某些交易,同时可以在需要时自由地切换到链上数据可用性解决方案(零知识卷叠)。 这实质上使用户可以根据他们的独特情况自由地进行权衡取舍。 去中心化交易所 (DEX) 可能更喜欢使用 Validium 的可扩展和私有基础设施进行大额交易。 它还可以为需要零知识卷叠更高安全性保证和去信任性的用户使用零知识卷叠。 -## Validium 和以太坊虚拟机的兼容性 {#validiums-and-evm-compatibility} +## Validium 和 EVM 兼容性 {#validiums-and-evm-compatibility} -与零知识卷叠一样,Validium 最适合简单的应用,例如代币交换和支付。 鉴于在零知识证明线路中证明[以太坊虚拟机](/developers/docs/evm/)指令的开销很大,因此在 Validium 之间很难为通用计算和智能合约执行提供支持。 +与零知识卷叠一样,Validium 最适合简单的应用,例如代币交换和支付。 鉴于在零知识证明电路中证明[EVM](/developers/docs/evm/) 指令的开销相当大,在 validium 之间支持通用计算和智能合约执行是很难实现的。 一些 Validium 项目试图通过编译与以太坊虚拟机兼容的语言(例如 Solidity、Vyper)来生成针对高效证明而优化的自定义字节码,从而回避这个问题。 这种方法的一个缺点是零知识证明友好的新的虚拟机可能不支持重要的以太坊虚拟机操作码,而且开发者必须直接用高级语言编写才能获得最佳体验。 这带来了更多问题:它迫使开发者使用全新的开发堆栈构建去中心化应用程序,并破坏了与当前以太坊基础设施的兼容性。 -然而,一些团队正在尝试针对零知识证明线路优化现有以太坊虚拟机操作码。 这将导致零知识以太坊虚拟机 (zkEVM) 的开发,这是一种与以太坊虚拟机兼容的虚拟机,可生成验证程序是否正确执行的证明。 使用零知识以太坊虚拟机,Validium 链可以在链下执行智能合约并提交有效性证明,以便在以太坊上验证链下计算(无需重新执行)。 +然而,一些团队正在尝试针对零知识证明线路优化现有以太坊虚拟机操作码。 这将导致零知识以太坊虚拟机 (zkEVM) 的开发,这是一种与以太坊虚拟机兼容的虚拟机,可生成验证程序是否正确执行的证明。 使用零知识以太坊虚拟机,Validium 链可以在链下执行智能合约并提交有效性证明,以便在以太坊上验证链下计算结果(无需重新执行)。 -[更多关于零知识以太坊虚拟机的信息](https://www.alchemy.com/overviews/zkevm)。 +[更多关于 zkEVM](https://www.alchemy.com/overviews/zkevm)。 ## Validium 如何扩展以太坊? {#scaling-ethereum-with-validiums} -### 1. 链下数据存储 {#off-chain-data-storage} +### 1. 链下数据存储 {#offchain-data-storage} -二层网络扩容项目(例如乐观卷叠和零知识卷叠)通过将部分交易数据发布到一层网络,牺牲了纯链下扩容协议(例如 [Plasma](/developers/docs/scaling/plasma/))的无限可扩展性来换取安全性。 然而,这意味着卷叠的可扩展性属性受到以太坊主网上数据带宽的限制(因此,[数据分片](/roadmap/danksharding/)提议要提高以太坊的数据存储容量)。 +二层网络扩容项目(例如乐观卷叠和 ZK 卷叠)通过在 L1 上发布一些交易数据来换取安全性,从而牺牲了纯链下扩容协议(例如 [Plasma](/developers/docs/scaling/plasma/))的无限可扩展性。 但这意味着卷叠的可扩展性受限于以太坊主网的数据带宽(为此,[数据分片](/roadmap/danksharding/)旨在提高以太坊的数据存储容量)。 -Validium 实现了可扩展性,它将所有交易数据保存在链下并且在将状态更新传送到以太坊主链时仅发布状态承诺(和有效性证明)。 然而,有效性证明的存在为 Validium 提供了比其他纯链下扩容解决方案(包括 Plasma 和[侧链](/developers/docs/scaling/sidechains/))更高的安全保障。 通过减少以太坊在验证链下交易之前必须处理的数据量,Validium 设计极大地提升了主网上的吞吐量。 +Validium 实现了可扩展性。它将所有交易数据保存在链下并且在将状态更新传送到以太坊主链时仅发布状态承诺(和有效性证明)。 然而,有效性证明的存在,为 validium 提供了比其他纯链下扩容解决方案(包括 Plasma 和[侧链](/developers/docs/scaling/sidechains/))更高的安全保证。 通过减少以太坊在验证链下交易之前必须处理的数据量,Validium 极大地提升了主网的吞吐量。 ### 2. 递归证明 {#recursive-proofs} 递归证明是一种有效性证明,它验证其他证明的有效性。 这些“证明的证明”的生成方式如下:通过以递归方式聚合多个证明直到创建一个可验证所有先前证明的最终证明,即递归证明。 递归证明通过增加每个有效性证明可以验证的交易数量来提升区块链处理速度。 -通常,Validium 运营商提交到以太坊作验证用途的每个有效性证明都会验证单个区块的完整性。 而一个递归证明可用来同时确认几个 Validium 区块的有效性 — 这是可能的,因为证明线路能够以递归方式将几个区块证明聚合成一个最终证明。 如果链上验证者合约接受递归证明,则所有底层区块都会立即最终确定。 +通常,Validium 运营商提交到以太坊作验证用途的每个有效性证明都会验证单个区块的完整性。 而一个递归证明可用来同时确认几个 Validium 区块的有效性 — 这是可能的,因为证明线路能够以递归方式将几个区块证明聚合成一个最终证明。 如果链上验证者合约接受递归证明,则所有底层区块都会立即确定。 ## Validium 的优缺点 {#pros-and-cons-of-validium} -| 优点 | 缺点 | -| ---------------------------------- | --------------------------------------------------------- | -| 有效性证明强制验证链下交易的完整性,并阻止运营商最终定无效状态更新。 | 生成有效性证明需要使用专用硬件,这会带来中心化风险。 | -| 提高用户的资本效率(将资金提取回以太坊时不会出现延迟) | 对通用计算/智能合约的支持有限;开发需要专门语言。 | -| 在高价值应用中,不容易受到基于欺诈证明的系统所面临的某些经济攻击。 | 生成零知识证明需要强大的算力;对于低吞吐量的应用不具有成本效益。 | -| 通过不将调用数据发布到以太坊主网来降低用户的燃料费用。 | 较慢的主观最终确定性时间(生成零知识证明需要 10-30 分钟),但完全最终确定性要快一些,因为没有争议时间延迟。 | -| 适用于特定用例,例如优先考虑交易隐私和可扩展性的交易或区块链游戏。 | 可以防止用户提取资金,因为生成所有权的默克尔证明需要链下数据始终可用。 | -| 链下数据可用性提升了吞吐量并增强了可扩展性。 | 安全模型依赖于信任假设和加密经济激励措施,与完全依赖加密安全机制的零知识卷叠不同。 | +| 优点 | 缺点 | +| -------------------------------------- | --------------------------------------------------------- | +| 有效性证明强制验证链下交易的完整性,并阻止运营商出现最终状态更新无效的情况。 | 生成有效性证明需要使用专用硬件,这会带来中心化风险。 | +| 提高用户的资本效率(将资金提取回以太坊时不会出现延迟) | 对通用计算/智能合约的支持有限;开发需要专门语言。 | +| 在高价值应用中,不容易受到基于欺诈证明的系统所面临的某些经济攻击。 | 生成零知识证明需要强大的算力;对于低吞吐量的应用不具有成本效益。 | +| 通过不将调用数据发布到以太坊主网来降低用户的燃料费用。 | 较慢的主观最终确定性时间(生成零知识证明需要 10-30 分钟),但完全最终确定性要快一些,因为没有争议时间延迟。 | +| 适用于特定用例,例如优先考虑交易隐私和可扩展性的交易或区块链游戏。 | 由于生成 Merkle 所有权证明需要始终提供链下数据,因此可能会阻止用户提取资金。 | +| 链下数据可用性提升了吞吐量并增强了可扩展性。 | 安全模型依赖于信任假设和加密经济激励措施,与完全依赖加密安全机制的零知识卷叠不同。 | ### 使用 Validium/Volitions {#use-validium-and-volitions} 许多项目提供 Validium 和 Volitions 实现,你可以将它们集成到自己的去中心化应用程序中: -**StarkWare StarkEx** - _StarkEx 是基于有效性证明的以太坊二层网络 (L2) 可扩展性解决方案。 它可以在零知识卷叠或 Validium 数据可用性模式下运行。_ +**StarkWare StarkEx** - _StarkEx 是一种基于有效性证明的以太坊二层网络 (L2) 扩容解决方案。 它可以在 ZK-Rollup 或 Validium 数据可用性模式下运行。_ - [相关文档](https://docs.starkware.co/starkex-v4/starkex-deep-dive/data-availability-modes#validium) - [网站](https://starkware.co/starkex/) -**Matter Labs zkPorter**- _zkPorter 是一个二层扩容协议,它用一种结合了零知识卷叠和分片观点的混合方法来处理数据可用性。 它支持任意多个分片,每个分片都有自己的数据可用性策略。_ +**Matter Labs zkPorter** - _zkPorter 是一种二层网络扩容协议,它通过结合 zkRollup 和分片的思想,采用混合方法处理数据可用性问题。 它能支持任意数量的分片,每个分片都有自己的数据可用性策略。_ - [博客](https://blog.matter-labs.io/zkporter-a-breakthrough-in-l2-scaling-ed5e48842fbf) - [相关文档](https://docs.zksync.io/zksync-protocol/rollup/data-availability) - [网站](https://zksync.io/) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [Validium 和二层 2 x 2 矩阵 — 第 99 期](https://www.buildblockchain.tech/newsletter/issues/no-99-validium-and-the-layer-2-two-by-two) -- [零知识卷叠与 Validium](https://blog.matter-labs.io/zkrollup-vs-validium-starkex-5614e38bc263) -- [Volition 与新兴数据可用性范围](https://medium.com/starkware/volition-and-the-emerging-data-availability-spectrum-87e8bfa09bb) -- [Rollups、Validium 和 Volitions:了解最热门的以太坊扩容解决方案](https://www.defipulse.com/blog/rollups-validiums-and-volitions-learn-about-the-hottest-ethereum-scaling-solutions) +- [Validium 和二层网络二分法 — 第 99 期](https://www.buildblockchain.tech/newsletter/issues/no-99-validium-and-the-layer-2-two-by-two) +- [ZK 卷叠与 Validium 的比较](https://blog.matter-labs.io/zkrollup-vs-validium-starkex-5614e38bc263) +- [Volition 和新兴的数据可用性范围](https://medium.com/starkware/volition-and-the-emerging-data-availability-spectrum-87e8bfa09bb) +- [Rollup、Validium 和 Volition:了解最热门的以太坊扩容解决方案](https://www.defipulse.com/blog/rollups-validiums-and-volitions-learn-about-the-hottest-ethereum-scaling-solutions) +- [以太坊 Rollup 实用指南](https://web.archive.org/web/20241108192208/https://research.2077.xyz/the-practical-guide-to-ethereum-rollups) diff --git a/public/content/translations/zh/developers/docs/scaling/zk-rollups/index.md b/public/content/translations/zh/developers/docs/scaling/zk-rollups/index.md index 7ade72b6bba..13c5dd5bc71 100644 --- a/public/content/translations/zh/developers/docs/scaling/zk-rollups/index.md +++ b/public/content/translations/zh/developers/docs/scaling/zk-rollups/index.md @@ -1,36 +1,35 @@ --- -title: 零知识卷叠 -description: 零知识卷叠简介 — 以太坊社区使用的一种扩容解决方案。 +title: "零知识卷叠" +description: "零知识卷叠简介 — 以太坊社区使用的一种扩容解决方案。" lang: zh --- -零知识卷叠(ZK 卷叠)是二层网络[扩容解决方案](/developers/docs/scaling/),通过将计算和状态存储转移到链下进行提高了以太坊主网吞吐量。 零知识卷叠可以处理一个批次中的数千笔交易,但仅将一部分最少量的摘要数据发布到主网。 这些摘要数据确定了应对以太坊状态进行的变化以及一些证明这些变化正确性的加密证明。 +零知识卷叠 (ZK-rollups) 是二层 [扩容解决方案](/developers/docs/scaling/),通过将计算和状态存储移至脱链,来提高以太坊主网的吞吐量。 零知识卷叠可以处理一个批次中的数千笔交易,但仅将一部分最少量的摘要数据发布到主网。 这些摘要数据确定了应对以太坊状态进行的变化以及一些证明这些变化正确性的加密证明。 ## 前提条件 {#prerequisites} -你应该已经阅读并理解关于[以太坊扩容](/developers/docs/scaling/)和[二层网络](/layer-2)的页面。 +你应该已经阅读并理解我们关于[以太坊扩容](/developers/docs/scaling/)和[二层网络](/layer-2)的页面。 ## 什么是零知识卷叠? {#what-are-zk-rollups} +**零知识卷叠 (ZK-rollups)** 将交易捆绑(或“卷叠”)成批次,并在脱链执行。 链下计算减少了必须发布到区块链的数据量。 零知识卷叠运营商提交用于表示批次中所有交易的变化摘要,而不是单独发送每笔交易。 它们还生成[有效性证明](/glossary/#validity-proof)来证明其变更的正确性。 -**零知识卷叠(ZK 卷叠)**将在链下执行的交易打包(或“卷叠”)成批。 链下计算减少了必须发布到区块链的数据量。 零知识卷叠运营商提交用于表示批次中所有交易的变化摘要,而不是单独发送每笔交易。 他们还生成[有效性证明](/glossary/#validity-proof)来证明状态变化的正确性。 +零知识卷叠的状态由部署在以太坊网络上的智能合约维护。 为了更新这个状态,零知识卷叠节点必须提交一个有效性证明进行验证。 如前所述,有效性证明是一种加密保证,即卷叠提出的状态变化确实是执行给定批次交易的结果。 这意味着零知识卷叠只需提供有效性证明即可在以太坊上最终确定交易,而无需像[乐观卷叠](/developers/docs/scaling/optimistic-rollups/)那样将所有交易数据发布到链上。 -零知识卷叠的状态由部署在以太坊网络上的智能合约维护。 为了更新这个状态,零知识卷叠节点必须提交一个有效性证明进行验证。 如前所述,有效性证明是一种加密保证,即卷叠提出的状态变化确实是执行给定批次交易的结果。 这意味着零知识卷叠只需提供有效性证明即可在以太坊上最终确定交易,而不是像[乐观卷叠](/developers/docs/scaling/optimistic-rollups/)那样将所有交易数据发布到链上。 +将资金从零知识卷叠转移到以太坊时不会出现延迟,因为一旦零知识卷叠合约验证了有效性证明后,就会执行退出交易。 相反,从乐观卷叠中提取资金会有延迟,以便任何人都可以用[欺诈证明](/glossary/#fraud-proof)来挑战退出交易。 -将资金从零知识卷叠转移到以太坊时不会出现延迟,因为一旦零知识卷叠合约验证了有效性证明后,就会执行退出交易。 相反,从乐观卷叠中提取资金会产生延迟,让任何人都可以使用[欺诈证明](/glossary/#fraud-proof)来挑战退出交易。 +零知识卷叠将交易作为 `calldata` 写入以太坊。 `calldata` 是存储对智能合约函数进行外部调用时所含数据的地方。 `calldata` 中的信息发布在区块链上,允许任何人独立地重建该卷叠的状态。 零知识卷叠使用压缩技术减少交易数据 — 例如,帐户用索引而不是地址表示,这样可以节省 28 字节的数据。 链上数据发布占据卷叠的大部分成本,因此数据压缩可以降低用户的费用。 -零知识卷叠将交易作为 `calldata` 写入以太坊。 对智能合约函数进行的外部调用中包含的数据就存储在 `calldata` 中。 `calldata` 中的信息发布在区块链上,让任何人都可以独立重建该卷叠的状态。 零知识卷叠使用压缩技术减少交易数据 — 例如,帐户用索引而不是地址表示,这样可以节省 28 字节的数据。 链上数据发布占据卷叠的大部分成本,因此数据压缩可以降低用户的费用。 - -## 零知识卷叠如何与以太坊交互? {#zk-rollups-and-ethereum} +## 零知识卷叠如何与以太坊交互? 零知识卷叠和以太坊 {#zk-rollups-and-ethereum} 零知识卷叠链是一种在以太坊区块链上运行并由链上以太坊智能合约管理的链下协议。 零知识卷叠在主网之外执行交易,但会定期将链下交易批次提交到链上卷叠合约。 与以太坊区块链非常相像,这种交易记录是不可更改的并形成了零知识卷叠链。 零知识卷叠的核心架构由以下组件构成: -1. **链上合约**:如前所述,零知识卷叠协议由运行在以太坊上的智能合约控制。 其中包括存储卷叠区块、跟踪存款并监控状态更新的主合约。 另一个上链上合约(验证者合约),它验证区块生产者提交的零知识证明。 因此,以太坊充当零知识卷叠的基础层或“一层网络”。 +1. **链上合约**:如前所述,零知识卷叠协议由运行在以太坊上的智能合约控制。 其中包括存储卷叠区块、跟踪存款并监控状态更新的主合约。 另一种链上合约(验证者合约)验证区块生产者提交的零知识证明。 因此,以太坊充当零知识卷叠的基础层或“一层网络”。 -2. **链下虚拟机 (VM)**:虽然零知识卷叠协议存在于以太坊上,但交易执行和状态存储却在独立于[以太坊虚拟机](/developers/docs/evm/)的单独虚拟机中进行。 这种链下虚拟机是零知识卷叠上交易的执行环境,并作为零知识卷叠协议的第二层或“二层网络”。 在以太坊主网上验证的有效性证明保证链下虚拟机中状态转换的正确性。 +2. **脱链虚拟机 (VM)**:虽然零知识卷叠协议存在于以太坊上,但交易执行和状态存储却在独立于 [EVM](/developers/docs/evm/) 的单独虚拟机中进行。 这种链下虚拟机是在零知识卷叠上交易的执行环境,并作为零知识卷叠协议的第二阶段或“第二阶段网络”。 在以太坊主网上验证的有效性证明保证链下虚拟机中状态转换的正确性。 -零知识卷叠是“混合扩容解决方案” — 独立运行但从以太坊获得安全性的链下协议。 具体来说,以太坊网络强制执行零知识卷叠上状态更新的有效性,并保证每次更新卷叠状态时后台数据的可用性。 因此,零知识卷叠比纯链下扩容解决方案安全得多,例如负责其安全属性的[侧链](/developers/docs/scaling/sidechains/),或 [Validium](/developers/docs/scaling/validium/),它也使用有效性证明在以太坊上验证交易但将交易数据存储在别处。 +零知识卷叠是“混合扩容解决方案” — 独立运行但从以太坊获得安全性的链下协议。 具体来说,以太坊网络强制执行零知识卷叠上状态更新的有效性,并保证每次更新卷叠状态时后台数据的可用性。 因此,零知识卷叠比纯脱链扩容解决方案安全得多,例如负责其安全属性的[侧链](/developers/docs/scaling/sidechains/),或 [validiums](/developers/docs/scaling/validium/),后者也使用有效性证明在以太坊上验证交易,但将交易数据存储在别处。 零知识卷叠依赖以太坊主协议获得: @@ -46,7 +45,7 @@ lang: zh 以太坊充当零知识卷叠的结算层:只有当一层网络合约接受有效性证明时,二层网络交易才会最终确定。 这就化解了恶意运营商破坏链的风险(例如,窃取卷叠资金),因为每笔交易都必须在主网上得到批准。 此外,以太坊保证一旦在一层网络上最终确定后,用户操作就不能被逆转。 -### 抗审查 {#censorship-resistance} +### 抗审查性 {#censorship-resistance} 大多数零知识卷叠使用“超级节点”(运营商)来执行交易、生产批次并将区块提交到一层网络。 尽管这样做保证了效率,但也增加了审查风险:恶意零知识卷叠运营商可以通过拒绝将用户的交易添加到批次中来审查用户。 @@ -62,17 +61,17 @@ lang: zh #### 零知识卷叠如何在以太坊上发布交易数据 {#how-zk-rollups-publish-transaction-data-on-ethereum} -如前所述,交易数据作为 `calldata` 发布到以太坊上。 `calldata` 是智能合约中的数据区,用于将参数传递给函数,其行为类似于[内存](/developers/docs/smart-contracts/anatomy/#memory)。 虽然 `calldata` 不存储到以太坊状态中,但它作为以太坊链[历史日志](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html?highlight=memory#logs)的一部分一直存在于链上。 `calldata` 不会影响以太坊的状态,使其成为一种在链上存储数据的实惠方式。 +如前所述,交易数据作为 `calldata` 发布到以太坊上。 `calldata` 是智能合约中的一个数据区域,用于向函数传递参数,其行为与[内存](/developers/docs/smart-contracts/anatomy/#memory)类似。 虽然 `calldata` 不作为以太坊状态的一部分存储,但它会作为以太坊链[历史日志](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html?highlight=memory#logs)的一部分永久保存在链上。 `calldata` 不会影响以太坊的状态,这使其成为一种在链上存储数据的廉价方式。 `calldata` 关键字通常标识交易调用的智能合约方法,并以任意字节序列的形式保存该方法的输入。 零知识卷叠使用 `calldata` 将压缩的交易数据发布到链上;卷叠运营商只需通过调用卷叠合约中所需的函数来添加一个新批次,并将压缩数据作为函数参数传递。 这有助于降低用户的成本,因为大部分卷叠费用用于在链上存储交易数据。 ### 状态承诺 {#state-commitments} -零知识卷叠的状态包括二层网络帐户和余额,用[默克尔树](/whitepaper/#merkle-trees)表示。 默克尔树根(默克尔根)的加密哈希存储在链上合约中,让卷叠协议可以跟踪零知识卷叠状态的变化。 +零知识卷叠的状态(包括二层帐户和余额)用[默克尔树](/whitepaper/#merkle-trees)表示。 默克尔树根(默克尔根)的加密哈希存储在链上合约中,让卷叠协议可以跟踪零知识卷叠状态的变化。 在执行一组新交易后,卷叠交易转换到新状态。 发起状态转换的运营商需要计算一个新的状态根并提交到链上合约。 如果与批次相关的有效性证明通过验证者合约的身份验证,则新默克尔根将成为零知识卷叠的规范状态根。 -除了计算状态根之外,零知识卷叠运营商还创建了一个批处理根 — 包含批处理中所有交易的默克尔树的根。 当提交新批次时,卷叠合约存储批次根,允许用户证明交易(例如,提款请求)包含在批次中。 用户必须提供交易详情、批次根和显示包含路径的 [Merkle 证明](/developers/tutorials/merkle-proofs-for-offline-data-integrity/)。 +除了计算状态根之外,零知识卷叠运营商还创建了一个批处理根 — 包含批处理中所有交易的默克尔树的根。 当提交新批次时,卷叠合约存储批次根,允许用户证明交易(例如,提款请求)包含在批次中。 用户必须提供交易详情、批次根和显示包含路径的[默克尔证明](/developers/tutorials/merkle-proofs-for-offline-data-integrity/)。 ### 有效性证明 {#validity-proofs} @@ -80,31 +79,31 @@ lang: zh 但是,在运营商证明新默克尔根是由卷叠状态的正确更新产生之前,卷叠合约不会自动接受提出的状态承诺。 零知识卷叠运营商通过生成有效性证明来做到这一点,有效性证明是一种简单的加密承诺,用于验证批量交易的正确性。 -有效性证明允许参与方在不透露陈述本身的情况下证明陈述的正确性 — 因此,它们又称为零知识证明。 零知识卷叠使用有效性证明确认链下状态转换的正确性,而无需在以太坊上重新执行交易。 这些证明可以有 [ZK-SNARK](https://arxiv.org/abs/2202.06877)(零知识简洁非交互式知识论证)或 [ZK-STARK](https://eprint.iacr.org/2018/046)(零知识可扩容透明知识论证)两种形式。 +有效性证明允许参与方在不透露陈述本身的情况下证明陈述的正确性 — 因此,它们又称为零知识证明。 零知识卷叠使用有效性证明确认链下状态转换的正确性,而无需在以太坊上重新执行交易。 这些证明可以采用 [ZK-SNARK](https://arxiv.org/abs/2202.06877)(零知识简洁非交互式知识论证)或 [ZK-STARK](https://eprint.iacr.org/2018/046)(零知识可扩展透明知识论证)的形式。 SNARK 和 STARK 都有助于证明零知识卷叠中链下计算的完整性,尽管每种证明类型都有不同的特征。 -**零知识简洁非交互式知识论证 (ZK-SNARK)** +**ZK-SNARKs** 为了让 ZK-SNARK 协议起作用,必须创建公共参考字符串 (CRS),公共参考字符串提供公共参数来证明和验证有效性证明。 证明系统的安全性取决于公共参考字符串设置;如果用于创建公共参数的信息落入恶意行为者手中,他们可能会生成虚假的有效性证明。 -一些零知识卷叠尝试通过采用[多方计算仪式 (MPC)](https://zkproof.org/2021/06/30/setup-ceremonies/amp/) 解决这一问题,即让受信任个人为 ZK-SNARK 线路生成公共参数。 每一方都提供一些随机性(称为“有毒废物”)来构建公共参考字符串,而且必须立即将其销毁。 +一些零知识卷叠尝试通过采用[多方计算仪式 (MPC)](https://zkproof.org/2021/06/30/setup-ceremonies/amp/) 解决这一问题,该仪式涉及受信任的个人,为 ZK-SNARK 电路生成公共参数。 每一方都提供一些随机性(称为“有毒废物”)来构建公共参考字符串,而且必须立即将其销毁。 使用受信任的设置,因为它们提高了公共参考字符串设置的安全性。 只要诚实参与者销毁其输入,ZK-SNARK 系统的安全性就得到了保证。 这种方法仍然需要信任相关人员删除他们抽样的随机性,并且不会破坏系统的安全保障。 撇开信任假设不谈,ZK-SNARK 因其更小的证明大小和恒定时间验证而广受欢迎。 由于运行零知识卷叠的较大一部分成本用于一层网络上的证明验证,因此二层网络使用 ZK-SNARK 生成可在主网上快速、经济实惠地验证的证明。 -**零知识可扩容透明知识论证 (ZK-STARK)** +**ZK-STARKs** 与 ZK-SNARK 一样,ZK-STARK 证明链下计算的有效性而不会透露输入。 然而,ZK-STARK 被认为是对 ZK-SNARK 的改进,因为前者具有可扩展性和透明性。 ZK-STARK 是“透明的”,因为无需受信任的公共参考字符串 (CRS) 设置,它们就可以工作。 然而,ZK-STARK 依靠可公开验证的随机性来设置用于生成和验证证明的参数。 -ZK-STARK 还提供了更强的可扩展性,因为证明和验证有效性证明所需的时间相对于底层计算的复杂性呈_准线性_增加。 对于 ZK-SNARK,证明和验证时间相对于底层计算的规模呈_线性_增加。 这意味着在涉及大型数据集时,ZK-STARK 比 ZK-SNARK 的证明和验证时间更少,这使得前者适用于大批量应用。 +ZK-STARK 还提供了更强的可扩展性,因为证明和验证有效性证明所需的时间,会随着底层计算的复杂性呈_准线性_增加。 对于 ZK-SNARK,证明和验证时间会随着底层计算的规模呈_线性_增加。 这意味着在涉及大型数据集时,ZK-STARK 比 ZK-SNARK 的证明和验证时间更少,这使得前者适用于大批量应用。 ZK-STARK 对于量子计算机也是安全的,而 ZK-SNARK 中使用的椭圆曲线密码学 (ECC) 被广泛认为容易受到量子计算攻击。 ZK-STARK 的缺点是它们产生的证明尺寸更大,在以太坊上验证的成本更高。 -#### 有效性证明如何在零知识卷叠中运作? {#validity-proofs-in-zk-rollups} +#### 有效性证明如何在零知识卷叠中运作? 零知识卷叠中的有效性证明 {#validity-proofs-in-zk-rollups} ##### 证明生成 @@ -136,13 +135,13 @@ ZK-STARK 对于量子计算机也是安全的,而 ZK-SNARK 中使用的椭圆 在证明线路验证状态更新的正确性后,二层网络运营商将计算出的有效性证明提交给一层网络上的验证者合约。 合约的验证线路验证证明的有效性,并检查证明中包含的公共输入: -- **前状态根**:零知识卷叠的旧状态根(在执行交易批次之前),表示二层网络链的前一个已知有效状态。 +- **前状态根**:零知识卷叠的旧状态根(即在执行批处理交易前),反映了二层链上一个已知的有效状态。 -- **后状态根**:零知识卷叠的新状态根(执行交易批次之后),表示二层网络链的最新状态。 后状态根是在证明线路中应用状态更新后产生的最终根。 +- **后状态根**:零知识卷叠的新状态根(即在执行批处理交易后),反映了二层链的最新状态。 后状态根是在证明线路中应用状态更新后产生的最终根。 -- **批处理根**:批次的默克尔根,通过_默克尔化_批次中的交易并对树根进行哈希处理得到。 +- **批次根**:批次的默克尔根,通过对批次中的交易进行_默克尔化_并对树根进行哈希运算而得出。 -- **交易输入**:与在已提交批次中执行的交易相关的数据。 +- **交易输入**:与作为已提交批次的一部分执行的交易所关联的数据。 如果证明符合线路条件(即证明是有效的),则意味着存在一系列有效交易,这些交易将卷叠从先前状态(由前状态根提供加密指纹)转换到新状态(由后状态根提供加密指纹)。 如果前状态根与存储在卷叠合约中的根匹配,并且证明是有效的,则卷叠合约从证明中获取后状态根并更新其状态树以反映卷叠的状态变化。 @@ -164,11 +163,11 @@ ZK-STARK 对于量子计算机也是安全的,而 ZK-SNARK 中使用的椭圆 卷叠合约对交易数据进行哈希处理,检查批处理根是否存在,并使用默克尔证明检查交易哈希是否是批处理根的一部分。 之后,合约执行退出交易并将资金发送到用户选择的一层网络上的地址。 -## 零知识卷叠和以太坊虚拟机的兼容性 {#zk-rollups-and-evm-compatibility} +## 零知识卷叠和 EVM 兼容性 {#zk-rollups-and-evm-compatibility} -与乐观卷叠不同,零知识卷叠不直接与[以太坊虚拟机 (EVM)](/developers/docs/evm/) 兼容。 在线路中证明通用以太坊虚拟机计算比证明简单计算(如前面描述的代币转账),更加困难且更加耗费资源。 +与乐观卷叠不同,零知识卷叠不易与[以太坊虚拟机 (EVM)](/developers/docs/evm/) 兼容。 在线路中证明通用以太坊虚拟机计算比证明简单计算(如前面描述的代币转账),更加困难且更加耗费资源。 -然而,[零知识技术的进步](https://hackmd.io/@yezhang/S1_KMMbGt#Why-possible-now)重新点燃了将以太坊虚拟机计算封装在零知识证明中的兴趣。 这些努力旨在创建一个零知识以太坊虚拟机 (zkEVM) 实现,它可以高效验证程序执行的正确性。 零知识以太坊虚拟机重新创建在线路中进行证明/验证的现有以太坊虚拟机操作码,从而允许执行智能合约。 +然而,[零知识技术的进步](https://hackmd.io/@yezhang/S1_KMMbGt#Why-possible-now)正重新点燃人们将 EVM 计算封装于零知识证明的兴趣。 这些努力旨在创建一个零知识以太坊虚拟机 (zkEVM) 实现,它可以高效验证程序执行的正确性。 零知识以太坊虚拟机重新创建在线路中进行证明/验证的现有以太坊虚拟机操作码,从而允许执行智能合约。 与以太坊虚拟机一样,零知识以太坊虚拟机在对某些输入执行计算之后在状态之间转换。 差别在于零知识以太坊虚拟机还创建了零知识证明,验证程序执行中每一步的正确性。 有效性证明可以验证影响虚拟机状态(内存、堆栈、存储)和计算本身的操作的正确性(即,操作是否调用了正确的操作码并正确执行它们?)。 @@ -178,21 +177,21 @@ ZK-STARK 对于量子计算机也是安全的,而 ZK-SNARK 中使用的椭圆 用户为零知识卷叠上的交易支付多少费用取决于燃料费用,就像在以太坊主网上一样。 但是,燃料费用在二层网络上的运作方式不同,并受以下费用影响: -1. **状态写入**:写入以太坊状态(即在以太坊区块链上提交交易)有固定费用。 零知识卷叠通过批量处理交易并将固定费用分摊给多名用户来降低该费用。 +1. **状态写入**:写入以太坊状态(即在以太坊区块链上提交交易)有固定成本。 零知识卷叠通过批量处理交易并将固定费用分摊给多名用户来降低该费用。 -2. **数据发布**:零知识卷叠将每笔交易的状态数据作为 `calldata` 发布到以太坊。 `calldata` 费用目前由 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 监管,它规定对于 `calldata` 的非零字节和零字节费用分别为 16 单位和 4 单位燃料。 每笔交易支付的费用受需要在链上为其发布多少 `calldata` 的影响。 +2. **数据发布**:零知识卷叠将每笔交易的状态数据作为 `calldata` 发布到以太坊。 `calldata` 成本目前由 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 决定,其中规定 `calldata` 的每个非零字节成本为 16 单位燃料,每个零字节为 4 单位燃料。 每笔交易支付的成本受需要为其在链上发布多少 `calldata` 的影响。 -3. **二层网络运营商费用**:这是支付给卷叠运营商的金额,用于补偿处理交易产生的计算费用,很像以太坊主网上的[交易“优先费(小费)”](/developers/docs/gas/#how-are-gas-fees-calculated)。 +3. **二层运营商费用**:这是支付给卷叠运营商的金额,作为处理交易所产生计算成本的补偿,与以太坊主网上的[交易“优先费(小费)”](/developers/docs/gas/#how-are-gas-fees-calculated)非常相似。 -4. **证明生成和验证**:零知识卷叠运营商必须为交易批次生成有效性证明,该操作耗费大量资源。 在主网上验证零知识证明也需要花费燃料(约 500,000 单位燃料)。 +4. **证明生成和验证**:零知识卷叠运营商必须为交易批次生成有效性证明,这项工作是资源密集型的。 在主网上验证零知识证明也需要花费燃料(约 500,000 单位燃料)。 -除了批量处理交易之外,零知识卷叠通过压缩交易数据降低用户的费用。 你可以[查看实时概览](https://l2fees.info/),了解使用以太坊零知识卷叠的费用。 +除了批量处理交易之外,零知识卷叠通过压缩交易数据降低用户的费用。 你可以[查看实时概览](https://l2fees.info/),了解使用以太坊零知识卷叠的成本。 -## 零知识卷叠如何扩展以太坊? {#scaling-ethereum-with-zk-rollups} +## 零知识卷叠如何扩展以太坊? 使用零知识卷叠扩容以太坊 {#scaling-ethereum-with-zk-rollups} ### 交易数据压缩 {#transaction-data-compression} -零知识卷叠通过在链下计算来提升以太坊基础层的吞吐量,但真正提升扩容的是压缩交易数据。 以太坊的[区块大小](/developers/docs/blocks/#block-size)限制了每个区块可以保存的数据,进而限制了每个区块处理的交易数量。 通过压缩交易相关数据,零知识卷叠显著增加了每个区块处理的交易数量。 +零知识卷叠通过在链下计算来提升以太坊基础层的吞吐量,但真正提升扩容的是压缩交易数据。 以太坊的[区块大小](/developers/docs/blocks/#block-size)限制了每个区块可以容纳的数据量,并因此限制了每个区块处理的交易数量。 通过压缩交易相关数据,零知识卷叠显著增加了每个区块处理的交易数量。 零知识卷叠能够比乐观卷叠更好地压缩交易数据,因为它们不必发布验证每笔交易所需的所有数据。 它们只需要发布在卷叠上重建帐户和余额的最新状态所需的最少量数据。 @@ -206,49 +205,52 @@ ZK-STARK 对于量子计算机也是安全的,而 ZK-SNARK 中使用的椭圆 ### 零知识卷叠的优缺点 {#zk-rollups-pros-and-cons} -| 优点 | 缺点 | -| --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | -| 有效性证明确保链下交易的正确性,并阻止运营商执行无效的状态转换。 | 与计算和验证有效性证明相关的成本很高,并且可能会增加卷叠用户的费用。 | -| 一旦在一层网络上验证了有效性证明,在批准状态更新后,交易的最终确定更快。 | 由于零知识技术的复杂性,构建与以太坊虚拟机兼容的零知识卷叠很困难。 | -| 依靠去信任加密机制来保证安全性,而不是像[乐观卷叠](/developers/docs/scaling/optimistic-rollups/#optimistic-pros-and-cons)那样依靠受激励参与者的诚信。 | 生成有效性证明需要专用硬件,这可能会鼓励一些参与方对链进行集中控制。 | -| 将恢复链下状态所需的数据存储在一层网络上,从而保证安全性、抗审查性和去中心化。 | 中心化运营商(排序者)可以影响交易的顺序。 | -| 用户可以从更高的资本效率中受益,并且可以毫无拖延地从二层网络中提取资金。 | 硬件要求可能会减少能够强制推进链状态的参与者数量,从而增加恶意运营商冻结卷叠状态和审查用户的风险。 | -| 不依赖于可用性假设,用户不必验证链来保护他们的资金。 | 一些证明系统(例如 ZK-SNARK)需要受信任的设置,如果处理不当,可能会危及零知识卷叠的安全模型。 | -| 更好的数据压缩有助于降低在以太坊上发布 `calldata` 的成本,并最大限度地减少用户的卷叠费用。 | | +| 优点 | 缺点 | +| -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | +| 有效性证明确保链下交易的正确性,并阻止运营商执行无效的状态转换。 | 与计算和验证有效性证明相关的成本很高,并且可能会增加卷叠用户的费用。 | +| 一旦在一层网络上验证了有效性证明,在批准状态更新后,交易的最终确定更快。 | 由于零知识技术的复杂性,构建与以太坊虚拟机兼容的零知识卷叠很困难。 | +| 依靠免信任的加密机制来保障安全,而非像[乐观卷叠](/developers/docs/scaling/optimistic-rollups/#optimistic-pros-and-cons)那样依赖受激励行动者的诚信。 | 生成有效性证明需要专用硬件,这可能会鼓励一些参与方对链进行集中控制。 | +| 将恢复链下状态所需的数据存储在一层网络上,从而保证安全性、抗审查性和去中心化。 | 中心化运营商(排序者)可以影响交易的顺序。 | +| 用户可以从更高的资本效率中受益,并且可以毫无拖延地从二层网络中提取资金。 | 硬件要求可能会减少能够强制推进链状态的参与者数量,从而增加恶意运营商冻结卷叠状态和审查用户的风险。 | +| 不依赖于可用性假设,用户不必验证链来保护他们的资金。 | 一些证明系统(例如 ZK-SNARK)需要受信任的设置,如果处理不当,可能会危及零知识卷叠的安全模型。 | +| 更好的数据压缩有助于降低在以太坊上发布 `calldata` 的成本,并最大限度地减少用户的卷叠费用。 | | -### 零知识卷叠的直观解释 {#zk-video} +### 零知识卷叠的视频解说 {#zk-video} 观看 Finematics 解说零知识卷叠: - -## 零知识以太坊虚拟机上有哪些项目? {#zkevm-projects} +## 零知识以太坊虚拟机上有哪些项目? zkEVM 项目 {#zkevm-projects} 零知识以太坊虚拟机上运行的项目包括: -- **[zkEVM](https://github.com/privacy-scaling-explorations/zkevm-specs)** - _zkEVM 是由以太坊基金会资助的项目,旨在开发与以太坊虚拟机兼容的零知识卷叠以及为以太坊区块生成有效性证明的机制。_ +- **[zkEVM](https://github.com/privacy-scaling-explorations/zkevm-specs)** - _zkEVM 是由以太坊基金会资助的项目,旨在开发与 EVM 兼容的零知识卷叠,以及为以太坊区块生成有效性证明的机制。_ + +- **[Polygon zkEVM](https://polygon.technology/solutions/polygon-zkevm)** - _一个在以太坊主网上运行的去中心化零知识卷叠,它在零知识以太坊虚拟机 (zkEVM) 上工作,以透明的方式执行以太坊交易,包括带零知识证明验证的智能合约。_ -- **[Polygon zkEVM](https://polygon.technology/solutions/polygon-zkevm)** - _是以太坊主网上的去中心化零知识卷叠,它在零知识以太坊虚拟机 (zkEVM) 上运行,以透明的方式执行以太坊交易,包括智能合约与零知识证明验证。_ +- **[Scroll](https://scroll.io/blog/zkEVM)** - _Scroll 是一家技术驱动型公司,致力于为以太坊构建原生的 zkEVM 二层解决方案。_ -- **[Scroll](https://scroll.io/blog/zkEVM)** - _Scroll 是 一家致力于为以太坊构建原生零知识以太坊虚拟机二层解决方案的技术驱动型公司。_ +- **[Taiko](https://taiko.xyz)** - _Taiko 是一个去中心化、与以太坊等效的零知识卷叠(一种[第 1 类 ZK-EVM](https://vitalik.eth.limo/general/2022/08/04/zkevm.html))。_ -- **[Taiko](https://taiko.xyz)** - _Taiko 是一个去中心化、类似以太坊的零知识卷叠(一种[第一类零知识以太坊虚拟机](https://vitalik.eth.limo/general/2022/08/04/zkevm.html))。_ +- **[ZKsync](https://docs.zksync.io/)** - _ZKsync Era 是一个与 EVM 兼容的零知识卷叠,由 Matter Labs 构建,并由其自己的 zkEVM 提供支持。_ -- **[ZKsync](https://docs.zksync.io/)** - _ZKsync Era 是与以太坊虚拟机兼容的零知识卷叠,由 Matter Labs 构建并由它自己的 zkEVM 提供支持。_ +- **[Starknet](https://starkware.co/starknet/)** - _StarkNet 是一个与 EVM 兼容的二层扩容解决方案,由 StarkWare 构建。_ -- **[Starknet](https://starkware.co/starknet/)** - _StarkNet 是以太坊虚拟机兼容的二层网络扩容解决方案,由 StarkWare 构建。_ +- **[Morph](https://www.morphl2.io/)** - _Morph 是一个混合式卷叠扩容解决方案,利用零知识证明来解决二层状态挑战问题。_ -- **[Morph](https://www.morphl2.io/)** - _Morph 是利用零知识证明来解决二层网络状态质询问题的混合卷叠扩容解决方案。_ +- **[Linea](https://linea.build)** - _Linea 是由 Consensys 构建、与以太坊等效的 zkEVM 二层网络,完全与以太坊生态系统保持一致。_ -## 进一步阅读零知识卷叠的相关内容 {#further-reading-on-zk-rollups} +## 关于零知识卷叠的延伸阅读 {#further-reading-on-zk-rollups} - [什么是零知识卷叠?](https://coinmarketcap.com/alexandria/glossary/zero-knowledge-rollups) - [什么是零知识卷叠?](https://alchemy.com/blog/zero-knowledge-rollups) -- [STARK(可扩容透明知识论证)和 SNARK(简洁非交互式知识论证)](https://consensys.net/blog/blockchain-explained/zero-knowledge-proofs-starks-vs-snarks/) -- [什么是 zkEVM(零知识以太坊虚拟机)?](https://www.alchemy.com/overviews/zkevm) -- [零知识以太坊虚拟机类型:以太坊等效、以太坊虚拟机等效、类型 1、类型 4 和其他晦涩的术语](https://taiko.mirror.xyz/j6KgY8zbGTlTnHRFGW6ZLVPuT0IV0_KmgowgStpA0K4) -- [zkEVM(零知识以太坊虚拟机)简介](https://hackmd.io/@yezhang/S1_KMMbGt) -- [超赞的 zkEVM(零知识以太坊虚拟机)资源](https://github.com/LuozhuZhang/awesome-zkevm) -- [ZK-SNARK(零知识简洁非交互式知识论证)底层技术](https://vitalik.eth.limo/general/2017/02/01/zk_snarks.html) -- [SNARK(简洁非交互式知识论证),怎么可能?](https://vitalik.eth.limo/general/2021/01/26/snarks.html) +- [以太坊卷叠实用指南](https://web.archive.org/web/20241108192208/https://research.2077.xyz/the-practical-guide-to-ethereum-rollups) +- [STARK 与 SNARK 对比](https://consensys.net/blog/blockchain-explained/zero-knowledge-proofs-starks-vs-snarks/) +- [什么是 zkEVM?](https://www.alchemy.com/overviews/zkevm) +- [ZK-EVM 类型:以太坊等效、EVM 等效、类型 1、类型 4 和其他神秘的流行语](https://taiko.mirror.xyz/j6KgY8zbGTlTnHRFGW6ZLVPuT0IV0_KmgowgStpA0K4) +- [zkEVM 简介](https://hackmd.io/@yezhang/S1_KMMbGt) +- [什么是 ZK-EVM L2?](https://linea.mirror.xyz/qD18IaQ4BROn_Y40EBMTUTdJHYghUtdECscSWyMvm8M) +- [zkEVM 精选资源](https://github.com/LuozhuZhang/awesome-zkevm) +- [ZK-SNARKs 原理](https://vitalik.eth.limo/general/2017/02/01/zk_snarks.html) +- [SNARK 如何成为可能?](https://vitalik.eth.limo/general/2021/01/26/snarks.html) diff --git a/public/content/translations/zh/developers/docs/smart-contracts/anatomy/index.md b/public/content/translations/zh/developers/docs/smart-contracts/anatomy/index.md index 26ecc0ce1e3..7df056b26d6 100644 --- a/public/content/translations/zh/developers/docs/smart-contracts/anatomy/index.md +++ b/public/content/translations/zh/developers/docs/smart-contracts/anatomy/index.md @@ -1,6 +1,6 @@ --- -title: 详解智能合约 -description: 深入解读智能合约:函数、数据和变量。 +title: "详解智能合约" +description: "深入解读智能合约:函数、数据和变量。" lang: zh --- @@ -8,20 +8,20 @@ lang: zh ## 前提条件 {#prerequisites} -确保你已经先阅读了[智能合约](/developers/docs/smart-contracts/)。 本文档假设你已经熟悉某种编程语言,例如 JavaScript 或 Python。 +请先确保您已阅读[智能合约](/developers/docs/smart-contracts/)的相关信息。 本文档假设你已经熟悉某种编程语言,例如 JavaScript 或 Python。 ## 数据 {#data} -任何合约数据必须分配到一个位置:要么是`存储`,要么是`内存`。 在智能合约中修改存储消耗很大,因此你需要考虑数据在哪里存取。 +任何合约数据都必须分配到一个位置:`storage` 或 `memory`。 在智能合约中修改存储消耗很大,因此你需要考虑数据在哪里存取。 ### 存储 {#storage} 持久性数据被称之为存储,由状态变量表示。 这些值被永久地存储在区块链上。 你需要声明一个类型,以便于合约在编译时可以跟踪它在区块链上需要多少存储。 ```solidity -// Solidity example +// Solidity 示例 contract SimpleStorage { - uint storedData; // State variable + uint storedData; // 状态变量 // ... } ``` @@ -33,7 +33,7 @@ storedData: int128 如果用过面向对象编程语言,应该会熟悉大多数类型。 但如果是刚接触以太坊开发,则会发现 `address` 是一个新类型。 -一个 `address` 类型可以容纳一个以太坊地址,相当于 20 个字节或 160 位。 它以十六进制的形式返回,前导是 0x。 +`address` 类型可以容纳一个以太坊地址,相当于 20 字节或 160 位。 它以十六进制的形式返回,前导是 0x。 其它类型包括: @@ -41,33 +41,33 @@ storedData: int128 - 整数(integer) - 定点数(fixed point numbers) - 固定大小的字节数组(fixed-size byte arrays) -- 动态大小的字节数组(dynamically-sized byte arrays) -- 有理数和整数常量(Rational and integer literals) -- 字符常量(String literals) -- 十六进制常量(Hexadecimal literals) -- 枚举(Enums) +- 动态大小字节数组 +- 有理数和整数字面量 +- 字符串字面量 +- 十六进制字面量 +- 枚举 了解更多信息,请参阅文档: -- [查看 Vyper 类型](https://vyper.readthedocs.io/en/v0.1.0-beta.6/types.html#value-types) -- [查看 Solidity 类型](https://solidity.readthedocs.io/en/latest/types.html#value-types) +- [查看 Vyper 类型](https://docs.vyperlang.org/en/v0.1.0-beta.6/types.html#value-types) +- [查看 Solidity 类型](https://docs.soliditylang.org/en/latest/types.html#value-types) ### 内存 {#memory} 仅在合约函数执行期间存储的值被称为内存变量。 由于这些变量不是永久地存储在区块链上,所以它们的使用成本要低得多。 -在 [Solidity 文档](https://solidity.readthedocs.io/en/latest/introduction-to-smart-contracts.html?highlight=memory#storage-memory-and-the-stack)中了解更多关于以太坊虚拟机如何存储数据(存储、内存和栈)。 +在 [Solidity 文档](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html#storage-memory-and-the-stack)中了解更多关于 EVM 如何存储数据(存储、内存和堆栈)的信息。 ### 环境变量 {#environment-variables} 除了在自己合约上定义的变量之外,还有一些特殊的全局变量。 它们主要用于提供有关区块链或当前交易的信息。 -示例: +例子: -| **属性** | **状态变量** | **描述** | -| ----------------- | -------- | ------------ | -| `block.timestamp` | uint256 | 当前区块的时间戳 | -| `msg.sender` | 地址 | 消息的发送者(当前调用) | +| **属性** | **状态变量** | **描述** | +| ------- | -------- | ------------ | +| `区块时间戳` | uint256 | 当前区块的时间戳 | +| `发送者` | 地址 | 消息的发送者(当前调用) | ## 函数 {#functions} @@ -75,15 +75,15 @@ storedData: int128 有两种函数调用方式: -- `internal` – 不会创建以太坊虚拟机调用 - - Internal 函数和状态变量只能在内部访问(只能在合约内部或者从其继承的合约内部访问)。 -- `external` – 会创建以太坊虚拟机调用 - - External 函数是合约接口的一部分,这意味着他可以被其它合约和交易调用。 一个 external 函数 `f` 不可以被内部调用(即 `f()` 不行,但 `this.f()` 可以)。 +- `internal` – 不会创建 EVM 调用 + - 内部函数和状态变量只能在内部访问(即从当前合约或其派生合约中访问) +- `external` – 会创建 EVM 调用 + - External 函数是合约接口的一部分,这意味着他可以被其它合约和交易调用。 外部函数 `f` 不能在内部调用(即 `f()` 不起作用,但 `this.f()` 可以)。 -它们可以是 `public` 或 `private` +它们也可以是 `public` 或 `private` -- `public` 函数可以在合约内部调用或者通过消息在合约外部调用 -- `private` 函数仅在其被定义的合约内部可见,并且在该合约的派生合约中不可见。 +- `public` 函数可以从合约内部调用,也可以通过消息从外部调用 +- `private` 函数仅在定义它们的合约中可见,在其派生合约中不可见 函数和状态变量都可以被定义为 public 或 private @@ -96,9 +96,9 @@ function update_name(string value) public { } ``` -- `string` 类型的参数 `value` 传入函数 `update_name` -- 函数声明为 `public`,意味着任何人都能访问它 -- 函数没有被声明为 `view`,因此它可以修改合约状态 +- 类型为 `string` 的参数 `value` 被传递到函数 `update_name` +- 它被声明为 `public`,意味着任何人都可以访问它 +- 它没有声明为 `view`,所以可以修改合约状态 ### 视图函数 {#view-functions} @@ -123,25 +123,26 @@ def readName() -> string: 这些操作被视为修改状态: 1. 写入状态变量。 -2. [正在导出事件](https://solidity.readthedocs.io/en/v0.7.0/contracts.html#events)。 -3. [创建其它合约](https://solidity.readthedocs.io/en/v0.7.0/control-structures.html#creating-contracts)。 -4. 使用 `selfdestruct`。 +2. [触发事件](https://docs.soliditylang.org/en/v0.7.0/contracts.html#events)。 +3. [创建其他合约](https://docs.soliditylang.org/en/v0.7.0/control-structures.html#creating-contracts)。 +4. 使用 `selfdestruct`。 5. 通过调用发送 ether。 -6. 调用任何未标记为 `view` 或 `pure` 的函数。 +6. 调用任何未标记 `view` 或 `pure` 的函数。 7. 使用底层调用。 8. 使用包含某些操作码的内联程序组。 ### 构造函数 {#constructor-functions} -`constructor` 函数只在首次部署合约时执行一次。 与许多基于类的编程语言中的 `constructor` 函数类似,这些函数常将状态变量初始化到指定的值。 +`constructor` 函数仅在首次部署合约时执行一次。 与许多基于类的编程语言中的 `constructor` 一样,这些函数通常会将状态变量初始化为其指定值。 ```solidity // Solidity 示例 -// 初始化合约数据,设置 `owner`为合约的创建者。 +// 初始化合约的数据,将“所有者” +// 设置为合约创建者的地址。 constructor() public { - // 所有智能合约依赖外部交易来触发其函数。 - // `msg` 是一个全局变量,包含了给定交易的相关数据, - // 例如发送者的地址和交易中包含的 ETH 数量。 + // 所有智能合约都依靠外部交易来触发其函数。 + // `msg` 是一个全局变量,包含给定交易的相关数据, + // 例如发送者的地址和交易中包含的 ETH 值。 // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties owner = msg.sender; } @@ -179,65 +180,66 @@ def __init__(_beneficiary: address, _bidding_time: uint256): pragma solidity >=0.4.0 <=0.6.0; contract ExampleDapp { - string dapp_name; // state variable + string dapp_name; // 状态变量 - // Called when the contract is deployed and initializes the value + // 在部署合约并初始化其值时调用 constructor() public { - dapp_name = "My Example dapp"; + dapp_name = "我的示例 dapp"; } - // Get Function + // Get 函数 function read_name() public view returns(string) { return dapp_name; } - // Set Function + // Set 函数 function update_name(string value) public { dapp_name = value; } } ``` -一个完整的合约可能就是这样。 在这里,`constructor` 函数为 `dapp_name` 变量提供了初始化值。 +一个完整的合约可能就是这样。 这里的 `constructor` 函数为 `dapp_name` 变量提供了一个初始值。 ## 事件和日志 {#events-and-logs} 事件让你的智能合约能够与前端或其他订阅应用程序进行通信。 一旦交易被验证并添加到区块中,智能合约就可以触发事件并记录信息,然后前端就可以处理和利用这些信息。 -## 附带注解的示例 {#annotated-examples} +## 带注解的示例 {#annotated-examples} -这是一些用 Solidity 写的例子。 如果希望运行这些代码,你可以在 [Remix](http://remix.ethereum.org) 中调试。 +这是一些用 Solidity 写的例子。 如果你想体验一下这些代码,可以在 [Remix](http://remix.ethereum.org) 中与它们交互。 ### Hello world {#hello-world} ```solidity -// Specifies the version of Solidity, using semantic versioning. +// 指定 Solidity 的版本,使用语义版本控制。 // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma pragma solidity ^0.5.10; -// 定义合约名称 `HelloWorld`。 -// 一个合约是函数和数据(其状态)的集合。 -// 一旦部署,合约就会留在以太坊区块链的一个特定地址上。 -// 了解更多: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html +// 定义一个名为 `HelloWorld` 的合约。 +// 合约是函数和数据(其状态)的集合。 +// 一旦部署,合约便会存在于以太坊区块链上的一个特定地址。 +// 了解更多:https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html contract HelloWorld { - // 定义`string`类型变量 `message` - // 状态变量是其值永久存储在合约存储中的变量。 - // 关键字 `public` 使得可以从合约外部访问。 - // 并创建了一个其它合约或客户端可以调用访问该值的函数。 + // 声明一个类型为 `string` 的状态变量 `message`。 + // 状态变量是其值被永久存储在合约存储中的变量。 + // 关键字 `public` 使变量可以从合约外部访问 + // 并创建一个其他合约或客户端可以调用以访问该值的函数。 string public message; - // 类似于很多基于类的面向对象语言, - // 构造函数是仅在合约创建时执行的特殊函数。 - // 构造器用于初始化合约的数据。 + // 与许多基于类的面向对象语言类似,构造函数是 + // 一个仅在创建合约时执行的特殊函数。 + // 构造函数用于初始化合约的数据。 // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors constructor(string memory initMessage) public { - // 接受一个字符变量 `initMessage` - // 并为合约的存储变量`message` 赋值 + // 接受一个字符串参数 `initMessage` 并将该值设置 + // 到合约的 `message` 存储变量中)。 message = initMessage; } - // 一个 public 函数接受字符参数并更新存储变量 `message` + // 一个接受字符串参数并更新 `message` 存储变量的 + // public 函数。 function update(string memory newMessage) public { message = newMessage; } @@ -250,69 +252,70 @@ contract HelloWorld { pragma solidity ^0.5.10; contract Token { - // 一个 `address` 类比于邮件地址 - 它用来识别以太坊的一个帐户。 - // 地址可以代表一个智能合约或一个外部(用户)帐户。 + // `address` 类似于电子邮件地址 - 用于在以太坊上标识帐户。 + // 地址可以表示智能合约或外部(用户)帐户。 // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/types.html#address address public owner; - // `mapping` 是一个哈希表数据结构。 - // 此 `mapping` 将一个无符号整数(代币余额)分配给地址(代币持有者)。 - // 了解更多: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types + // `mapping` 本质上是一个哈希表数据结构。 + // 此 `mapping` 将一个无符号整数(代币余额)分配给一个地址(代币持有者)。 + // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types mapping (address => uint) public balances; - // 事件允许在区块链上记录活动。 - // 以太坊客户端可以监听事件,以便对合约状态更改作出反应。 - // 了解更多: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events + // 事件允许在区块链上记录活动日志。 + // 以太坊客户端可以侦听事件,以便对合约状态更改做出反应。 + // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events event Transfer(address from, address to, uint amount); - // 初始化合约数据,设置 `owner`为合约创建者的地址。 + // 初始化合约数据,将“所有者” + // 设置为合约创建者的地址。 constructor() public { - // 所有智能合约依赖外部交易来触发其函数。 - // `msg` 是一个全局变量,包含了给定交易的相关数据, - // 例如发送者的地址和包含在交易中的 ETH 数量。 + // 所有智能合约都依靠外部交易来触发其函数。 + // `msg` 是一个全局变量,包含给定交易的相关数据, + // 例如发送者地址和交易中包含的 ETH 值。 // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties owner = msg.sender; } - // 创建一些新代币并发送给一个地址。 + // 创建一定数量的新代币并将其发送到一个地址。 function mint(address receiver, uint amount) public { // `require` 是一个用于强制执行某些条件的控制结构。 - // 如果 `require` 的条件为 `false`,则异常被触发, - // 所有在当前调用中对状态的更改将被还原。 - // 学习更多: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions + // 如果 `require` 语句的计算结果为 `false`,则会触发异常, + // 这将恢复在当前调用期间对状态所做的所有更改。 + // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions - // 只有合约创建人可以调用这个函数 - require(msg.sender == owner, "You are not the owner."); + // 只有合约所有者可以调用此函数 + require(msg.sender == owner, "你不是所有者。"); // 强制执行代币的最大数量 - require(amount < 1e60, "Maximum issuance exceeded"); + require(amount < 1e60, "已超出最大发行量"); - // 将 "收款人"的余额增加"金额" + // 将 `receiver` 的余额增加 `amount` balances[receiver] += amount; } - // 从任何调用者那里发送一定数量的代币到一个地址。 + // 从任何调用者向一个地址发送一定数量的现有代币。 function transfer(address receiver, uint amount) public { - // 发送者必须有足够数量的代币用于发送 - require(amount <= balances[msg.sender], "Insufficient balance."); + // 发送者必须有足够的代币才能发送 + require(amount <= balances[msg.sender], "余额不足。"); - // 调整两个帐户的余额 + // 调整两个地址的代币余额 balances[msg.sender] -= amount; balances[receiver] += amount; - // 触发之前定义的事件。 + // 触发之前定义的事件 emit Transfer(msg.sender, receiver, amount); } } ``` -### 唯一的数字资产 {#unique-digital-asset} +### 独特的数字资产 {#unique-digital-asset} ```solidity pragma solidity ^0.5.10; -// 从其它文件向当前合约中导入符号。 -// 本例使用一系列来自 OpenZeppelin 的辅助合约。 +// 将其他文件中的符号导入当前合约。 +// 在本例中,为来自 OpenZeppelin 的一系列辅助合约。 // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol"; @@ -320,65 +323,65 @@ import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol import "../node_modules/@openzeppelin/contracts/introspection/ERC165.sol"; import "../node_modules/@openzeppelin/contracts/math/SafeMath.sol"; -// `is` 关键字用于从其它外部合约继承函数和关键字。 -// 本例中,`CryptoPizza` 继承 `IERC721` 和 `ERC165` 合约。 +// `is` 关键字用于从外部合约继承函数和关键字。 +// 在本例中,`CryptoPizza` 继承自 `IERC721` 和 `ERC165` 合约。 // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance contract CryptoPizza is IERC721, ERC165 { - // 使用 OpenZeppelin's SafeMath 库来安全执行算数操作。 + // 使用 OpenZeppelin 的 SafeMath 库安全地执行算术运算。 // 了解更多:https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath using SafeMath for uint256; - // Solidity 语言中的常量状态变量与其他语言类似。 - // 但是必须用一个表达式为常量赋值,而这个表达式本身必须在编译时是一个常量。 - // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables + // Solidity 中的常量状态变量与其他语言类似 + // 但你必须从编译时为常量的表达式中赋值。 + // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables uint256 constant dnaDigits = 10; uint256 constant dnaModulus = 10 ** dnaDigits; bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; - // Struct types let you define your own type - // Learn more: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs + // 结构类型允许你定义自己的类型 + // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/types.html#structs struct Pizza { string name; uint256 dna; } - // Creates an empty array of Pizza structs + // 创建一个空的 Pizza 结构数组 Pizza[] public pizzas; - // Mapping from pizza ID to its owner's address + // 从披萨 ID 到其所有者地址的映射 mapping(uint256 => address) public pizzaToOwner; - // Mapping from owner's address to number of owned token + // 从所有者地址到所拥有代币数量的映射 mapping(address => uint256) public ownerPizzaCount; - // Mapping from token ID to approved address + // 从代币 ID 到批准地址的映射 mapping(uint256 => address) pizzaApprovals; - // You can nest mappings, this example maps owner to operator approvals + // 你可以嵌套映射,此示例将所有者映射到操作员批准 mapping(address => mapping(address => bool)) private operatorApprovals; - // Internal function to create a random Pizza from string (name) and DNA + // 从字符串(名称)和 DNA 创建随机 Pizza 的内部函数 function _createPizza(string memory _name, uint256 _dna) - // The `internal` keyword means this function is only visible - // within this contract and contracts that derive this contract - // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters + // `internal` 关键字意味着此函数仅在此合约和派生此合约的 + // 合约中可见 + // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters internal - // `isUnique` is a function modifier that checks if the pizza already exists - // Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers + // `isUnique` 是一个函数修饰符,用于检查披萨是否已存在 + // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers isUnique(_name, _dna) { - // Adds Pizza to array of Pizzas and get id + // 将 Pizza 添加到 Pizzas 数组并获取 id uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1); - // Checks that Pizza owner is the same as current user - // Learn more: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions + // 检查 Pizza 所有者是否与当前用户相同 + // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions - // note that address(0) is the zero address, - // indicating that pizza[id] is not yet allocated to a particular user. + // 请注意,address(0) 是零地址, + // 表示 pizza[id] 尚未分配给特定用户。 assert(pizzaToOwner[id] == address(0)); - // Maps the Pizza to the owner + // 将 Pizza 映射到所有者 pizzaToOwner[id] = msg.sender; ownerPizzaCount[msg.sender] = SafeMath.add( ownerPizzaCount[msg.sender], @@ -386,37 +389,37 @@ contract CryptoPizza is IERC721, ERC165 { ); } - // Creates a random Pizza from string (name) + // 从字符串(名称)创建随机 Pizza function createRandomPizza(string memory _name) public { uint256 randDna = generateRandomDna(_name, msg.sender); _createPizza(_name, randDna); } - // Generates random DNA from string (name) and address of the owner (creator) + // 从字符串(名称)和所有者(创建者)的地址生成随机 DNA function generateRandomDna(string memory _str, address _owner) public - // Functions marked as `pure` promise not to read from or modify the state - // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions + // 标记为 `pure` 的函数保证不会读取或修改状态 + // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions pure returns (uint256) { - // Generates random uint from string (name) + address (owner) + // 从字符串(名称)+ 地址(所有者)生成随机 uint uint256 rand = uint256(keccak256(abi.encodePacked(_str))) + uint256(_owner); rand = rand % dnaModulus; return rand; } - // Returns array of Pizzas found by owner + // 返回按所有者找到的 Pizzas 数组 function getPizzasByOwner(address _owner) public - // Functions marked as `view` promise not to modify state - // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions + // 标记为 `view` 的函数保证不会修改状态 + // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions view returns (uint256[] memory) { - // Uses the `memory` storage location to store values only for the - // lifecycle of this function call. + // 使用 `memory` 存储位置来仅在此函数调用的 + // 生命周期内存储值。 // 了解更多:https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack uint256[] memory result = new uint256[](ownerPizzaCount[_owner]); uint256 counter = 0; @@ -429,28 +432,28 @@ contract CryptoPizza is IERC721, ERC165 { return result; } - // 转移 Pizza 和归属关系到其它地址 + // 将 Pizza 和所有权转移到其他地址 function transferFrom(address _from, address _to, uint256 _pizzaId) public { - require(_from != address(0) && _to != address(0), "Invalid address."); - require(_exists(_pizzaId), "Pizza does not exist."); - require(_from != _to, "Cannot transfer to the same address."); - require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved."); + require(_from != address(0) && _to != address(0), "无效地址。"); + require(_exists(_pizzaId), "披萨不存在。"); + require(_from != _to, "不能转移到相同地址。"); + require(_isApprovedOrOwner(msg.sender, _pizzaId), "地址未经批准。"); ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1); ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1); pizzaToOwner[_pizzaId] = _to; - // 触发继承自 IERC721 合约中定义的事件。 + // 触发导入的 IERC721 合约中定义的事件 emit Transfer(_from, _to, _pizzaId); _clearApproval(_to, _pizzaId); } /** - * 安全转账给定代币 ID 的所有权到其它地址 - * 如果目标地址是一个合约,则该合约必须实现 `onERC721Received`函数, - * 该函数调用了安全转账并且返回一个 magic value。 - * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; - * 否则,转账被回退。 + * 将给定代币 ID 的所有权安全地转移到另一个地址 + * 如果目标地址是合约,则它必须实现 `onERC721Received`, + * 它在安全转移时被调用,并返回 magic value + * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; + * 否则,转移将被还原。 */ function safeTransferFrom(address from, address to, uint256 pizzaId) public @@ -460,11 +463,11 @@ contract CryptoPizza is IERC721, ERC165 { } /** - * 安全转账给定代币 ID 所有权到其它地址 - * 如果目标地址是一个合约,则该合约必须实现 `onERC721Received` 函数, - * 该函数调用安全转账并返回一个 magic value - * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; - * 否则,转账被回退。 + * 将给定代币 ID 的所有权安全地转移到另一个地址 + * 如果目标地址是合约,则它必须实现 `onERC721Received`, + * 它在安全转移时被调用,并返回 magic value + * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; + * 否则,转移将被还原。 */ function safeTransferFrom( address from, @@ -473,12 +476,12 @@ contract CryptoPizza is IERC721, ERC165 { bytes memory _data ) public { this.transferFrom(from, to, pizzaId); - require(_checkOnERC721Received(from, to, pizzaId, _data), "Must implement onERC721Received."); + require(_checkOnERC721Received(from, to, pizzaId, _data), "必须实现 onERC721Received。"); } /** - * Internal function to invoke `onERC721Received` on a target address - * The call is not executed if the target address is not a contract + * 在目标地址上调用 `onERC721Received` 的内部函数 + * 如果目标地址不是合约,则不执行调用 */ function _checkOnERC721Received( address from, @@ -499,13 +502,13 @@ contract CryptoPizza is IERC721, ERC165 { return (retval == _ERC721_RECEIVED); } - // Burns a Pizza - destroys Token completely - // The `external` function modifier means this function is - // part of the contract interface and other contracts can call it + // 销毁一个 Pizza - 完全销毁代币 + // `external` 函数修饰符表示此函数是 + // 合约接口的一部分,其他合约可以调用它 function burn(uint256 _pizzaId) external { - require(msg.sender != address(0), "Invalid address."); - require(_exists(_pizzaId), "Pizza does not exist."); - require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved."); + require(msg.sender != address(0), "无效地址。"); + require(_exists(_pizzaId), "披萨不存在。"); + require(_isApprovedOrOwner(msg.sender, _pizzaId), "地址未经批准。"); ownerPizzaCount[msg.sender] = SafeMath.sub( ownerPizzaCount[msg.sender], @@ -514,58 +517,58 @@ contract CryptoPizza is IERC721, ERC165 { pizzaToOwner[_pizzaId] = address(0); } - // Returns count of Pizzas by address + // 按地址返回 Pizzas 的数量 function balanceOf(address _owner) public view returns (uint256 _balance) { return ownerPizzaCount[_owner]; } - // Returns owner of the Pizza found by id + // 按 id 返回找到的 Pizza 的所有者 function ownerOf(uint256 _pizzaId) public view returns (address _owner) { address owner = pizzaToOwner[_pizzaId]; - require(owner != address(0), "Invalid Pizza ID."); + require(owner != address(0), "无效披萨 ID。"); return owner; } - // Approves other address to transfer ownership of Pizza + // 批准其他地址转移 Pizza 的所有权 function approve(address _to, uint256 _pizzaId) public { - require(msg.sender == pizzaToOwner[_pizzaId], "Must be the Pizza owner."); + require(msg.sender == pizzaToOwner[_pizzaId], "必须是披萨所有者。"); pizzaApprovals[_pizzaId] = _to; emit Approval(msg.sender, _to, _pizzaId); } - // Returns approved address for specific Pizza + // 返回特定 Pizza 的批准地址 function getApproved(uint256 _pizzaId) public view returns (address operator) { - require(_exists(_pizzaId), "Pizza does not exist."); + require(_exists(_pizzaId), "披萨不存在。"); return pizzaApprovals[_pizzaId]; } /** - * Private function to clear current approval of a given token ID - * Reverts if the given address is not indeed the owner of the token + * 清除给定代币 ID 的当前批准的私有函数 + * 如果给定地址不是代币的真正所有者,则还原 */ function _clearApproval(address owner, uint256 _pizzaId) private { - require(pizzaToOwner[_pizzaId] == owner, "Must be pizza owner."); - require(_exists(_pizzaId), "Pizza does not exist."); + require(pizzaToOwner[_pizzaId] == owner, "必须是披萨所有者。"); + require(_exists(_pizzaId), "披萨不存在。"); if (pizzaApprovals[_pizzaId] != address(0)) { pizzaApprovals[_pizzaId] = address(0); } } /* - * Sets or unsets the approval of a given operator - * An operator is allowed to transfer all tokens of the sender on their behalf + * 设置或取消设置给定操作员的批准 + * 允许操作员代表发送者转移其所有代币 */ function setApprovalForAll(address to, bool approved) public { - require(to != msg.sender, "Cannot approve own address"); + require(to != msg.sender, "不能批准自己的地址"); operatorApprovals[msg.sender][to] = approved; emit ApprovalForAll(msg.sender, to, approved); } - // Tells whether an operator is approved by a given owner + // 告知操作员是否获得给定所有者的批准 function isApprovedForAll(address owner, address operator) public view @@ -574,20 +577,20 @@ contract CryptoPizza is IERC721, ERC165 { return operatorApprovals[owner][operator]; } - // Takes ownership of Pizza - only for approved users + // 取得 Pizza 的所有权 - 仅限批准的用户 function takeOwnership(uint256 _pizzaId) public { - require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved."); + require(_isApprovedOrOwner(msg.sender, _pizzaId), "地址未经批准。"); address owner = this.ownerOf(_pizzaId); this.transferFrom(owner, msg.sender, _pizzaId); } - // Checks if Pizza exists + // 检查 Pizza 是否存在 function _exists(uint256 pizzaId) internal view returns (bool) { address owner = pizzaToOwner[pizzaId]; return owner != address(0); } - // Checks if address is owner or is approved to transfer Pizza + // 检查地址是否为所有者或被批准转移 Pizza function _isApprovedOrOwner(address spender, uint256 pizzaId) internal view @@ -602,7 +605,7 @@ contract CryptoPizza is IERC721, ERC165 { this.isApprovedForAll(owner, spender)); } - // Check if Pizza is unique and doesn't exist yet + // 检查 Pizza 是否唯一且尚不存在 modifier isUnique(string memory _name, uint256 _dna) { bool result = true; for (uint256 i = 0; i < pizzas.length; i++) { @@ -614,19 +617,18 @@ contract CryptoPizza is IERC721, ERC165 { result = false; } } - require(result, "Pizza with such name already exists."); + require(result, "具有此类名称的披萨已存在。"); _; } - // Returns whether the target address is a contract + // 返回目标地址是否是合约 function isContract(address account) internal view returns (bool) { uint256 size; - // Currently there is no better way to check if there is a contract in an address - // than to check the size of the code at that address. - // See https://ethereum.stackexchange.com/a/14016/36603 - // for more details about how this works. - // TODO Check this again before the Serenity release, because all addresses will be - // contracts then. + // 目前,没有比检查地址处的代码大小更好的方法来检查地址中是否存在合约。 + // 有关其工作原理的更多详细信息, + // 请参阅 https://ethereum.stackexchange.com/a/14016/36603。 + // TODO 在 Serenity 发布之前再次检查,因为届时所有地址都将是 + // 合约。 // solium-disable-next-line security/no-inline-assembly assembly { size := extcodesize(account) @@ -636,20 +638,20 @@ contract CryptoPizza is IERC721, ERC165 { } ``` -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} 查阅 Solidity 和 Vyper 文档,以获得关于智能合约的更完整概述: -- [Solidity](https://solidity.readthedocs.io/) -- [Vyper](https://vyper.readthedocs.io/) +- [Solidity](https://docs.soliditylang.org/) +- [Vyper](https://docs.vyperlang.org/en/stable/) -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [智能合约](/developers/docs/smart-contracts/) - [以太坊虚拟机](/developers/docs/evm/) ## 相关教程 {#related-tutorials} -- [减少合约大小以应对合约大小的限制](/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/) _– 一些减少智能合约大小的实用提示。_ -- [用事件记录智能合约的数据](/developers/tutorials/logging-events-smart-contracts/) _——对智能合约事件的介绍以及如何使用它们来记录数据。_ -- [在 Solidity 中与其它合约交互](/developers/tutorials/interact-with-other-contracts-from-solidity/) _——如何从现有合约中部署智能合约并与之交互。_ +- [缩减合约以对抗合约大小限制](/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/)_– 一些减小智能合约大小的实用技巧。_ +- [使用事件记录智能合约中的数据](/developers/tutorials/logging-events-smart-contracts/)_– 智能合约事件简介以及如何使用它们来记录数据。_ +- [在 Solidity 中与其他合约交互](/developers/tutorials/interact-with-other-contracts-from-solidity/)_– 如何从现有合约部署智能合约并与之交互。_ diff --git a/public/content/translations/zh/developers/docs/smart-contracts/compiling/index.md b/public/content/translations/zh/developers/docs/smart-contracts/compiling/index.md index 722dd3c6170..3ed5004ae32 100644 --- a/public/content/translations/zh/developers/docs/smart-contracts/compiling/index.md +++ b/public/content/translations/zh/developers/docs/smart-contracts/compiling/index.md @@ -1,6 +1,6 @@ --- -title: 编译智能合约 -description: 解释你为什么需要编译智能合约以及编译实际上做了什么。 +title: "编译智能合约" +description: "解释你为什么需要编译智能合约以及编译实际上做了什么。" lang: zh incomplete: true --- @@ -9,18 +9,18 @@ incomplete: true ## 前提条件 {#prerequisites} -在阅读关于编译的文档之前,请阅读我们的[智能合约](/developers/docs/smart-contracts/)和[以太坊虚拟机](/developers/docs/evm/)可能会有帮助。 +在阅读有关编译的内容前,您会发现,阅读我们关于[智能合约](/developers/docs/smart-contracts/)和[以太坊虚拟机](/developers/docs/evm/)的介绍会很有帮助。 -## 以太坊虚拟机 {#the-evm} +## EVM {#the-evm} -要使[以太坊虚拟机](/developers/docs/evm/)能够运行你的合约,你的合约必须被编译为**字节码**。 编译过程把如下代码: +为使[以太坊虚拟机](/developers/docs/evm/)能够运行您的合约,它必须是**字节码**。 编译过程把如下代码: ```solidity pragma solidity 0.4.24; contract Greeter { - function greet() public constant returns (string) { + function greet() public view returns (string memory) { return "Hello"; } @@ -33,17 +33,17 @@ contract Greeter { PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x41 JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0xCFAE3217 EQ PUSH2 0x46 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x52 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x5B PUSH2 0xD6 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP4 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x9B JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0x80 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0xC8 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x60 PUSH1 0x40 DUP1 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x5 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x48656C6C6F000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP SWAP1 POP SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 SLT 0xec 0xe 0xf5 0xf8 SLT 0xc7 0x2d STATICCALL ADDRESS SHR 0xdb COINBASE 0xb1 BALANCE 0xe8 0xf8 DUP14 0xda 0xad DUP13 LOG1 0x4c 0xb4 0x26 0xc2 DELEGATECALL PUSH7 0x8994D3E002900 ``` -这些代码称为**操作码**。 以太坊虚拟机操作码是以太坊虚拟机 (EVM) 能够执行的低级指令。 每个操作码都代表一个具体的操作,例如算术运算、逻辑运算、数据操作,控制流等等。 +这些被称为**操作码**。 以太坊虚拟机操作码是以太坊虚拟机 (EVM) 能够执行的低级指令。 每个操作码都代表一个具体的操作,例如算术运算、逻辑运算、数据操作,控制流等等。 -[更多关于操作码的信息](/developers/docs/evm/opcodes/) +[关于操作码的更多信息](/developers/docs/evm/opcodes/) -## Web 应用程序 {#web-applications} +## Web 应用 {#web-applications} -编译器还将生成你需要的**应用程序二进制接口 (ABI)** ,以便你的应用程序能够理解合约并调用合约的功能。 +编译器还会生成**应用程序二进制接口 (ABI)**。您的应用程序需要 ABI 来理解合约并调用其函数。 ABI 是一份 JSON 文件,描述了部署的合约及这个智能合约的函数。 这在 web2 和 web3 之间的鸿沟上架起交流的桥梁 -[Javascript 客户端库](/developers/docs/apis/javascript/)将读取**应用程序二进制接口 (ABI)**,以便你在 Web 应用程序接口中调用你的智能合约。 +[JavaScript 客户端库](/developers/docs/apis/javascript/)将读取 **ABI**,以便您在您的 Web 应用程序界面中调用您的智能合约。 以下是 ERC-20 代币合约的应用程序二进制接口。 ERC-20 是你可以在以太坊交易的代币。 @@ -272,11 +272,11 @@ ABI 是一份 JSON 文件,描述了部署的合约及这个智能合约的函 ] ``` -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [ABI spec](https://solidity.readthedocs.io/en/v0.7.0/abi-spec.html) _– Solidity_ +- [ABI 规范](https://solidity.readthedocs.io/en/v0.7.0/abi-spec.html) _– Solidity_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [JavaScript 客户端库](/developers/docs/apis/javascript/) - [以太坊虚拟机](/developers/docs/evm/) diff --git a/public/content/translations/zh/developers/docs/smart-contracts/composability/index.md b/public/content/translations/zh/developers/docs/smart-contracts/composability/index.md index da5eea243a1..d4172324810 100644 --- a/public/content/translations/zh/developers/docs/smart-contracts/composability/index.md +++ b/public/content/translations/zh/developers/docs/smart-contracts/composability/index.md @@ -1,13 +1,13 @@ --- -title: 智能合约的可组合性 -description: +title: "智能合约的可组合性" +description: "了解智能合约如何像乐高积木那样,透过重用现有的组件来构建复杂的去中心化应用程序。" lang: zh incomplete: true --- ## 简介 {#a-brief-introduction} -智能合约在以太坊上是公开的,可视为开放式应用程序接口。 你不需要写自己的智能合约才能成为一个去中心化应用程序开发者,你只需要知道如何与它们交互。 例如,你可以使用现有的智能合约 [Uniswap](https://uniswap.exchange/swap),一个去中心化的交易所,在你的应用中处理代币交易逻辑 – 你并不需要一切从零开始。 看看他们的一些 [v2](https://github.com/Uniswap/uniswap-v2-core/tree/master/contracts) 和 [v3](https://github.com/Uniswap/uniswap-v3-core/tree/main/contracts) 合约。 +智能合约在以太坊上公开,并且可以看成开放应用程序接口。 你不需要写自己的智能合约才能成为一个去中心化应用程序开发者,你只需要知道如何与它们交互。 例如,你可以使用去中心化交易所 [Uniswap](https://uniswap.exchange/swap) 的现有智能合约来处理你应用中的所有代币兑换逻辑——你不需要从头开始。 查看他们的一些 [v2](https://github.com/Uniswap/uniswap-v2-core/tree/master/contracts) 和 [v3](https://github.com/Uniswap/uniswap-v3-core/tree/main/contracts) 合约。 ## 什么是可组合性? {#what-is-composability} @@ -19,58 +19,58 @@ incomplete: true 以太坊智能合约就像是公共应用程序接口,任何人都可以与合约交互或将其整合到去中心化应用程序中以获得更多功能。 智能合约的可组合性一般有三个原则:模块化、自主性和可发现性。 -**1. 模块化**:这是独立组件执行具体任务的能力。 在以太坊,每个智能合约都有一个特定的用例(如 Uniswap 示例所示)。 +**1. 模块化**:这是指单个组件执行特定任务的能力。 在以太坊,每个智能合约都有一个特定的用例(如 Uniswap 示例所示)。 -**2. 自主性**:可组合的组件必须能够独立运行。 以太坊中每个智能合约都可以在不依赖系统其他部分的情况下自动执行。 +**2. 自主性**:可组合组件必须能够独立运行。 以太坊中每个智能合约都可以在不依赖系统其他部分的情况下自动执行。 -**3. 可发现性**:开发者无法在外部合约或软件库未公开时调用合约或将库整合到应用程序中。 按照设计,智能合约是开源的;任何人都可以调用合约或派生代码库。 +**3. 可发现性**:如果外部合约或软件库不是公开可用的,开发人员就无法调用它们或将其集成到应用程序中。 按照设计,智能合约是开源的;任何人都可以调用合约或派生代码库。 -## 可组合性带来的好处 {#benefits-of-composability} +## 可组合性的好处 {#benefits-of-composability} ### 缩短开发周期 {#shorter-development-cycle} -减少了开发者在创建[去中心化应用程序](/apps/#what-are-dapps)时的必要工作。 [正如 Naval Ravikant 所说的那样:](https://twitter.com/naval/status/1444366754650656770)“开放源码意味着每个问题只需要解决一次。” +可组合性减少了开发人员在创建[去中心化应用程序](/apps/#what-are-dapps)时所需的工作量。 [正如 Naval Ravikant 所说:](https://twitter.com/naval/status/1444366754650656770)“开源意味着每个问题只须解决一次。” 如果有智能合约解决了某个问题,那么其他开发者可以重用这个合约,所以他们无需解决同样的问题。 这种方法让开发者可以使用现有软件库并添加一些额外功能来创建新的去中心化应用程序。 -### 增加创新 {#greater-innovation} +### 更强的创新能力 {#greater-innovation} 可组合性鼓励创新和实验,因为开发者们可以自由地重用、修改、复制或整合开源代码以达到预期结果。 这样,开发小组在基础功能上将花费较少的时间,并可以将更多的时间分配到新功能的实验上。 -### 改善用户体验 {#better-user-experience} +### 更好的用户体验 {#better-user-experience} 以太坊生态系统中各组成部分之间的互操作性可改善用户体验。 相较于应用程序无法互通的碎片化生态系统,去中心化应用程序在集成外部智能合约后,用户可以获取更多功能。 我们将使用一个仲裁交易的示例来说明互操作性的好处: -如果某个代币在`交易所 A` 的交易价格高于`交易所 B`,你可以利用价格差赚取利润。 然而,只有当你有足够的资本来为交易提供资金的情况下,你才能做到这一点(即,从`交易所 B` 购买代币并在`交易所 A` 出售)。 +如果某个代币在 `exchange A` 的交易价格高于 `exchange B`,你可以利用价差赚取利润。 但是,只有当你拥有足够的资金来完成这笔交易(即从 `exchange B` 购买代币,然后在 `exchange A` 上卖出)时,你才能这么做。 -在你没有足够资金来支付交易的情况下,闪电贷可能是个理想的办法。 [闪电贷](/defi/#flash-loans)的技术含量较高,但最基本的逻辑是,你可以借入资产(无抵押品),并在_一笔_交易中返还相同的资产。 +在你没有足够资金来支付交易的情况下,闪电贷可能是个理想的办法。 [闪电贷](/defi/#flash-loans) 技术性很强,但其基本思想是,你可以在_一笔_交易中(无抵押)借入资产并归还。 -回到我们最初的示例,仲裁交易者可以拿出大笔闪电贷,从`交易所 B` 购买代币,在`交易所 A` 出售它们,退还资本+利息,并将利润保留在同一笔交易中。 这种复杂的逻辑需要将多个合约的调用结合起来,如果智能合约缺乏互操作性,这种调用是不可能做到的。 +回到我们最初的例子,套利交易者可以借入一大笔闪电贷,从 `exchange B` 购买代币,在 `exchange A` 上卖出,偿还本金和利息,并在同一笔交易中保留利润。 这种复杂的逻辑需要将多个合约的调用结合起来,如果智能合约缺乏互操作性,这种调用是不可能做到的。 ## 以太坊中的可组合性示例 {#composability-in-ethereum} -### 代币交换 {#token-swaps} +### 代币兑换 {#token-swaps} 如果你创建了一个需要用以太币支付交易费用的去中心化应用程序,你可以通过整合代币交换逻辑,允许用户使用其他 ERC-20 代币付款。 在合约执行调用的函数之前,代码会自动把用户的代币转换为以太币。 ### 治理 {#governance} -为[去中心化自治组织](/dao/)构建定制的治理系统可能会耗费大量时间和金钱。 或者,你可以使用开放源代码治理工具包,例如 [Aragon 客户端](https://client.aragon.org/),来引导去中心化自治组织,以快速创建治理框架。 +为 [DAO](/dao/) 构建定制的治理系统可能既昂贵又耗时。 或者,你可以使用开源治理工具包(如 [Aragon Client](https://client.aragon.org/))来引导你的 DAO,从而快速创建治理框架。 ### 身份管理 {#identity-management} -你可以集成去中心化身份 (DID) 工具来管理用户的身份验证,而不是建立一个自定义身份验证系统或依靠中心化的身份提供商。 一个例子是 [SpruceID](https://www.spruceid.com/),它是一个开源工具包,提供了“使用以太坊登录”的功能,让用户能够通过以太坊钱包验证身份。 +你可以集成去中心化身份 (DID) 工具来管理用户的身份验证,而不是建立一个自定义身份验证系统或依靠中心化的身份提供商。 例如 [SpruceID](https://www.spruceid.com/),它是一个开源工具包,提供“用以太坊登录”功能,让用户可以用以太坊钱包验证身份。 ## 相关教程 {#related-tutorials} -- [使用 create-eth-app 启动去中心化应用程序前端开发](/developers/tutorials/kickstart-your-dapp-frontend-development-with-create-eth-app/) _– 概述如何使用 create-eth-app,借助开箱即用的热门智能合约创建应用程序。_ +- [使用 create-eth-app 快速开始你的去中心化应用程序前端开发](/developers/tutorials/kickstart-your-dapp-frontend-development-with-create-eth-app/)_——概述如何使用 create-eth-app 创建开箱即用的、包含热门智能合约的应用程序。_ -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -_还有哪些社区资源对你有所帮助? 编辑本页面以添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ -- [可组合性是创新](https://future.a16z.com/how-composability-unlocks-crypto-and-everything-else/) +- [可组合性即创新](https://a16zcrypto.com/posts/article/how-composability-unlocks-crypto-and-everything-else/) - [为什么可组合性对 Web3 很重要](https://hackernoon.com/why-composability-matters-for-web3) - [什么是可组合性?](https://blog.aragon.org/what-is-composability/#:~:text=Aragon,connect%20to%20every%20other%20piece.) diff --git a/public/content/translations/zh/developers/docs/smart-contracts/deploying/index.md b/public/content/translations/zh/developers/docs/smart-contracts/deploying/index.md index d842c3abcb5..0e09a6cfe1e 100644 --- a/public/content/translations/zh/developers/docs/smart-contracts/deploying/index.md +++ b/public/content/translations/zh/developers/docs/smart-contracts/deploying/index.md @@ -1,81 +1,81 @@ --- -title: 部署智能合约 -description: +title: "部署智能合约" +description: "了解如何将智能合约部署到以太坊网络,包括先决条件、工具,以及部署步骤。" lang: zh --- -需要部署智能合约才能提供给以太坊网络的用户使用。 +你需要部署你的智能合约,以供以太坊网络的用户使用。 -要部署一个智能合约,只需发送一个包含编译后的智能合约代码的以太坊交易,而不需要指定任何收件人。 +要部署智能合约,你只需发送一笔包含已编译智能合约代码的以太坊交易,无需指定任何接收方。 -## 前置要求 {#prerequisites} +## 前提条件 {#prerequisites} -在部署智能合约之前,你需要理解[以太坊网络](/developers/docs/networks/), [交易](/developers/docs/transactions/)和[详解智能合约](/developers/docs/smart-contracts/anatomy/)。 +在部署智能合约之前,你应该了解[以太坊网络](/developers/docs/networks/)、[交易](/developers/docs/transactions/)以及[智能合约剖析](/developers/docs/smart-contracts/anatomy/)。 -部署一个合约也需要耗费以太币 (ETH),因为他们被存储在区块链上,所以你应该熟悉以太坊的[燃料和费用](/developers/docs/gas/)。 +部署合约也需要花费以太币 (ETH),因为合约存储在区块链上,所以你应该熟悉以太坊上的[燃料和费用](/developers/docs/gas/)。 -最后,你需要在部署之前编译你的合约,所以请确保你已经阅读了[编译智能合约](/developers/docs/smart-contracts/compiling/)。 +最后,在部署合约之前,你需要先编译它,所以请确保你已经阅读过关于[编译智能合约](/developers/docs/smart-contracts/compiling/)的文章。 ## 如何部署智能合约 {#how-to-deploy-a-smart-contract} -### 你所需要的 {#what-youll-need} +### 你需要准备什么 {#what-youll-need} -- 合约的字节码 – 可通过[编译](/developers/docs/smart-contracts/compiling/)生成 +- 你的合约字节码——通过[编译](/developers/docs/smart-contracts/compiling/)生成 - 用作燃料的以太币 – 像其他交易一样,你需要设定燃料限制,这样就知道部署合约比简单的以太币交易需要更多的燃料。 -- 一个部署脚本或插件。 -- 通过以下方式之一可以访问[以太坊节点](/developers/docs/nodes-and-clients/):运行自己的节点、连接到公共节点或使用[节点服务](/developers/docs/nodes-and-clients/nodes-as-a-service/)的应用程序接口密钥。 +- 一个部署脚本或插件 +- 访问[以太坊节点](/developers/docs/nodes-and-clients/),可以通过运行自己的节点、连接到公共节点,或通过 API 密钥使用[节点服务](/developers/docs/nodes-and-clients/nodes-as-a-service/)。 ### 部署智能合约的步骤 {#steps-to-deploy} -具体步骤将取决于使用的开发框架。 例如,你可以查看[安全帽提供的合约部署文档](https://hardhat.org/docs/tutorial/deploying)或 [Foundry 提供 的智能合约部署与验证文档](https://book.getfoundry.sh/forge/deploying)。 如同其他[帐户](/developers/docs/accounts/)一样,部署后,你的合约将有一个以太坊地址,并且可以使用[源代码验证工具](/developers/docs/smart-contracts/verifying/#source-code-verification-tools)来验证。 +具体步骤将取决于使用的开发框架。 例如,你可以查看[Hardhat关于部署合约的文档](https://hardhat.org/docs/tutorial/deploying)或 [Foundry 关于部署和验证智能合约的文档](https://book.getfoundry.sh/forge/deploying)。 一旦部署,你的合约将拥有一个以太坊地址,和其他[账户](/developers/docs/accounts/)一样,并且可以使用[源代码验证工具](/developers/docs/smart-contracts/verifying/#source-code-verification-tools)进行验证。 ## 相关工具 {#related-tools} -**Remix - _Remix 集成开发环境可以开发、部署和管理类似区块链的以太坊智能合约。_** +**Remix - _Remix IDE 允许为以太坊等区块链开发、部署和管理智能合约_** - [Remix](https://remix.ethereum.org) -**Tenderly - _Web3 开发平台,提供调试、可观测性和基础设施构建基块,用于开发、测试、监测和操作智能合约_** +**Tenderly - _Web3 开发平台,为开发、测试、监控和运行智能合约提供调试、可观察性和基础设施构建模块_** - [tenderly.co](https://tenderly.co/) -- [相关文档](https://docs.tenderly.co/) +- [文档](https://docs.tenderly.co/) - [GitHub](https://github.com/Tenderly) - [Discord](https://discord.gg/eCWjuvt) -**安全帽 - _用于编译、部署、测试和调试你的以太坊软件的开发环境_** +**Hardhat - _一个用于编译、部署、测试和调试你的以太坊软件的开发环境_** - [hardhat.org](https://hardhat.org/getting-started/) -- [关于部署合约的文档](https://hardhat.org/docs/tutorial/deploying) +- [关于部署你的合约的文档](https://hardhat.org/docs/tutorial/deploying) - [GitHub](https://github.com/nomiclabs/hardhat) - [Discord](https://discord.com/invite/TETZs2KK4k) -**thirdweb - _使用一条命令轻松地将任何合约部署到任何与以太坊虚拟机兼容的区块链_** +**thirdweb - _使用一条命令,轻松将任何合约部署到任何兼容 EVM 的链_** - [相关文档](https://portal.thirdweb.com/deploy/) -**Crossmint - _企业级 Web3 开发平台,可用于部署智能合约,启用信用卡和跨链支付,使用应用程序接口创建、分发、销售、储存和编辑非同质化代币。_** +**Crossmint - _企业级 web3 开发平台,可用于部署智能合约,支持信用卡和跨链支付,并使用 API 来创建、分发、出售、存储和编辑 NFT。_** - [crossmint.com](https://www.crossmint.com) -- [相关文档](https://docs.crossmint.com) +- [文档](https://docs.crossmint.com) - [Discord](https://discord.com/invite/crossmint) - [博客](https://blog.crossmint.com) ## 相关教程 {#related-tutorials} -- [部署你的第一个智能合约](/developers/tutorials/deploying-your-first-smart-contract/) _ – 介绍如何在以太坊测试网络上部署你的第一个智能合约。_ -- [Hello World | 智能合约教程](/developers/tutorials/hello-world-smart-contract/) _ – 一门便于学习的教程,介绍如何在以太坊上创建和部署基本智能合约。_ -- [在 Solidity 中与其它合约交互](/developers/tutorials/interact-with-other-contracts-from-solidity/) _——如何从现有合约中部署智能合约并与之交互。_ -- [如何减少合约的大小](/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/) _- 如何减少合约的大小使其保持在限制之下并节省燃料_ +- [部署你的第一个智能合约](/developers/tutorials/deploying-your-first-smart-contract/)_– 介绍如何在以太坊测试网络上部署你的第一个智能合约。_ +- [Hello World | 智能合约教程](/developers/tutorials/hello-world-smart-contract/) _– 一个简单易懂的教程,介绍如何在以太坊上创建和部署一个基本的智能合约。_ +- [在 Solidity 中与其他合约交互](/developers/tutorials/interact-with-other-contracts-from-solidity/)_– 如何从现有合约部署智能合约并与之交互。_ +- [如何缩减合约大小](/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/) _- 如何减小合约大小,使其保持在限制范围内并节省燃料_ -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [https://docs.openzeppelin.com/learn/deploying-and-interacting](https://docs.openzeppelin.com/learn/deploying-and-interacting) - _OpenZeppelin_ -- [使用安全帽部署合约](https://hardhat.org/docs/tutorial/deploying) - _Nomic Labs_ +- [使用Hardhat部署你的合约](https://hardhat.org/docs/tutorial/deploying) - _Nomic Labs_ -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [开发框架](/developers/docs/frameworks/) -- [运行以太坊节点](/developers/docs/nodes-and-clients/run-a-node/) +- [运行一个以太坊节点](/developers/docs/nodes-and-clients/run-a-node/) - [节点即服务](/developers/docs/nodes-and-clients/nodes-as-a-service) diff --git a/public/content/translations/zh/developers/docs/smart-contracts/formal-verification/index.md b/public/content/translations/zh/developers/docs/smart-contracts/formal-verification/index.md index 642a316f529..2dbc176c431 100644 --- a/public/content/translations/zh/developers/docs/smart-contracts/formal-verification/index.md +++ b/public/content/translations/zh/developers/docs/smart-contracts/formal-verification/index.md @@ -1,6 +1,6 @@ --- -title: 智能合约的形式化验证 -description: 以太坊智能合约的形式化验证概述 +title: "智能合约的形式化验证" +description: "以太坊智能合约的形式化验证概述" lang: zh --- @@ -26,7 +26,7 @@ lang: zh 高级模型侧重于智能合约和外部代理之间的关系,例如外部帐户 (EOA)、合约帐户和区块链环境。 这些模型有助于定义属性,这些属性规定了合约应该如何响应某些用户的交互行为。 -相反,其他一些形式化模型侧重于智能合约的低级行为。 虽然高级模型有助于论证合约的功能,但它们可能无法捕捉到实现的内部运作细节。 低级模型对程序分析应用了白盒视图并依赖于智能合约应用程序的低级表示,例如程序跟踪和[控制流程图](https://en.wikipedia.org/wiki/Control-flow_graph),来推理与合约执行相关的属性。 +相反,其他一些形式化模型侧重于智能合约的低级行为。 虽然高级模型有助于论证合约的功能,但它们可能无法捕捉到实现的内部运作细节。 低级模型对程序分析应用了白盒视图并依赖于智能合约应用程序的低级表示(例如程序跟踪和[控制流程图](https://en.wikipedia.org/wiki/Control-flow_graph)),来推理与合约执行相关的属性。 低级模型被视为理想模型,因为它们体现着智能合约在以太坊执行环境(即[以太坊虚拟机](/developers/docs/evm/))中的实际执行。 低级建模技术在确立智能合约的重要安全属性和检测潜在漏洞方面特别有用。 @@ -40,11 +40,11 @@ lang: zh 在开发安全的智能合约实现时,形式化规范非常重要。 无法实现不变量或者在执行过程中属性被违反的合约容易出现漏洞,可能会损害功能或者受到恶意的利用。 -## 智能合约形式化规范的类型 {#formal-specifications-for-smart-contracts} +## 智能合约的形式化规范类型 {#formal-specifications-for-smart-contracts} 形式化规范支持对程序执行的正确性进行数学推理。 与形式化模型一样,形式化规范能够详尽描述合约实现的高级属性或低级行为。 -形式化规范从[程序逻辑](https://en.wikipedia.org/wiki/Logic_programming)的元素中推导出来,可对程序的属性进行形式化推理。 程序逻辑具有形式化规则,它们使用数学语言表示程序的预期行为。 可以使用各种程序逻辑制定形式化规范,包括[可达性逻辑](https://en.wikipedia.org/wiki/Reachability_problem)、[时间逻辑](https://en.wikipedia.org/wiki/Temporal_logic)以及[霍尔逻辑](https://en.wikipedia.org/wiki/Hoare_logic)。 +形式化规范从[程序逻辑](https://en.wikipedia.org/wiki/Logic_programming)的元素中推导出来,可对程序的属性进行形式化推理。 程序逻辑具有形式化规则,它们使用数学语言表示程序的预期行为。 创建形式化规范时会使用各种程序逻辑,包括[可达性逻辑](https://en.wikipedia.org/wiki/Reachability_problem)、[时间逻辑](https://en.wikipedia.org/wiki/Temporal_logic)和[霍尔逻辑](https://en.wikipedia.org/wiki/Hoare_logic)。 智能合约的形式化规范可以大致分类为**高级**或**低级**规范。 无论属于哪一类,规范都必须充分明确地描述被分析系统的属性。 @@ -54,11 +54,11 @@ lang: zh [时间逻辑](https://en.wikipedia.org/wiki/Temporal_logic)是“用时间限定的命题的推理规则(例如,“我_总是_饿”或者“我_最终_会饿”)。” 当应用于形式化验证时,时间逻辑用来声明建模成状态机的系统的正确行为的断言。 具体而言,时间逻辑描述智能合约可以进入的未来状态以及它如何在不同状态之间转换。 -高级规范一般详述智能合约的两个关键时间属性:**安全性**和**活性**。 安全属性代表“任何坏事始终都不会发生”的想法,通常用来表示不变性。 安全属性可以定义常规软件要求(例如不发生[死锁](https://www.techtarget.com/whatis/definition/deadlock)),或者表达合约领域特定的属性(例如,函数访问控制的不变量、状态变量的容许值或代币转账的条件)。 +高级规范一般详述智能合约的两个关键时间属性:**安全**性和**活性**。 安全属性代表“任何坏事始终都不会发生”的想法,通常用来表示不变性。 安全属性可以定义常规软件要求(例如不发生[死锁](https://www.techtarget.com/whatis/definition/deadlock)),或者表达合约领域特定的属性(例如,函数访问控制的不变量、状态变量的容许值或代币转账的条件)。 以下面的安全要求为例,它描述了在 ERC-20 代币合约中使用 `transfer()` 或 `transferFrom()` 的条件:_“发送人的余额始终不能少于请求发送的代币金额。”_。 这种合约不变量的自然语言描述可以转化为形式化(数学)规范,以便随后能够进行严格的有效性检查。 -活性属性断言“好事终究会发生”,并涉及到合约通过不同状态的能力。 活性属性的一个例子是“流动性”,指的是合约在收到请求把余额转账给用户的能力。 如果违反了该属性,用户将不能提取存入合约的资产,就像在 [Parity 钱包事件](https://www.cnbc.com/2017/11/08/accidental-bug-may-have-frozen-280-worth-of-ether-on-parity-wallet.html)中发生的情况一样。 +活性属性断言“好事终究会发生”,并涉及到合约通过不同状态的能力。 活性属性的一个例子是“流动性”,指的是合约在收到请求把余额转账给用户的能力。 如果该属性被违反,用户将无法提取存储在合约中的资产,就像在 [Parity 钱包事件](https://www.cnbc.com/2017/11/08/accidental-bug-may-have-frozen-280-worth-of-ether-on-parity-wallet.html)中发生的那样。 ### 低级规范 {#low-level-specifications} @@ -70,7 +70,7 @@ lang: zh ### 霍尔式属性 {#hoare-style-properties} -[霍尔逻辑](https://en.wikipedia.org/wiki/Hoare_logic)提供了一套形式化规则来推理程序(包括智能合约)的正确性。 霍尔式属性使用霍尔三元组 \{_P_}_c_\{_Q_} 表示,其中 _c_ 代表程序,_P_ 和 _Q_ 是 _c_(即程序)状态的谓词,它们正式描述成_前置条件_和_后置条件_。 +[霍尔逻辑](https://en.wikipedia.org/wiki/Hoare_logic)提供了一套形式化规则来推理程序(包括智能合约)的正确性。 霍尔式属性使用霍尔三元组 `{P}c{Q}` 表示,其中 `c` 代表程序,`P` 和 `Q` 是 `c`(即程序)状态的谓词,二者分别正式描述成_前置条件_和_后置条件_。 前置条件是描述函数正确执行所需条件的谓词;用户调用合约必须满足该要求。 后置条件是描述函数在正确执行时所达成条件的谓词;用户在调用函数后可以期待该条件为真。 在霍尔逻辑中,_不变量_是一个在函数执行时保留的谓词(即它不改变)。 @@ -100,7 +100,7 @@ lang: zh - 如果用户未给提案投票,可以要求退款 -执行轨迹级属性的示例可以是_“没有存入资金的用户无法对提案投票”_或_“未对提案投票的用户始终应该可以要求退款”_。 这两个属性断言优先执行次序(在存入资金_之前_无法投票和给提案投票_之后_无法要求退款)。 +执行轨迹级属性的示例可以是_“没有存入资金的用户无法对提案投票”_或_“未对提案投票的用户始终应该可以要求退款”_。 这两个属性断言优先执行次序(在存入资金之前无法投票和给提案投票之后无法要求退款)。 ## 智能合约的形式化验证技术 {#formal-verification-techniques} @@ -110,7 +110,7 @@ lang: zh 模型检查要求创建系统(即合约)的抽象数学表示并使用根植于[命题逻辑](https://www.baeldung.com/cs/propositional-logic)的公式表示该系统的属性。 这简化了模型检查算法的任务,即证明一个数学模型满足给定的逻辑公式。 -形式化验证的模型检查主要用来评估时间属性,后者描述合约在一段时间内的行为。 如前所述,智能合约的时间属性包括_安全_和_活性_。 +形式化验证的模型检查主要用来评估时间属性,后者描述合约在一段时间内的行为。 如前所述,智能合约的时间属性包括安全性和活性。 例如,与访问控制有关的安全属性(例如,_只有合约的所有者才能调用 `selfdestruct`_)可以用形式化逻辑来编写。 此后,模型检查算法能验证合约是否满足此形式化规范。 @@ -120,7 +120,7 @@ lang: zh 定理证明是一种程序(包括智能合约)正确性的数学推理方法。 它涉及将合约系统的模型以及其规范转换成数学公式(逻辑语句)。 -定理证明的目的是验证这些语句之间的逻辑等价性。 “逻辑等价性”(又称为“逻辑双向蕴含”)是指两个语句之间的一种关系类型,即_当且仅当_语句二为真时,语句一才能为真。 +定理证明的目的是验证这些语句之间的逻辑等价性。 “逻辑等价性”(又称为“逻辑双向蕴含”)是指两个语句之间的一种关系类型,即当且仅当语句二为真时,语句一才能为真。 关于合约模型及其属性的语句之间的必要关系(逻辑等价性)被表述为一个可证明的语句(称为定理)。 使用形式化推理系统,自动化定理证明器可以验证该定理的有效性。 也就是说,定理证明器可以确证智能合约模型与其规范完全相符。 @@ -134,7 +134,7 @@ lang: zh 符号执行把执行轨迹表示成针对符号输入值的数学公式,也称为_路径谓词_。 [SMT 求解器](https://en.wikipedia.org/wiki/Satisfiability_modulo_theories)用来检查路径谓词是否“可满足”(即存在一个满足公式的值)。 如果可以满足脆弱路径,SMT 求解器将产生一个具体值,将执行引向该路径。 -假设智能合约的函数把 `uint` 值 (`x`) 作为输入,并且当 `x` 大于 `5` 且小于 `10` 时回滚。 使用正常测试程序寻找一个触发错误的 `x` 值需要运行数十个测试用例(或者更多),而且不保证能实际找到一个触发错误的输入。 +假设智能合约的函数把 uint 值 (`x`) 作为输入,并且当 `x` 大于 `5` 且小于 `10` 时回滚。 使用正常测试程序寻找一个触发错误的 `x` 值需要运行数十个测试用例(或者更多),而且不保证能实际找到一个触发错误的输入。 相反,符号执行工具使用符号值来执行函数:`X > 5 ∧ X < 10`(即,`x` 大于 5 同时 `x` 小于 10)。 相关的路径谓词 `x = X > 5 ∧ X < 10` 将提供给 SMT 求解器来求解。 如果一个特定值满足公式 `x = X > 5 ∧ X < 10`,SMT 求解器将计算它 — 例如,求解器可能生成 `7` 作为 `x` 的值。 @@ -152,15 +152,16 @@ function safe_add(uint x, uint y) returns(uint z){ require(z>=y); return z; +} ``` -导致整数溢出的执行轨迹需要满足公式:`z = x + y AND (z >= x) AND (z=>y) AND (z < x OR z < y)`,不太可能对该公式求解,因此,它作为函数 `safe_add` 永远不会溢出的数学证明。 +导致整数溢出的执行轨迹需要满足公式:`z = x + y AND (z >= x) AND (z >= y) AND (z < x OR z < y)`。该公式不太可能被求解,因此,它可作为函数 `safe_add` 永远不会溢出的数学证明。 -### 为什么对智能合约进行形式化验证? {#benefits-of-formal-verification} +### 为什么对智能合约进行形式化验证? 形式化验证的好处 {#benefits-of-formal-verification} -#### 可靠性需要 {#need-for-reliability} +#### 对可靠性的需求 {#need-for-reliability} -形式化验证用来评估安全至上的系统的正确性,这类系统如果失败,将产生灾难性后果,例如死亡、受伤或者经济损失。 智能合约是具有高价值的应用程序,控制着大量价值,设计上的小错误将导致[用户蒙受难以挽回的损失](https://www.freecodecamp.org/news/a-hacker-stole-31m-of-ether-how-it-happened-and-what-it-means-for-ethereum-9e5dc29e33ce/amp/)。 然而,在部署前形式化验证合约,可以增加一些保障,确保合约在区块链上运行后表现如同预期一样。 +形式化验证用来评估安全至上的系统的正确性,这类系统如果失败,将产生灾难性后果,例如死亡、受伤或者经济损失。 智能合约是控制巨额价值的高价值应用程序,设计中的简单错误可能导致[用户的损失无法挽回](https://www.freecodecamp.org/news/a-hacker-stole-31m-of-ether-how-it-happened-and-what-it-means-for-ethereum-9e5dc29e33ce/amp/)。 然而,在部署前形式化验证合约,可以增加一些保障,确保合约在区块链上运行后表现如同预期一样。 可靠性是所有智能合约渴求的一种品质,尤其是因为部署在以太坊虚拟机 (EVM) 上的代码通常是不可更改的。 由于发布后的升级不容易获得,并且合约可靠性是需要保证的,因此形式化验证必不可少。 形式化验证能够发现棘手的问题,例如整数下溢和溢出、重入攻击和糟糕的燃料优化,审计人员和测试人员可能会漏掉这些问题。 @@ -170,7 +171,7 @@ function safe_add(uint x, uint y) returns(uint z){ 然而,这种方法无法证明不在样本里的输入值的正确执行。 因此,测试合约可能有助于检测到漏洞(即是否一些代码路径在执行过程中未能返回预期结果),但是**它无法确证没有漏洞存在**。 -相反,形式化验证可以形式化证明智能合约在无限执行范围内满足要求,而_无需_运行合约。 这需要制定精确描述正确合约行为的形式化规范并开发合约系统的形式化(数学)模型。 然后,我们可以按照形式化证明程序来检查合约模型与其规范是否一致。 +相反,形式化验证可以形式化证明智能合约在无限执行范围内满足要求,而无需运行合约。 这需要制定精确描述正确合约行为的形式化规范并开发合约系统的形式化(数学)模型。 然后,我们可以按照形式化证明程序来检查合约模型与其规范是否一致。 通过形式化验证,验证合约的业务逻辑是否满足要求的问题就变成一个能被证明或否定的数学命题。 通过形式化证明一个命题,我们可以使用有限的步骤验证无数个测试用例。 通过这种方式,形式化验证有更好的前景,可以证明依据规划合约的功能正确。 @@ -190,7 +191,7 @@ function safe_add(uint x, uint y) returns(uint z){ ## 形式化验证的缺点 {#drawbacks-of-formal-verification} -### 人工成本 {#cost-of-manual-labor} +### 手动劳动成本 {#cost-of-manual-labor} 形式化验证,尤其是需要人为引导证明器来推导出正确性证明的半自动化验证,需要大量人力。 此外,制定形式化规范是一项复杂的活动,需要高水平技能。 @@ -208,39 +209,39 @@ function safe_add(uint x, uint y) returns(uint z){ 而且,程序验证器并不是总能确定一个属性(描述成一个逻辑公式)是否能被满足(“[可判定性问题](https://en.wikipedia.org/wiki/Decision_problem)”),因为一个程序也许永远不会终止。 因此,即便合约的规范合理,也可能无法证明合约的一些属性。 -## 以太坊智能合约的形式化验证工具 {#formal-verification-tools} +## 用于以太坊智能合约的形式化验证工具 {#formal-verification-tools} ### 用于制定形式化规范的规范语言 {#specification-languages} -**Act**:_*Act 允许存储更新、前置条件/后置条件、合约不变量的规范。 其工具套件也具有证明后端,可通过 Coq、SMT 求解器或 hevm 证明许多属性。** +**Act**:__Act 允许指定存储更新、前置/后置条件和合约不变量。__ 其工具套件也具有证明后端,可通过 Coq、SMT 求解器或 hevm 证明许多属性。\*_ - [GitHub](https://github.com/ethereum/act) -- [相关文档](https://ethereum.github.io/act/) +- [相关文档](https://github.com/argotorg/act) -**Scribble** - _*Scribble 把 Scribble 规范语言中的代码注释转换为检查规范的具体断言。** +**Scribble** - __Scribble 把 Scribble 规范语言中的代码注释转换为检查规范的具体断言。__ - [相关文档](https://docs.scribble.codes/) -**Dafny** - _*Dafny 是一种可直接验证的编程语言,依赖于高层次注释来推理和验证代码的正确性。** +**Dafny** - __Dafny 是一种可直接验证的编程语言,依赖于高层次注释来推理和验证代码的正确性。__ - [GitHub](https://github.com/dafny-lang/dafny) ### 用于检查正确性的程序验证器 {#program-verifiers} -**Certora Prover** - _ Certora Prover 是一种检查智能合约代码正确性的自动形式化验证工具。 它使用 CVL(Certora 验证语言)编写规范,并组合使用静态分析和约束求解检测属性违反。_ +**Certora Prover** - _Certora Prover 是一种检查智能合约代码正确性的自动形式化验证工具。 它使用 CVL(Certora 验证语言)编写规范,并组合使用静态分析和约束求解检测属性违反。_ - [网站](https://www.certora.com/) - [相关文档](https://docs.certora.com/en/latest/index.html) -**Solidity SMTChecker** - _*Solidity 的SMTChecker 是一个基于 SMT(可满足性模理论)和 Horn 求解的内置模型检查器。 它在编译期间确认合约源代码是否符合规范并静态检查是否违反了安全属性。** +**Solidity SMTChecker** - __Solidity 的 SMTChecker 是一个基于 SMT(可满足性模理论)和 Horn 求解的内置模型检查器。 它在编译期间确认合约源代码是否符合规范并静态检查是否违反了安全属性。__ - [GitHub](https://github.com/ethereum/solidity) -**solc-verify** - _*solc-verify 是 Solidity 编译器的扩展版本,它可以使用注释和模块化程序验证对 Solidity 代码执行自动形式化验证。** +**solc-verify** - __solc-verify 是 Solidity 编译器的扩展版本,它可以使用注释和模块化程序验证对 Solidity 代码执行自动形式化验证。__ - [GitHub](https://github.com/SRI-CSL/solidity) -**KEVM** - _*KEVM 是以太坊虚拟机 (EVM) 的形式化语义,用 K 框架编写。 KEVM 是可执行的,并且能够使用可达性逻辑证明某些与属性相关的断言。** +**KEVM** - __KEVM 是以太坊虚拟机 (EVM) 的形式化语义,用 K 框架编写。 KEVM 是可执行的,并且能够使用可达性逻辑证明某些与属性相关的断言。__ - [GitHub](https://github.com/runtimeverification/evm-semantics) - [相关文档](https://jellopaper.org/) @@ -252,19 +253,19 @@ function safe_add(uint x, uint y) returns(uint z){ - [GitHub](https://github.com/isabelle-prover) - [相关文档](https://isabelle.in.tum.de/documentation.html) -**Coq** - _Coq 是一种交互式定理证明器,让你可以使用定理来定义程序并以交互方式产生经机器检查的正确性证明。_ +**Rocq** - _Rocq 是一个交互式定理证明器,可用于使用定理定义程序,并以交互方式生成机器检查的正确性证明。_ -- [GitHub](https://github.com/coq/coq) -- [相关文档](https://coq.github.io/doc/v8.13/refman/index.html) +- [GitHub](https://github.com/rocq-prover/rocq) +- [相关文档](https://rocq-prover.org/docs) ### 用于检测智能合约中易受攻击模式的基于符号执行的工具 {#symbolic-execution-tools} -**Manticore** - _*一种基于符号执行的工具,用于分析以太坊虚拟机的字节码分析工具*。* +**Manticore** - __一个基于符号执行的以太坊虚拟机字节码分析工具。__ - [GitHub](https://github.com/trailofbits/manticore) - [相关文档](https://github.com/trailofbits/manticore/wiki) -**hevm** - _*hevm 是一种面向以太坊虚拟机字节码的符号执行引擎和等价性检查器。** +**hevm** - __hevm 是一种面向以太坊虚拟机字节码的符号执行引擎和等价性检查器。__ - [GitHub](https://github.com/dapphub/dapptools/tree/master/src/hevm) @@ -273,11 +274,11 @@ function safe_add(uint x, uint y) returns(uint z){ - [GitHub](https://github.com/ConsenSys/mythril-classic) - [相关文档](https://mythril-classic.readthedocs.io/en/develop/) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [智能合约的形式化验证是如何运作的](https://runtimeverification.com/blog/how-formal-verification-of-smart-contracts-works/) -- [形式化验证如何确保智能合约无懈可击](https://media.consensys.net/how-formal-verification-can-ensure-flawless-smart-contracts-cbda8ad99bd1) -- [以太坊生态系统中的形式化验证项目概览](https://github.com/leonardoalt/ethereum_formal_verification_overview) -- [以太坊 2.0 存款智能合约的端对端形式化验证](https://runtimeverification.com/blog/end-to-end-formal-verification-of-ethereum-2-0-deposit-smart-contract/) -- [形式化验证世界上最热门的智能合约](https://www.zellic.io/blog/formal-verification-weth) +- [智能合约形式化验证的工作原理](https://runtimeverification.com/blog/how-formal-verification-of-smart-contracts-works/) +- [形式化验证如何确保智能合约完美无瑕](https://media.consensys.net/how-formal-verification-can-ensure-flawless-smart-contracts-cbda8ad99bd1) +- [以太坊生态系统中的形式化验证项目概述](https://github.com/leonardoalt/ethereum_formal_verification_overview) +- [以太坊 2.0 存款智能合约的端到端形式化验证](https://runtimeverification.com/blog/end-to-end-formal-verification-of-ethereum-2-0-deposit-smart-contract/) +- [对全球最流行的智能合约进行形式化验证](https://www.zellic.io/blog/formal-verification-weth) - [SMTChecker 和形式化验证](https://docs.soliditylang.org/en/v0.8.15/smtchecker.html) diff --git a/public/content/translations/zh/developers/docs/smart-contracts/index.md b/public/content/translations/zh/developers/docs/smart-contracts/index.md index 1e400402728..6a4a25b8db4 100644 --- a/public/content/translations/zh/developers/docs/smart-contracts/index.md +++ b/public/content/translations/zh/developers/docs/smart-contracts/index.md @@ -1,24 +1,23 @@ --- -title: 智能合约简介 -description: 智能合约概述,重点介绍其独特的特征和局限性。 +title: "智能合约简介" +description: "智能合约概述,重点介绍其独特的特征和局限性。" lang: zh --- ## 什么是智能合约? {#what-is-a-smart-contract} - 智能合约只是一个运行在以太坊链上的一个程序。 它是位于以太坊区块链上一个特定地址的一系列代码(函数)和数据(状态)。 -智能合约也是一个[以太坊帐户](/developers/docs/accounts/),我们称之为合约帐户。 这意味着它们有余额,可以成为交易的对象。 但是,他们无法被人操控,他们是被部署在网络上作为程序运行着。 个人用户可以通过提交交易执行智能合约的某一个函数来与智能合约进行交互。 智能合约能像常规合约一样定义规则,并通过代码自动强制执行。 默认情况下,你无法删除智能合约,与它们的交互是不可逆的。 +智能合约是一种[以太坊帐户](/developers/docs/accounts/)。 这意味着它们有余额,可以成为交易的对象。 但是,他们无法被人操控,他们是被部署在网络上作为程序运行着。 个人用户可以通过提交交易执行智能合约的某一个函数来与智能合约进行交互。 智能合约能像常规合约一样定义规则,并通过代码自动强制执行。 默认情况下,你无法删除智能合约,与它们的交互是不可逆的。 -## 前置要求 {#prerequisites} +## 前提条件 {#prerequisites} -如果你刚刚入门或寻找技术含量较低的介绍,我们推荐我们的[智能合约简介](/smart-contracts/)。 +如果你刚开始入门或正在寻找技术性不强的介绍,我们建议你阅读我们的[智能合约简介](/smart-contracts/)。 -确保在你已深入了解[帐户](/developers/docs/accounts/)、[交易](/developers/docs/transactions/)和[以太坊虚拟机](/developers/docs/evm/),然后再开始学习智能合约。 +在进入智能合约的世界之前,请确保你已经阅读了有关[帐户](/developers/docs/accounts/)、[交易](/developers/docs/transactions/)和[以太坊虚拟机](/developers/docs/evm/)的资料。 ## 数字自动售货机 {#a-digital-vending-machine} -也许对于智能合约最恰当的比喻是自动售货机,就像 [Nick Szabo](https://unenumerated.blogspot.com/) 描述的那样。 有了正确的投入,就保证了某些产出。 +正如 [Nick Szabo](https://unenumerated.blogspot.com/) 所描述,智能合约的最佳比喻或许是自动售货机。 有了正确的投入,就能保证一定的产出。 要从售货机中获取零食: @@ -35,28 +34,28 @@ pragma solidity 0.8.7; contract VendingMachine { - // Declare state variables of the contract + // 声明合约的状态变量 address public owner; mapping (address => uint) public cupcakeBalances; - // When 'VendingMachine' contract is deployed: - // 1. set the deploying address as the owner of the contract - // 2. set the deployed smart contract's cupcake balance to 100 + // 部署“VendingMachine”合约时: + // 1. 将部署地址设置成合约的所有者 + // 2. 将已部署的智能合约的纸杯蛋糕余额设为 100 constructor() { owner = msg.sender; cupcakeBalances[address(this)] = 100; } - // Allow the owner to increase the smart contract's cupcake balance + // 允许所有者增加智能合约的纸杯蛋糕余额 function refill(uint amount) public { - require(msg.sender == owner, "Only the owner can refill."); + require(msg.sender == owner, "只有所有者才能补充。"); cupcakeBalances[address(this)] += amount; } - // Allow anyone to purchase cupcakes + // 允许任何人购买纸杯蛋糕 function purchase(uint amount) public payable { - require(msg.value >= amount * 1 ether, "You must pay at least 1 ETH per cupcake"); - require(cupcakeBalances[address(this)] >= amount, "Not enough cupcakes in stock to complete this purchase"); + require(msg.value >= amount * 1 ether, "每个纸杯蛋糕必须至少支付 1 ETH"); + require(cupcakeBalances[address(this)] >= amount, "库存中的纸杯蛋糕不足,无法完成此次购买"); cupcakeBalances[address(this)] -= amount; cupcakeBalances[msg.sender] += amount; } @@ -65,48 +64,48 @@ contract VendingMachine { 就像自动售货机让厂商不再需要员工一样,智能合约可以在许多行业中取代中间人。 -## 无需准入性 {#permissionless} +## 无需许可 {#permissionless} -任何人都可以编写智能合约并将其部署到区块链网络上。 你只需要学习如何用[智能合约语言编码](/developers/docs/smart-contracts/languages/),并有足够的以太币来部署你的合约。 部署智能合约在技术上是一笔交易,因此就像你需要为简单的以太币转账支付燃料费一样,你也需要为部署智能合约支付[燃料费](/developers/docs/gas/)。 但是,合约部署的燃料成本要高得多。 +任何人都可以编写智能合约并将其部署到区块链网络上。 你只需要学习如何用[智能合约语言](/developers/docs/smart-contracts/languages/)进行编码,并拥有足够的 ETH 来部署你的合约。 部署智能合约在技术上是一笔交易,因此你需要支付[燃料](/developers/docs/gas/),就像为简单的 ETH 转账支付燃料一样。 但是,合约部署的燃料成本要高得多。 以太坊提供了对开发者友好的智能合约编程语言: - Solidity - Vyper -[关于语言的更多信息](/developers/docs/smart-contracts/languages/) +[更多关于语言](/developers/docs/smart-contracts/languages/) -然而,智能合约必须要先编译才能部署,以便以太坊虚拟机可以解释并存储它们。 [关于编译的更多信息](/developers/docs/smart-contracts/compiling/) +然而,智能合约必须要先编译才能部署,以便以太坊虚拟机可以解释并存储它们。 [更多关于编译](/developers/docs/smart-contracts/compiling/) ## 可组合性 {#composability} 智能合约在以太坊上公开,并且可以看成开放应用程序接口。 这意味着你可以在自己的智能合约中调用其他智能合约,以大幅扩展可能的功能。 合约甚至可以部署其他合约。 -了解关于[智能合约可组合性](/developers/docs/smart-contracts/composability/)的更多信息。 +了解更多关于[智能合约可组合性](/developers/docs/smart-contracts/composability/)的信息。 ## 局限性 {#limitations} 智能合约本身无法获取有关“现实世界”事件的信息,因为它们无法从链下来源检索数据。 这意味着它们无法对现实世界中的事件作出响应。 这是设计使然。 因为依赖外部信息可能会影响共识,而共识对安全性和去中心化而言十分重要。 -然而,对于区块链应用程序来说,能够使用链下数据非常重要。 解决方案是[预言机](/developers/docs/oracles/),它们是将链下数据引入并供智能合约使用的工具。 +然而,对于区块链应用程序来说,能够使用链下数据非常重要。 解决方案是[预言机](/developers/docs/oracles/),这是一种可以引入链下数据并提供给智能合约使用的工具。 -智能合约的另一个限制是最大合约大小。 智能合约最大可达 24 KB,否则会消耗完燃料。 可以使用[钻石模式](https://eips.ethereum.org/EIPS/eip-2535)来规避它。 +智能合约的另一个限制是最大合约大小。 智能合约最大可达 24 KB,否则会消耗完燃料。 这个问题可以通过使用[钻石模式](https://eips.ethereum.org/EIPS/eip-2535)来规避。 -## 多重签名合约 {#multisig} +## 多签合约 {#multisig} -多重签名合约是需要多个有效签名才能执行交易的智能合约帐户。 这对于避免持有大量以太币或其他代币的合约出现单点故障非常有用。 多重签名还可以在多方之间划分合同执行和密钥管理的责任,并防止丢失单个私钥导致不可逆转的资金损失。 由于这些原因,多重签名合约可用于简单的去中心化自治组织治理。 多重签名需要 M 个可能的可接受签名中的 N 个签名才能执行(其中 N ≤ M,并且 M > 1)。 普遍使用 `N = 3, M = 5` 和 `N = 4, M = 7`。 4/7 多重签名需要七个可能的有效签名中的四个。 这意味着即使失去了三个签名,资金仍然可以收回。 在这种情况下,这也意味着必须得到大多数密钥持有人的同意和签名才能执行合约。 +多重签名合约是需要多个有效签名才能执行交易的智能合约帐户。 这对于避免持有大量以太币或其他代币的合约出现单点故障非常有用。 多重签名还可以在多方之间划分合同执行和密钥管理的责任,并防止丢失单个私钥导致不可逆转的资金损失。 由于这些原因,多重签名合约可用于简单的去中心化自治组织治理。 多签需要从 M 个可能的可接受签名中获得 N 个签名才能执行(其中 N ≤ M,且 M > 1)。 通常使用 `N = 3, M = 5` 和 `N = 4, M = 7`。 4/7 多重签名需要七个可能的有效签名中的四个。 这意味着即使失去了三个签名,资金仍然可以收回。 在这种情况下,这也意味着必须得到大多数密钥持有人的同意和签名才能执行合约。 ## 智能合约资源 {#smart-contract-resources} -**OpenZeppelin 合约**** - _安全智能合约开发库。_** +**OpenZeppelin Contracts -** **_安全智能合约开发库。_** - [openzeppelin.com/contracts/](https://openzeppelin.com/contracts/) - [GitHub](https://github.com/OpenZeppelin/openzeppelin-contracts) - [社区论坛](https://forum.openzeppelin.com/c/general/16) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [Coinbase:什么是智能合约?](https://www.coinbase.com/learn/crypto-basics/what-is-a-smart-contract) - [Chainlink:什么是智能合约?](https://chain.link/education/smart-contracts) -- [视频:智能合约简介](https://youtu.be/ZE2HxTmxfrI) -- [Cyfrin Updraft:Web3 学习与审计平台](https://updraft.cyfrin.io) +- [视频:简明解释 - 智能合约](https://youtu.be/ZE2HxTmxfrI) +- [Cyfrin Updraft:Web3 学习和审计平台](https://updraft.cyfrin.io) diff --git a/public/content/translations/zh/developers/docs/smart-contracts/languages/index.md b/public/content/translations/zh/developers/docs/smart-contracts/languages/index.md index 98d353b80bb..efca2340e0d 100644 --- a/public/content/translations/zh/developers/docs/smart-contracts/languages/index.md +++ b/public/content/translations/zh/developers/docs/smart-contracts/languages/index.md @@ -1,19 +1,19 @@ --- -title: 智能合约语言 -description: 两种主要的智能合约语言(Solidity 和 Vyper)的概述和比较。 +title: "智能合约语言" +description: "两种主要的智能合约语言(Solidity 和 Vyper)的概述和比较。" lang: zh --- -关于以太坊的一个重要方面是,智能合约可以使用相对友好的开发者语言编程。 如果你熟悉 Python 或任何[大括号语言](https://wikipedia.org/wiki/List_of_programming_languages_by_type#Curly-bracket_languages),可以找到一种语法熟悉的语言。 +关于以太坊的一个重要方面是,智能合约可以使用相对友好的开发者语言编程。 如果你有 Python 或任何[花括号语言](https://wikipedia.org/wiki/List_of_programming_languages_by_type#Curly-bracket_languages)的经验,你可以找到一种语法熟悉的语言。 最受欢迎和维护得最好的两种语言是: - Solidity - Vyper -Remix 集成开发环境提供了一个全面的开发环境,用于创建和测试用 Solidity 和 Vyper 语言编写的智能合约。 [尝试使用浏览器版本的 Remix 集成开发环境](https://remix.ethereum.org)开始编写代码。 +Remix 集成开发环境提供了一个全面的开发环境,用于创建和测试用 Solidity 和 Vyper 语言编写的智能合约。 [试用浏览器内置的 Remix IDE](https://remix.ethereum.org) 开始编码。 -更有经验的开发者也可能想要使用 Yul:一种用于[以太坊虚拟机](/developers/docs/evm/)的中间语言,或者是 Yul+ 语言,这是一种 Yul 扩展。 +经验更丰富的开发者可能还想使用 Yul(一种用于[以太坊虚拟机](/developers/docs/evm/)的中间语言)或 Yul+(Yul 的扩展)。 如果你很好奇,喜欢帮助测试仍在大力发展的新语言,则可以尝试使用 Fe,这是一种新兴的智能合约语言,目前仍处于起步阶段。 @@ -33,49 +33,49 @@ Remix 集成开发环境提供了一个全面的开发环境,用于创建和 ### 重要链接 {#important-links} -- [相关文档](https://docs.soliditylang.org/en/latest/) -- [Solidity 语言网站](https://soliditylang.org/) +- [文档](https://docs.soliditylang.org/en/latest/) +- [Solidity 语言门户](https://soliditylang.org/) - [Solidity 示例](https://docs.soliditylang.org/en/latest/solidity-by-example.html) - [GitHub](https://github.com/ethereum/solidity/) -- 桥接到 [Solidity Matrix 聊天室](https://matrix.to/#/#ethereum_solidity:gitter.im)的 [Solidity Gitter 聊天室](https://gitter.im/ethereum/solidity) -- [备忘单](https://reference.auditless.com/cheatsheet) +- [Solidity Gitter 聊天室](https://gitter.im/ethereum/solidity)桥接至 [Solidity Matrix 聊天室](https://matrix.to/#/#ethereum_solidity:gitter.im) +- [速查表](https://reference.auditless.com/cheatsheet) - [Solidity 博客](https://blog.soliditylang.org/) - [Solidity Twitter](https://twitter.com/solidity_lang) -### 合约示例 {#example-contract} +### 示例合约 {#example-contract} ```solidity -/ SPDX-License-Identifier: GPL-3.0 +// SPDX-License-Identifier: GPL-3.0 pragma solidity >= 0.7.0; contract Coin { - // The keyword "public" makes variables - // accessible from other contracts + // 关键字“public”使变量 + // 可从其他合约访问 address public minter; mapping (address => uint) public balances; - // Events allow clients to react to specific - // contract changes you declare + // 事件允许客户端对你声明的特定 + // 合约更改做出反应 event Sent(address from, address to, uint amount); - // Constructor code is only run when the contract - // is created + // 构造函数代码仅在创建 + // 合约时运行 constructor() { minter = msg.sender; } - // Sends an amount of newly created coins to an address - // Can only be called by the contract creator + // 将一定数量的新创建的代币发送到一个地址 + // 只能由合约创建者调用 function mint(address receiver, uint amount) public { require(msg.sender == minter); require(amount < 1e60); balances[receiver] += amount; } - // Sends an amount of existing coins - // from any caller to an address + // 从任何调用者向一个地址 + // 发送一定数量的现有代币 function send(address receiver, uint amount) public { - require(amount <= balances[msg.sender], "Insufficient balance."); + require(amount <= balances[msg.sender], "余额不足。"); balances[msg.sender] -= amount; balances[receiver] += amount; emit Sent(msg.sender, receiver, amount); @@ -83,7 +83,7 @@ contract Coin { } ``` -这个示例应该能让你感觉到 Solidity 合约语法是什么样子的。 有关函数和变量的详细说明,[请参阅文档](https://docs.soliditylang.org/en/latest/contracts.html)。 +这个示例应该能让你感觉到 Solidity 合约语法是什么样子的。 有关函数和变量的更详细说明,[请参阅文档](https://docs.soliditylang.org/en/latest/contracts.html)。 ## Vyper {#vyper} @@ -101,104 +101,107 @@ contract Coin { - 无限长度循环 - 二进制定长浮点 -更多信息,[请查阅 Vyper 原理](https://vyper.readthedocs.io/en/latest/index.html)。 +更多信息,请[阅读 Vyper 的设计原理](https://vyper.readthedocs.io/en/latest/index.html)。 -### 重要的链接 {#important-links-1} +### 重要链接 {#important-links-1} -- [相关文档](https://vyper.readthedocs.io) +- [文档](https://vyper.readthedocs.io) - [Vyper 示例](https://vyper.readthedocs.io/en/latest/vyper-by-example.html) - [更多 Vyper 示例](https://vyper-by-example.org/) - [GitHub](https://github.com/vyperlang/vyper) - [Vyper 社区 Discord 聊天](https://discord.gg/SdvKC79cJk) -- [备忘单](https://reference.auditless.com/cheatsheet) -- [Vyper 的智能合约开发框架和工具](/developers/docs/programming-languages/python/) -- [VyperPunk - 学习保护和破解 Vyper 智能合约](https://github.com/SupremacyTeam/VyperPunk) -- [Vyper 开发中心](https://github.com/zcor/vyper-dev) -- [Vyper 最热门的智能合约示例](https://github.com/pynchmeister/vyper-greatest-hits/tree/main/contracts) -- [出色的 Vyper 精选资源](https://github.com/spadebuilders/awesome-vyper) +- [速查表](https://reference.auditless.com/cheatsheet) +- [适用于 Vyper 的智能合约开发框架和工具](/developers/docs/programming-languages/python/) +- [VyperPunk - 学习如何保护和破解 Vyper 智能合约](https://github.com/SupremacyTeam/VyperPunk) +- [用于开发的 Vyper Hub](https://github.com/zcor/vyper-dev) +- [Vyper 智能合约最佳示例](https://github.com/pynchmeister/vyper-greatest-hits/tree/main/contracts) +- [Awesome Vyper 精选资源](https://github.com/spadebuilders/awesome-vyper) ### 示例 {#example} ```python -# Open Auction +# 公开拍卖 -# Auction params -# Beneficiary receives money from the highest bidder +# 拍卖参数 +# 受益人从最高出价者处收款 beneficiary: public(address) auctionStart: public(uint256) auctionEnd: public(uint256) -# Current state of auction +# 拍卖的当前状态 highestBidder: public(address) highestBid: public(uint256) -# Set to true at the end, disallows any change +# 结束时设置为 true,不允许任何更改 ended: public(bool) -# Keep track of refunded bids so we can follow the withdraw pattern +# 跟踪已退还的出价,以便遵循取款模式 pendingReturns: public(HashMap[address, uint256]) + +# 创建一个简单拍卖,代表受益人地址 `_beneficiary`, +# 拍卖时间为 `_bidding_time` 秒。 @external def __init__(_beneficiary: address, _bidding_time: uint256): self.beneficiary = _beneficiary self.auctionStart = block.timestamp self.auctionEnd = self.auctionStart + _bidding_time -# Bid on the auction with the value sent -# together with this transaction. -# The value will only be refunded if the -# auction is not won. +# 使用与此交易一起发送的价值对拍卖进行出价。 +# 只有未赢得拍卖, +# 价值才会被退还。 @external @payable def bid(): - # Check if bidding period is over. + # 检查出价期是否结束。 assert block.timestamp < self.auctionEnd - # Check if bid is high enough + # 检查出价是否足够高 assert msg.value > self.highestBid - # Track the refund for the previous high bidder + # 跟踪先前最高出价者的退款 self.pendingReturns[self.highestBidder] += self.highestBid - # Track new high bid + # 跟踪新的最高出价 self.highestBidder = msg.sender - self.highestBid = msg.value The withdraw pattern is -# used here to avoid a security issue. If refunds were directly -# sent as part of bid(), a malicious bidding contract could block -# those refunds and thus block new higher bids from coming in. + self.highestBid = msg.value + +# 取回先前已退还的出价。此处使用取款模式 +# 以避免安全问题。如果退款直接 +# 作为 bid() 的一部分发送,恶意出价合约可能会阻止 +# 这些退款,从而阻止新的更高出价进入。 @external def withdraw(): pending_amount: uint256 = self.pendingReturns[msg.sender] self.pendingReturns[msg.sender] = 0 send(msg.sender, pending_amount) -# End the auction and send the highest bid -# to the beneficiary. +# 结束拍卖并将最高出价 +# 发送给受益人。 @external def endAuction(): - # It is a good guideline to structure functions that interact - # with other contracts (i.e., they call functions or send ether) - # into three phases: - # 1. checking conditions - # 2. performing actions (potentially changing conditions) - # 3. interacting with other contracts - # If these phases are mixed up, the other contract could call - # back into the current contract and modify the state or cause - # effects (ether payout) to be performed multiple times. - # If functions called internally include interaction with external - # contracts, they also have to be considered interaction with - # external contracts. - - # 1. Conditions - # Check if auction endtime has been reached + # 一个好的指导原则是将与其他合约交互的函数(即调用函数或发送以太币) + # 结构化为三个阶段: + # 1. 检查条件 + # 2. 执行操作(可能会改变条件) + # 3. 与其他合约交互 + # 如果这些阶段混合在一起,另一个合约可能会回调 + # 到当前合约并修改状态或导致 + # 效果(以太币支付)被多次执行。 + # 如果内部调用的函数包含与外部合约的交互, + # 它们也必须被视为与 + # 外部合约的交互。 + + # 1. 条件 + # 检查是否已达到拍卖结束时间 assert block.timestamp >= self.auctionEnd - # Check if this function has already been called + # 检查此函数是否已被调用 assert not self.ended - # 2. Effects + # 2. 效果 self.ended = True - # 3. Interaction + # 3. 交互 send(self.beneficiary, self.highestBid) ``` -这个例子应该让你了解 Vyper 合约语法是什么样的。 有关函数和变量的详细说明,[请参阅文档](https://vyper.readthedocs.io/en/latest/vyper-by-example.html#simple-open-auction)。 +这个例子应该让你了解 Vyper 合约语法是什么样的。 有关函数和变量的更详细说明,[请参阅文档](https://vyper.readthedocs.io/en/latest/vyper-by-example.html#simple-open-auction)。 ## Yul 和 Yul+ {#yul} @@ -207,24 +210,25 @@ def endAuction(): **Yul** - 以太坊的中继语言。 -- 支持 [EVM](/developers/docs/evm) 和 [Ewasm](https://github.com/ewasm),一种以太坊风格的 WebAssembly,以及旨在成为两个平台均可用的公分母。 -- 高级优化阶段的良好目标,既使 EVM 和 eWASM 平台均等受益。 +- 支持 [EVM](/developers/docs/evm) 和 [Ewasm](https://github.com/ewasm)(一种以太坊风格的 WebAssembly),旨在成为这两个平台的通用分母。 +- 是高级优化阶段的理想目标,可使 EVM 和 Ewasm 平台同等受益。 **Yul+** - Yul 的低级、高效扩展。 -- 最初设计用于[乐观卷叠](/developers/docs/scaling/optimistic-rollups/)合约。 +- 最初为[乐观卷叠](/developers/docs/scaling/optimistic-rollups/)合约而设计。 - Yul+ 可以被视为对 Yul 的实验性升级建议,为其添加新功能。 -### 重要的链接 {#important-links-2} +### 重要链接 {#important-links-2} -- [Yul 相关文档](https://docs.soliditylang.org/en/latest/yul.html) -- [Yul+ 相关文档](https://github.com/fuellabs/yulp) -- [Yul+ 介绍帖子](https://medium.com/@fuellabs/introducing-yul-a-new-low-level-language-for-ethereum-aa64ce89512f) +- [Yul 文档](https://docs.soliditylang.org/en/latest/yul.html) +- [Yul+ 文档](https://github.com/fuellabs/yulp) +- [Yul+ 介绍文章](https://medium.com/@fuellabs/introducing-yul-a-new-low-level-language-for-ethereum-aa64ce89512f) -### 合约示例 {#example-contract-2} +### 示例合约 {#example-contract-2} -以下简单示例实现了幂函数。 它可以使用 `solc --strict-assembly --bin input.yul` 编译。 这个例子应该 存储在 input.yul 文件中。 +以下简单示例实现了幂函数。 可以使用 `solc --strict-assembly --bin input.yul` 对其进行编译。 这个例子应该 +存储在 input.yul 文件中。 ``` { @@ -245,7 +249,7 @@ def endAuction(): } ``` -如果你已经熟悉智能合约,可以在 [此处找到 Yul 中的完整 ERC20 实例](https://solidity.readthedocs.io/en/latest/yul.html#complete-erc20-example)。 +如果你对智能合约已非常有经验,可以在[此处](https://solidity.readthedocs.io/en/latest/yul.html#complete-erc20-example)找到用 Yul 实现的完整 ERC20。 ## Fe {#fe} @@ -259,10 +263,10 @@ def endAuction(): - [GitHub](https://github.com/ethereum/fe) - [Fe 公告](https://snakecharmers.ethereum.org/fe-a-new-language-for-the-ethereum-ecosystem/) - [Fe 2021 路线图](https://notes.ethereum.org/LVhaTF30SJOpkbG1iVw1jg) -- [Fe Discord 聊天室](https://discord.com/invite/ywpkAXFjZH) +- [Fe Discord 聊天](https://discord.com/invite/ywpkAXFjZH) - [Fe Twitter](https://twitter.com/official_fe) -### 合约示例 {#example-contract-3} +### 示例合约 {#example-contract-3} 以下是在 Fe 中执行的简单的智能合约。 @@ -282,7 +286,6 @@ contract GuestBook: pub def get_msg(addr: address) -> BookMsg: return self.guest_book[addr].to_mem() - ``` ## 如何选择 {#how-to-choose} @@ -293,7 +296,7 @@ contract GuestBook: ### Solidity 的优点是什么? {#solidity-advantages} -- 如果你是初学者,这里有很多教程和学习工具。 在[通过编码学习](/developers/learning-tools/)部分了解更多相关信息。 +- 如果你是初学者,这里有很多教程和学习工具。 在[“通过编码学习”](/developers/learning-tools/)部分查看更多相关信息。 - 提供出色的开发者工具。 - Solidity 拥有庞大的开发人员社区,这意味着你很可能会很快找到问题的答案。 @@ -310,9 +313,9 @@ contract GuestBook: ## 语言比较 {#language-comparisons} -关于基本语法的比较、合同生命周期、接口、操作员、数据结构、功能、控制流程以及更多,请查看[由 Auditless 编写的备忘清单](https://reference.auditless.com/cheatsheet/) +要比较基本语法、合约生命周期、接口、运算符、数据结构、函数、控制流等,请查看 [Auditless 制作的这份速查表](https://reference.auditless.com/cheatsheet/) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [OpenZeppelin 的 Solidity 合约库](https://docs.openzeppelin.com/contracts/5.x/) - [Solidity 示例](https://solidity-by-example.org) diff --git a/public/content/translations/zh/developers/docs/smart-contracts/libraries/index.md b/public/content/translations/zh/developers/docs/smart-contracts/libraries/index.md index cfd3ccea2dd..4151354d085 100644 --- a/public/content/translations/zh/developers/docs/smart-contracts/libraries/index.md +++ b/public/content/translations/zh/developers/docs/smart-contracts/libraries/index.md @@ -1,26 +1,26 @@ --- -title: 智能合约库 -description: +title: "智能合约库" +description: "探索可重用的智能合约库和构建块来加速你的以太坊开发项目。" lang: zh --- 你无需从头开始编写项目中的每一个智能合约 我们有许多开源代码的智能合约库可为你的项目提供可重复利用的构建块,从而使你不必重新开始。 -## 前置要求 {#prerequisites} +## 前提条件 {#prerequisites} -在我们跳转到智能合约库之前,清楚地了解一个智能合约的构成是一个不错的主意。 如果尚未进行智能合约的了解,请直接点击[智能合约](/developers/docs/smart-contracts/anatomy/)。 +在我们跳转到智能合约库之前,清楚地了解一个智能合约的构成是一个不错的主意。 若您尚未阅读[智能合约剖析](/developers/docs/smart-contracts/anatomy/),请前往阅读。 -## 资料库中的内容 {#whats-in-a-library} +## 程序库中有什么 {#whats-in-a-library} 你通常可以在智能合约库中找到两种构建模块:可以添加到合约中的可复用代码,与各种标准的实现。 ### 行为 {#behaviors} -当编写智能合约时,你很可能会发现自己在写重复的代码。 比如说在智能合约中指派一个_管理员_地址执行受保护的操作,或添加一个紧急_暂停_按钮以应对预料不到的问题。 +编写智能合约时,您很有可能会发现自己需要反复编写类似的模式,例如,指定一个_管理员_地址来执行合约中受保护的操作,或在发生意外问题时添加紧急_暂停_按钮。 -智能合约库通常提供这些行为的可复用实现方式为[标准库](https://solidity.readthedocs.io/en/v0.7.2/contracts.html#libraries)或在 solidity 中通过[继承](https://solidity.readthedocs.io/en/v0.7.2/contracts.html#inheritance)的方式实现。 +智能合约程序库通常在 Solidity 中以[程序库](https://solidity.readthedocs.io/en/v0.7.2/contracts.html#libraries)或通过[继承](https://solidity.readthedocs.io/en/v0.7.2/contracts.html#inheritance)的形式,为这些行为提供可重用的实现。 -例如,以下是[`不可拥有的`合约的简化版本](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.0/contracts/access/Ownable.sol)来自 [OpenZeppelin 合约库](https://github.com/OpenZeppelin/openzeppelin-contracts),它设计了一个作为合约所有者的地址,并且提供了一个修饰者来限制该所有者获得一种方法。 +例如,下面是 [OpenZeppelin 合约程序库](https://github.com/OpenZeppelin/openzeppelin-contracts)中 [`Ownable` 合约](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.0/contracts/access/Ownable.sol)的简化版本,它将一个地址指定为合约的所有者,并提供一个修饰符,用于将方法的访问权限限制为仅该所有者可用。 ```solidity contract Ownable { @@ -37,7 +37,7 @@ contract Ownable { } ``` -在你的合约中使用这个构建模块,你需要先导入它,然后在你自己的合约中扩展它。 这个将会允许你使用 `Ownable` 合约提供的修改器来保护你的函数。 +在你的合约中使用这个构建模块,你需要先导入它,然后在你自己的合约中扩展它。 这样,您就可以使用基础 `Ownable` 合约提供的修饰符来保护自己的函数。 ```solidity import ".../Ownable.sol"; // Path to the imported library @@ -50,19 +50,19 @@ contract MyContract is Ownable { } ``` -另一个比较受欢迎的例子是 [SafeMath](https://docs.openzeppelin.com/contracts/3.x/utilities#math) 或[DsMath](https://dappsys.readthedocs.io/en/latest/ds_math.html)。 这些库(与基础合约不同)提供了语言本身不具有的带有溢出检查的算术函数。 使用这些库而不是本地的算术操作可以来防止你的合约出现溢出错误,这些错误可能会导致灾难性的后果! +另一个流行的示例是 [SafeMath](https://docs.openzeppelin.com/contracts/3.x/utilities#math) 或 [DsMath](https://dappsys.readthedocs.io/en/latest/ds_math.html)。 这些库(与基础合约不同)提供了语言本身不具有的带有溢出检查的算术函数。 使用这些库而不是本地的算术操作可以来防止你的合约出现溢出错误,这些错误可能会导致灾难性的后果! ### 标准 {#standards} -为了促进[可组合性和互操作性](/developers/docs/smart-contracts/composability/),以太坊社区已经以**以太坊意见征求**的形式定义了几个标准。 你可以在[标准](/developers/docs/standards/)部分阅读更多关于他们的信息。 +为促进[可组合性和互操作性](/developers/docs/smart-contracts/composability/),以太坊社区以 **ERC** 的形式定义了多项标准。 您可以在[标准](/developers/docs/standards/)部分阅读有关这些标准的更多信息。 -当将以太坊意见征求作为你的合约的一部分时,更好的做法是寻找已有的标准去实现而不是试图推出你自己的方式。 许多智能合约库包含了最流行的以太坊意见征求标准的实现。 例如,普遍存在的 [ERC20 同质化通证标准](/developers/tutorials/understand-the-erc-20-token-smart-contract/)可在 [HQ20](https://github.com/HQ20/contracts/blob/master/contracts/token/README.md) [DappSys](https://github.com/dapphub/ds-token/) 和 [OpenZeppelin](https://docs.openzeppelin.com/contracts/3.x/erc20) 中找到。 此外,一些以太坊意见征求还提供规范实现作为以太坊意见征求本身的一部分。 +当将以太坊意见征求作为你的合约的一部分时,更好的做法是寻找已有的标准去实现而不是试图推出你自己的方式。 许多智能合约库包含了最流行的以太坊意见征求标准的实现。 例如,无处不在的 [ERC20 同质化代币标准](/developers/tutorials/understand-the-erc-20-token-smart-contract/)可以在 [HQ20](https://github.com/HQ20/contracts/blob/master/contracts/token/README.md)、[DappSys](https://github.com/dapphub/ds-token/) 和 [OpenZeppelin](https://docs.openzeppelin.com/contracts/3.x/erc20) 中找到。 此外,一些以太坊意见征求还提供规范实现作为以太坊意见征求本身的一部分。 -值得一提的是,一些以太坊意见征求不是独立的,而是对其他以太坊意见征求的补充。 例如, [ERC2612](https://eips.ethereum.org/EIPS/eip-2612) 为 ERC20 添加了一个扩展,以提高其可用性。 +值得一提的是,一些以太坊意见征求不是独立的,而是对其他以太坊意见征求的补充。 例如,[ERC2612](https://eips.ethereum.org/EIPS/eip-2612) 为 ERC20 添加了一个扩展,以提高其可用性。 -## 如何添加库 {#how-to} +## 如何添加程序库 {#how-to} -始终参考你所包含的库的文档,以获得关于如何将其包含在你的项目中的具体说明 一些 Solidity 合约库使用 `npm` 来打包,所以你可以直接 `npm` 安装它们。 大多数[编译](/developers/docs/smart-contracts/compiling/)合约的工具会在你的 `node_modules` 中查找智能合约库,所以你可以做以下工作。 +始终参考你所包含的库的文档,以获得关于如何将其包含在你的项目中的具体说明 一些 Solidity 合约程序库使用 `npm` 打包,因此您只需 `npm install` 即可安装它们。 大多数[编译](/developers/docs/smart-contracts/compiling/)合约的工具都会在您的 `node_modules` 中查找智能合约程序库,因此您可以执行以下操作: ```solidity // This will load the @openzeppelin/contracts library from your node_modules @@ -73,13 +73,13 @@ contract MyNFT is ERC721 { } ``` -无论你使用哪种方法,当包括一个库时,总是要注意[语言](/developers/docs/smart-contracts/languages/)的版本。 例如,如果你用 Solidity 0.5 编写你的合约,你就不能使用 Solidity 0.6 的库。 +无论您使用哪种方法,在引入程序库时,请务必留意[语言](/developers/docs/smart-contracts/languages/)版本。 例如,如果你用 Solidity 0.5 编写你的合约,你就不能使用 Solidity 0.6 的库。 ## 何时使用 {#when-to-use} 为你的项目使用智能合约库有几个好处。 首先,它为你提供了现成的构建模块,你可以将其纳入你的系统,而不必自己编码,从而节省了你的时间。 -安全性也是一个重要的优点。 开源智能合约库也经常受到严格审查。 鉴于许多项目都依赖于它们,社区有强烈的动机来对它们持续审计。 在应用程序代码中发现错误比在可重用的合约库中发现错误要常见得多。 一些库还接受了[外部审计](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/audits),以提高安全性。 +安全性也是一个重要的优点。 开源智能合约库也经常受到严格审查。 鉴于许多项目都依赖于它们,社区有强烈的动机来对它们持续审计。 在应用程序代码中发现错误比在可重用的合约库中发现错误要常见得多。 为增强安全性,有些程序库还会经过[外部审计](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/audits)。 然而,使用智能合约库有可能将你不熟悉的代码纳入你的项目。 导入一个合约并将其直接包含在你的项目中是很诱人的,但如果没有很好地理解该合约的作用,你可能会由于一个意外的行为而无意中在你的系统中引入一个问题。 一定要确保阅读你要导入的代码的文档,然后在使其成为你的项目的一部分之前审查代码本身。 @@ -87,7 +87,7 @@ contract MyNFT is ERC721 { ## 相关工具 {#related-tools} -**OpenZeppelin 合约-** **_安全的智能合约开发库。_** +**OpenZeppelin 合约 -** **_最受欢迎的安全智能合约开发程序库。_** - [相关文档](https://docs.openzeppelin.com/contracts/) - [GitHub](https://github.com/OpenZeppelin/openzeppelin-contracts) @@ -98,20 +98,20 @@ contract MyNFT is ERC721 { - [相关文档](https://dappsys.readthedocs.io/) - [GitHub](https://github.com/dapphub/dappsys) -**HQ20 -** **_一个带有合约、库和案例的 Solidity 项目,帮助你为现实世界建立功能齐全的分布式应用。_** +**HQ20 -** **_一个 Solidity 项目,包含合约、程序库和示例,可帮助您为现实世界构建功能齐全的分布式应用程序。_** - [GitHub](https://github.com/HQ20/contracts) -**thirdweb Solidity SDK - ** **_提供了高效构建自定义智能合约所需的工具_** +**thirdweb Solidity SDK -** **_提供高效构建自定义智能合约所需的工具_** - [相关文档](https://portal.thirdweb.com/contracts/build/overview) - [GitHub](https://github.com/thirdweb-dev/contracts) ## 相关教程 {#related-tutorials} -- [以太坊开发者的安全考虑](/developers/docs/smart-contracts/security/) _– 构建智能合约时的安全注意事项教程,包括库的使用。_ -- [了解 ERC-20 代币智能合约](/developers/tutorials/understand-the-erc-20-token-smart-contract/) _- 关于 ERC20 标准的教程,由多个库提供。_ +- [以太坊开发者安全注意事项](/developers/docs/smart-contracts/security/)_– 关于构建智能合约时安全注意事项的教程,包括程序库的使用。_ +- [理解 ERC-20 代币智能合约](/developers/tutorials/understand-the-erc-20-token-smart-contract/) _- 关于 ERC20 标准的教程,由多个程序库提供。_ -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ diff --git a/public/content/translations/zh/developers/docs/smart-contracts/naming/index.md b/public/content/translations/zh/developers/docs/smart-contracts/naming/index.md new file mode 100644 index 00000000000..4227b228d49 --- /dev/null +++ b/public/content/translations/zh/developers/docs/smart-contracts/naming/index.md @@ -0,0 +1,101 @@ +--- +title: "为智能合约命名" +description: "使用 ENS 为以太坊智能合约命名的最佳实践" +lang: zh +--- + +智能合约是以太坊去中心化基础设施的基石,可实现自主应用程序和协议。 但即使合约功能不断发展,用户和开发者仍然依赖原始的十六进制地址来识别和引用这些合约。 + +使用[以太坊域名服务 (ENS)](https://ens.domains/) 为智能合约命名,可通过消除十六进制合约地址来改善用户体验,并降低地址中毒和欺骗攻击等攻击的风险。 本指南将解释为智能合约命名的重要性、实施方法,以及可用的工具(如 [Enscribe](https://www.enscribe.xyz)),以简化流程并帮助开发者采用这种做法。 + +## 为何要为智能合约命名? {#why-name-contracts} + +### 人类可读的标识符 {#human-readable-identifiers} + +开发者和用户可以使用 `v2.myapp.eth` 等人类可读的名称,而不用与 `0x8f8e...f9e3` 等不透明的合约地址进行交互。 这简化了智能合约的交互。 + +这得益于[以太坊域名服务](https://ens.domains/),该服务为以太坊地址提供去中心化的命名服务。 这类似于域名服务 (DNS) 让互联网用户能够使用 ethereum.org 等名称访问网络地址,而不是通过 `104.18.176.152` 等 IP 地址访问。 + +### 提高安全性和信任度 {#improved-security-and-trust} + +已命名的合约有助于减少向错误地址进行的意外交易。 它们还有助于用户识别与特定应用程序或品牌相关的合约。 这增加了一层声誉信任,尤其是当名称附加到像 `uniswap.eth` 这样知名的父域时。 + +由于以太坊地址的长度为 42 个字符,用户很难识别地址中的微小变化,即使用户只修改了几个字符。 例如,像钱包这样面向用户的应用程序通常会将 `0x58068646C148E313CB414E85d2Fe89dDc3426870` 这样的地址截断为 `0x580...870`。 用户不太可能注意到几个字符被更改的恶意地址。 + +地址欺骗和中毒攻击就采用了这种技术,诱使用户相信他们正在与正确的地址交互或向其发送资金,而实际上该地址只是与正确的地址相似,但并不相同。 + +用于钱包和合约的 ENS 名称可防范这些类型的攻击。 与 DNS 欺骗攻击一样,ENS 欺骗攻击也可能发生,但用户更有可能注意到 ENS 名称中的拼写错误,而不是十六进制地址中的微小修改。 + +### 为钱包和浏览器提供更好的用户体验 {#better-ux} + +当智能合约配置了 ENS 名称后,钱包和区块链浏览器等应用程序就可以显示智能合约的 ENS 名称,而不是十六进制地址。 这为用户带来了显著的用户体验 (UX) 提升。 + +例如,当与 Uniswap 等应用程序交互时,用户通常会看到他们交互的应用程序托管在 `uniswap.org` 网站上,但如果 Uniswap 没有使用 ENS 为其智能合约命名,他们将看到一个十六进制的合约地址。 如果合约已命名,他们可以看到更有用的 `v4.contracts.uniswap.eth`。 + +## 在部署时命名与部署后命名 {#when-to-name} + +有两种为智能合约命名的时间点: + +- **部署时**:在部署合约时为其分配一个 ENS 名称。 +- **部署后**:将现有的合约地址映射到一个新的 ENS 名称。 + +这两种方法都依赖于拥有 ENS 域的所有者或管理员访问权限,以便他们可以创建和设置 ENS 记录。 + +## ENS 如何为合约命名 {#how-ens-naming-works} + +ENS 名称存储在链上,并通过 ENS 解析器解析为以太坊地址。 为智能合约命名: + +1. 注册或控制一个父 ENS 域(例如 `myapp.eth`) +2. 创建一个子域(例如 `v1.myapp.eth`) +3. 将子域的 `address` 记录设置为合约地址 +4. 将合约的反向记录设置为 ENS,以便通过其地址找到该名称 + +ENS 名称是分层的,支持无限的子名称。 设置这些记录通常需要与 ENS 注册表和公共解析器合约进行交互。 + +## 合约命名工具 {#tools} + +有两种命名智能合约的方法。 一种是使用 [ENS 应用程序](https://app.ens.domains) 并进行一些手动步骤,另一种是使用 [Enscribe](https://www.enscribe.xyz)。 下文将对此进行概述。 + +### 手动设置 ENS {#manual-ens-setup} + +使用 [ENS 应用程序](https://app.ens.domains/),开发者可以手动创建子名称并设置正向地址记录。 但是,他们不能通过 ENS 应用程序为名称设置反向记录来为智能合约设置主名称。 必须采取手动步骤,相关内容在 [ENS 文档](https://docs.ens.domains/web/naming-contracts/) 中有介绍。 + +### Enscribe {#enscribe} + +[Enscribe](https://www.enscribe.xyz) 简化了使用 ENS 的智能合约命名,并增强了用户对智能合约的信任。 它提供: + +- **原子化部署和命名**:在部署新合约时分配 ENS 名称 +- **部署后命名**:将名称附加到已部署的合约上 +- **多链支持**:适用于支持 ENS 的以太坊和 L2 网络 +- **合约验证数据**:包含从多个来源获取的合约验证数据,以增加用户的信任度 + +Enscribe 支持用户提供的 ENS 名称,如果用户没有 ENS 名称,也支持其自己的域名。 + +您可以访问 [Enscribe App](https://app.enscribe.xyz) 来开始命名和查看智能合约。 + +## 最佳实践 {#best-practices} + +- **使用清晰的版本化名称**,例如 `v1.myapp.eth`,使合约升级透明化 +- **设置反向记录**以将合约链接到 ENS 名称,以便在钱包和区块链浏览器等应用程序中可见。 +- 如果您想防止所有权意外变更,请**密切监控到期时间** +- **验证合约来源**,以便用户可以相信已命名的合约会按预期运行 + +## 风险 {#risks} + +为智能合约命名可为以太坊用户带来巨大好处,但是,ENS 域的所有者必须对其管理保持警惕。 值得注意的风险包括: + +- **到期**:与 DNS 名称一样,ENS 名称注册的期限也是有限的。 因此,所有者必须监控其域的到期日期,并在到期前及时续订。 ENS 应用程序和 Enscribe 都会在即将到期时为域名所有者提供视觉指示。 +- **所有权变更**:ENS 记录在以太坊上表示为 NFT,特定 `.eth` 域的所有者拥有相关的 NFT。 因此,如果一个不同的帐户获得了该 NFT 的所有权,新所有者可以根据自己的需要修改任何 ENS 记录。 + +为降低此类风险,`.eth` 二级域名 (2LD) 的所有者帐户应通过多签钱包来确保安全,并创建子域来管理合约命名。 这样,万一在子域级别发生任何意外或恶意的所有权变更,2LD 所有者可以将其覆盖。 + +## 合约命名的未来 {#future} + +合约命名正在成为去中心化应用程序开发的最佳实践,类似于域名在网络上取代 IP 地址的方式。 随着钱包、浏览器和仪表板等更多基础设施集成了合约的 ENS 解析,已命名的合约将提高整个生态系统的安全性并减少错误。 + +通过使智能合约更易于识别和理解,命名有助于弥合以太坊上用户与应用程序之间的差距,从而提高用户的安全性和用户体验。 + +## 扩展阅读{#further-reading} + +- [使用 ENS 命名智能合约](https://docs.ens.domains/web/naming-contracts/) +- [使用 Enscribe 命名智能合约](https://www.enscribe.xyz/docs)。 diff --git a/public/content/translations/zh/developers/docs/smart-contracts/security/index.md b/public/content/translations/zh/developers/docs/smart-contracts/security/index.md index e058ab091bd..664f30bc0ef 100644 --- a/public/content/translations/zh/developers/docs/smart-contracts/security/index.md +++ b/public/content/translations/zh/developers/docs/smart-contracts/security/index.md @@ -1,54 +1,54 @@ --- -title: 智能合约安全性 -description: 安全的以太坊智能合约构建准则概述 +title: "智能合约安全性" +description: "安全的以太坊智能合约构建准则概述" lang: zh --- 智能合约极为灵活,能够控制大量的价值和数据,并在区块链上运行基于代码的不可改变逻辑。 因而,一个由去信任的去中心化应用程序构成的生态系统应运而生且充满活力,它具备了许多传统系统所没有的优势。 同时,这也给攻击者提供了利用智能合约中的漏洞来获利的机会。 -公共区块链(比如以太坊)使智能合约的安全性问题变的更加复杂。 已部署的合约代码_通常_无法更改因而不能给安全问题打补丁,并且由于这种不可变性,从智能合约中盗取的资产极难追踪并且绝大多数无法挽回。 +公共区块链(比如以太坊)使智能合约的安全性问题变的更加复杂。 已部署的合约代码_通常_无法更改以修补安全漏洞,而由于其不可变性,从智能合约中盗取的资产极难追踪且基本上无法追回。 -虽然统计数据有所差异,但据估计,由于智能合约的安全缺陷而被盗窃或丢失的资产总额肯定超过了 10 亿美元。 其中包括几次著名事件,比如 [DAO 攻击事件](https://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/)(360 万个以太币被盗,按照当前价格计算总金额超过 10 亿美元)、[Parity 多重签名钱包攻击事件](https://www.coindesk.com/markets/2017/07/19/30-million-ether-reported-stolen-due-to-parity-wallet-breach)(黑客窃取了 3000 万美元)以及 [Parity 钱包冻结问题](https://www.theguardian.com/technology/2017/nov/08/cryptocurrency-300m-dollars-stolen-bug-ether)(价值超过 3 亿美元的以太币遭到永久锁定)。 +虽然统计数据有所差异,但据估计,由于智能合约的安全缺陷而被盗窃或丢失的资产总额肯定超过了 10 亿美元。 其中包括一些备受瞩目的事件,例如 [DAO 黑客攻击](https://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/)(360 万 ETH 被盗,按当前价格计算价值超过 10 亿美元)、[Parity 多签钱包遭黑客攻击](https://www.coindesk.com/markets/2017/07/19/30-million-ether-reported-stolen-due-to-parity-wallet-breach)(黑客窃取了 3000 万美元),以及 [Parity 钱包冻结问题](https://www.theguardian.com/technology/2017/nov/08/cryptocurrency-300m-dollars-stolen-bug-ether)(价值超过 3 亿美元的 ETH 被永久锁定)。 上述几个事件迫使开发者必须付诸努力,构建安全、稳健、恢复力强的智能合约。 智能合约安全性是每个开发者都需要学习和研究的严肃问题。 本指南将介绍针对以太坊开发者的安全性注意事项,并研究增强智能合约安全性的资源。 -## 前言 {#prerequisites} +## 前提条件 {#prerequisites} -在开始研究安全性问题之前,请确保自己已经熟悉[智能合约开发的基础知识](/developers/docs/smart-contracts/)。 +在着手处理安全问题之前,请确保您熟悉[智能合约开发的基础知识](/developers/docs/smart-contracts/)。 -## 安全以太坊智能合约的构建准则 {#smart-contract-security-guidelines} +## 构建安全的以太坊智能合约指南 {#smart-contract-security-guidelines} -### 1. 设计合理的访问控制 {#design-proper-access-controls} +### 1. 设计适当的访问控制 {#design-proper-access-controls} -在智能合约中,带有 `public` 或 `external` 标记的函数可以被任何外部帐户 (EOA) 或者合约帐户调用。 如果你希望他人与你的合约交互,就必须为函数指定公共可见性。 然而,标记为 `private` 的函数只能被智能合约内部的函数调用,外部帐户无法调用。 为每个网络用户提供合约函数的访问权限会造成问题,尤其是当这种访问意味着任何人都能执行敏感操作(比如铸币)的情况。 +在智能合约中,标记为 `public` 或 `external` 的函数可由任何外部持有账户 (EOA) 或合约账户调用。 如果你希望他人与你的合约交互,就必须为函数指定公共可见性。 然而,标记为 `private` 的函数只能被智能合约内部的函数调用,外部帐户无法调用。 为每个网络用户提供合约函数的访问权限会造成问题,尤其是当这种访问意味着任何人都能执行敏感操作(比如铸币)的情况。 -为了防止未经授权使用智能合约函数,有必要实现安全访问控制。 访问控制机制将使用智能合约中某些特定函数的能力限定给经过核准的实体,例如负责管理合约的帐户。 两种模式有助于在智能合约中实现访问控制,**所有权模式**和**基于角色的控制**: +为了防止未经授权使用智能合约函数,有必要实现安全访问控制。 访问控制机制将使用智能合约中某些特定函数的能力限定给经过核准的实体,例如负责管理合约的帐户。 **所有权模式**和**基于角色的控制**是在智能合约中实现访问控制的两种有用模式: #### 所有权模式 {#ownable-pattern} -在所有权模式中,在合约创建过程中将地址设置为合约的“所有者”。 受保护的函数都分配有 `OnlyOwner` 修改器,这样可以确保合约在执行函数之前验证调用地址的身份。 从合约所有者以外的其他地址调用受保护的函数,始终会被回滚,阻止不必要的访问。 +在所有权模式中,在合约创建过程中将地址设置为合约的“所有者”。 受保护的函数被分配了一个 `OnlyOwner` 修饰符,这能确保合约在执行函数前验证调用地址的身份。 从合约所有者以外的其他地址调用受保护的函数,始终会被回滚,阻止不必要的访问。 #### 基于角色的访问控制 {#role-based-access-control} -在智能合约中将一个地址注册成 `Owner` 会引入中心化风险,并代表一种单点故障。 如果所有者的帐户密钥已泄露,攻击者就可以攻击其拥有的合约。 这就是采用基于角色的访问控制模式及多个管理帐户可能是更好方案的原因。 +在智能合约中将单个地址注册为 `Owner` 会引入中心化风险,并构成单点故障。 如果所有者的帐户密钥已泄露,攻击者就可以攻击其拥有的合约。 这就是采用基于角色的访问控制模式及多个管理帐户可能是更好方案的原因。 在基于角色的访问控制中,对敏感函数的访问分布在一组受信任的参与者之间。 例如,一个帐户可能负责铸造代币,而另一个帐户进行升级或暂停合约。 以这种方式分散访问控制,消除了单点故障并减少了对用户的信任假设。 ##### 使用多重签名钱包 -实施安全访问控制的另一种方法是使用[多重签名帐户](/developers/docs/smart-contracts/#multisig)来管理合约。 与常规外部帐户不同,多重签名帐户由多个实体拥有,需要最低数量的帐户签名(比如 5 个中的 3 个)才能执行交易。 +实现安全访问控制的另一种方法是使用[多签账户](/developers/docs/smart-contracts/#multisig)来管理合约。 与常规外部帐户不同,多重签名帐户由多个实体拥有,需要最低数量的帐户签名(比如 5 个中的 3 个)才能执行交易。 使用多重签名进行访问控制增加了额外一层安全性保障,因为需要多方同意才能对目标合约执行操作。 如果有必要使用所有权模式,这种方法尤其有用,因为攻击者或内部作恶者操控敏感的合约函数以达到恶毒目的会更加困难。 -### 2. 使用 require()、assert() 和 revert() 语句保护合约操作 {#use-require-assert-revert} +### 2. 使用 require()、assert() 和 revert() 语句来保护合约操作 {#use-require-assert-revert} -如上所述,一旦智能合约部署到区块链上,任何人都可以调用其中的公共函数。 由于无法事先知道外部帐户将如何与合约交互,因此最好在部署之前实施内部安全措施以防出现有问题的操作。 可以通过使用 `require()`、`assert()` 和 `revert()` 语句强制执行智能合约中的正确行为,在执行不满足某些要求时触发异常并回滚状态变化。 +如上所述,一旦智能合约部署到区块链上,任何人都可以调用其中的公共函数。 由于无法事先知道外部帐户将如何与合约交互,因此最好在部署之前实施内部安全措施以防出现有问题的操作。 您可以通过使用 `require()`、`assert()` 和 `revert()` 语句在智能合约中强制执行正确的行为,以便在执行未能满足某些要求时触发异常并回滚状态变更。 -**`require()`**:`require` 在函数开始时定义并确保在被调用函数执行之前满足预定义的条件。 `require` 语句可用于在处理函数之前验证用户输入、检查状态变量或验证调用帐户的身份。 +**`require()`**:`require` 在函数开头定义,确保在执行被调用的函数前满足预定义的条件。 `require` 语句可用于验证用户输入、检查状态变量或在函数继续执行前验证调用账户的身份。 -**`assert()`**:`assert()` 用于检测内部错误,并检查代码中是否有违反“不变量”的情况。 不变量是关于合约状态的逻辑断言,对于函数的所有执行都应该为真。 举个例子,代币合约的最大总供应量或余额就是一个不变量。 使用 `assert()` 可确保合约永远不会达到易受攻击的状态,如果达到,对状态变量的所有更改都会回滚。 +**`assert()`**:`assert()` 用于检测内部错误和检查代码中是否违反“不变量”。 不变量是关于合约状态的逻辑断言,对于函数的所有执行都应该为真。 举个例子,代币合约的最大总供应量或余额就是一个不变量。 使用 `assert()` 可以确保您的合约永远不会进入易受攻击的状态,如果进入了,对状态变量的所有更改都会被回滚。 -**`revert()`**:`revert()` 可用于 if-else 语句,可在要求的条件未满足时触发异常。 下面的示例合约使用 `revert()` 来保护函数的执行: +**`revert()`**:`revert()` 可用于 if-else 语句,在不满足所需条件时触发异常。 下面的示例合约使用 `revert()` 来保护函数的执行: ``` pragma solidity ^0.8.4; @@ -58,8 +58,8 @@ contract VendingMachine { error Unauthorized(); function buy(uint amount) public payable { if (amount > msg.value / 2 ether) - revert("Not enough Ether provided."); - // Perform the purchase. + revert("提供的以太币不足。"); + // 执行购买操作。 } function withdraw() public { if (msg.sender != owner) @@ -72,17 +72,17 @@ contract VendingMachine { ### 3. 测试智能合约并验证代码正确性 {#test-smart-contracts-and-verify-code-correctness} -鉴于在[以太坊虚拟机](/developers/docs/evm/)中运行的代码的不可变性,智能合约在开发阶段需要更高水平的质量评估。 对合约进行大量测试并观察是否存在任何意外结果,将显著增强合约的安全性并为用户提供长远保护。 +在[以太坊虚拟机](/developers/docs/evm/)中运行的代码具有不可变性,这意味着智能合约在开发阶段需要更高水平的质量评估。 对合约进行大量测试并观察是否存在任何意外结果,将显著增强合约的安全性并为用户提供长远保护。 -常用办法编写小单元测试,这些测试使用预计合约从用户处接收的模拟数据。 [单元测试](/developers/docs/smart-contracts/testing/#unit-testing)能够测试某些函数的功能并确保智能合约按预期运行。 +常用办法编写小单元测试,这些测试使用预计合约从用户处接收的模拟数据。 [单元测试](/developers/docs/smart-contracts/testing/#unit-testing)有助于测试特定函数的功能,并确保智能合约按预期工作。 遗憾的是,单独使用单元测试对提高智能合约的安全性效果甚微。 单元测试也许可以证明函数对于模拟数据正确执行,但单元测试的有效性受限于编写的测试。 这就意味着很难检测到威胁智能合约安全性的边缘情况和漏洞。 -更好的方法是将单元测试与基于属性的测试相结合,后者是通过[静态和动态分析](/developers/docs/smart-contracts/testing/#static-dynamic-analysis)进行的。 静态分析依赖于底层的表示(例如[控制流程图](https://en.wikipedia.org/wiki/Control-flow_graph)和[抽象语法树](https://deepsource.io/glossary/ast/))分析可达到的程序状态和执行路径。 同时,动态分析技术([例如智能合约模糊测试](https://www.cyfrin.io/blog/smart-contract-fuzzing-and-invariants-testing-foundry))使用随机输入值执行合约代码,以检测违反安全属性的操作。 +更好的方法是将单元测试与使用[静态和动态分析](/developers/docs/smart-contracts/testing/#static-dynamic-analysis)执行的基于属性的测试相结合。 静态分析依赖于低级别表示(例如[控制流图](https://en.wikipedia.org/wiki/Control-flow_graph)和[抽象语法树](https://deepsource.io/glossary/ast/)) 来分析可达的程序状态和执行路径。 同时,动态分析技术(例如[智能合约模糊测试](https://www.cyfrin.io/blog/smart-contract-fuzzing-and-invariants-testing-foundry))通过使用随机输入值执行合约代码来检测违反安全属性的操作。 -[形式化验证](/developers/docs/smart-contracts/formal-verification)是另一项验证智能合约安全属性的技术。 与常规测试不同,形式化验证能够确证智能合约中没有错误。 这是通过制定细致描述安全属性的形式化规范并证明智能合约的形式化模型符合这一规范来实现的。 +[形式化验证](/developers/docs/smart-contracts/formal-verification)是验证智能合约安全属性的另一种技术。 与常规测试不同,形式化验证能够确证智能合约中没有错误。 这是通过制定细致描述安全属性的形式化规范并证明智能合约的形式化模型符合这一规范来实现的。 -### 4. 申请代码独立审核 {#get-independent-code-reviews} +### 4. 请求对您的代码进行独立审查 {#get-independent-code-reviews} 在测试智能合约后,最好请其他人检查源代码是否存在安全问题。 虽然测试无法发现智能合约中的所有缺陷,但进行独立审核能增加发现漏洞的可能性。 @@ -92,18 +92,18 @@ contract VendingMachine { 尽管如此,你也不应将审计看作终极方案。 智能合约审计无法发现所有漏洞并且主要是为了额外增加一轮审核,这有助于检测到开发者在最初的开发和测试中遗漏的问题。 你还应遵循与审计员合作的最佳做法(例如正确记录代码并添加行内注释),让智能合约审计发挥最大作用。 -- [智能合约审计提示和技巧](https://twitter.com/tinchoabbate/status/1400170232904400897) - _@tinchoabbate_ -- [充分利用你的审计](https://inference.ag/blog/2023-08-14-tips/) - _推理_ +- [智能合约审计技巧和诀窍](https://twitter.com/tinchoabbate/status/1400170232904400897) - _@tinchoabbate_ +- [充分利用您的审计](https://inference.ag/blog/2023-08-14-tips/) - _Inference_ -#### 漏洞奖励 {#bug-bounties} +#### 漏洞赏金 {#bug-bounties} 执行外部代码审查的另一种方法是设立漏洞奖励计划。 漏洞奖励是一种经济奖励,提供给发现应用程序中漏洞的个人(通常是白帽黑客)。 -应用得当,漏洞奖励可以激励黑客群体中的成员检查你的代码是否存在重大缺陷。 一个真实的示例是“无限复制倾向漏洞”,它可以让攻击者在以太坊上运行的[二层网络](/layer-2/)协议 [Optimism](https://www.optimism.io/) 上创建无限量的以太币。 幸运的是,一位白帽黑客[发现了这一漏洞](https://www.saurik.com/optimism.html)并告知了以太坊团队,[并获得了一大笔报酬](https://cryptoslate.com/critical-bug-in-ethereum-l2-optimism-2m-bounty-paid/)。 +应用得当,漏洞奖励可以激励黑客群体中的成员检查你的代码是否存在重大缺陷。 一个真实的例子是“无限金钱漏洞”,该漏洞可能让攻击者在 [Optimism](https://www.optimism.io/)(一个在以太坊上运行的[第 2 层](/layer-2/)协议)上创建无限量的以太币。 幸运的是,一位白帽黑客[发现了这个漏洞](https://www.saurik.com/optimism.html)并通知了团队,[在此过程中获得了一大笔奖金](https://cryptoslate.com/critical-bug-in-ethereum-l2-optimism-2m-bounty-paid/)。 -一种实用策略是按有风险资金数额的比例设置漏洞奖励计划的报酬金额。 这种方法被描述成“[比例漏洞奖励](https://medium.com/immunefi/a-defi-security-standard-the-scaling-bug-bounty-9b83dfdc1ba7)”,通过提供经济激励让大家负责任地披露而非利用漏洞。 +一种实用策略是按有风险资金数额的比例设置漏洞奖励计划的报酬金额。 这种方法被称为“[分级漏洞赏金](https://medium.com/immunefi/a-defi-security-standard-the-scaling-bug-bounty-9b83dfdc1ba7)”,它为个人提供经济激励,鼓励他们负责任地披露漏洞,而不是利用漏洞。 -### 5. 智能合约开发过程中遵循最佳做法 {#follow-smart-contract-development-best-practices} +### 5. 在智能合约开发过程中遵循最佳实践 {#follow-smart-contract-development-best-practices} 即使审计和漏洞奖励存在,你也有责任编写高质量的代码。 遵循正确的设计和开发流程是良好的智能合约安全性的开端: @@ -113,15 +113,15 @@ contract VendingMachine { - 确保拉取请求至少有一位独立审核者 — 如果只有你一人完成项目,考虑和其他开发者相互进行代码审核 -- 在[开发环境](/developers/docs/frameworks/)下测试、编译、和部署智能合约 +- 使用[开发环境](/developers/docs/frameworks/)来测试、编译、部署智能合约 -- 通过基本代码分析工具运行代码,例如 [Cyfrin Aderyn](https://github.com/Cyfrin/aderyn) 、Mythril 和 Slither。 理想情况下,应在合并每个拉取请求前进行这一操作,并比较输出中的不同之处 +- 使用基础代码分析工具(例如 [Cyfrin Aderyn](https://github.com/Cyfrin/aderyn)、Mythril 和 Slither)运行您的代码。 理想情况下,应在合并每个拉取请求前进行这一操作,并比较输出中的不同之处 - 确保代码在编译时没有错误,并且 Solidity 编译器没有发出警告 -- 正确记录代码(使用 [NatSpec](https://solidity.readthedocs.io/en/develop/natspec-format.html)),并用易于理解的语言描述合约架构的细节。 这将使其他人更容易审计和审核你的代码。 +- (使用 [NatSpec](https://solidity.readthedocs.io/en/develop/natspec-format.html))妥善地为代码编写文档,并用通俗易懂的语言描述合约架构的细节。 这将使其他人更容易审计和审核你的代码。 -### 6. 实施可靠的灾难恢复计划 {#implement-disaster-recovery-plans} +### 6. 实施稳健的灾难恢复计划 {#implement-disaster-recovery-plans} 设计安全的访问控制、使用函数修改器以及其他建议能够提高智能合约的安全性,但这些并不能排除恶意利用的可能性。 构建安全的智能合约需要“做好失败准备”,并制定好应变计划有效地应对攻击。 适当的灾难恢复计划应包括以下部分或全部内容: @@ -129,13 +129,13 @@ contract VendingMachine { 虽然以太坊智能合约默认是不可变的,但通过使用升级模式可以实现一定程度的可变性。 如果重大缺陷导致合约不可用并且部署新逻辑是最可行的选择,有必要升级合约。 -合约升级机制的原理有所不同,但“代理模式”是智能合约升级最常见的方法之一。 [代理模式](https://www.cyfrin.io/blog/upgradeable-proxy-smart-contract-pattern)将应用程序的状态和逻辑划分为_两个_合约。 第一个合约(称为“代理合约”)存储状态变量(如用户余额),而第二个合约(称为"逻辑合约")存放执行合约函数的代码。 +合约升级机制的原理有所不同,但“代理模式”是智能合约升级最常见的方法之一。 [代理模式](https://www.cyfrin.io/blog/upgradeable-proxy-smart-contract-pattern)将应用程序的状态和逻辑拆分到_两个_合约中。 第一个合约(称为“代理合约”)存储状态变量(如用户余额),而第二个合约(称为"逻辑合约")存放执行合约函数的代码。 -帐户与代理合约互动,代理合约通过[`delegatecall()`](https://docs.soliditylang.org/en/v0.8.16/introduction-to-smart-contracts.html?highlight=delegatecall#delegatecall-callcode-and-libraries)的低级调用将所有功能调用分发给逻辑合约。 与普通的消息调用不同,`delegatecall()` 确保在逻辑的合约地址上运行的代码是在调用合约的语境下执行。 这意味着逻辑合约将始终写入代理的存储空间(而非自身存储空间),并且 `msg.sender` 和 `msg.value` 的原始值保持不变。 +账户与代理合约交互,代理合约使用 [`delegatecall()`](https://docs.soliditylang.org/en/v0.8.16/introduction-to-smart-contracts.html?highlight=delegatecall#delegatecall-callcode-and-libraries) 低层级调用将所有函数调用分派到逻辑合约。 与常规消息调用不同,`delegatecall()` 确保在逻辑合约地址运行的代码在调用合约的上下文中执行。 这意味着逻辑合约将始终写入代理的存储(而不是它自己的存储),并且 `msg.sender` 和 `msg.value` 的原始值会被保留。 将调用委托给逻辑合约需要将其地址存储在代理合约的存储空间。 因此,升级合约的逻辑就相当于部署另一个逻辑合约并在代理合约中存储新的地址。 由于对代理合约的后续调用会自动传送到新的逻辑合约,因此你“升级”了合约,但实际上并未修改代码。 -[更多关于升级合约的信息](/developers/docs/smart-contracts/upgrading/)。 +[关于升级合约的更多信息](/developers/docs/smart-contracts/upgrading/)。 #### 紧急停止 {#emergency-stops} @@ -143,16 +143,16 @@ contract VendingMachine { 这种情况下,核心方案是实施一种“紧急停止”功能,阻止对合约中有漏洞的函数的调用。 紧急停止通常由以下几部分组成: -1. 表明智能合约是否处在停止状态的全局布尔变量。 在设置合约时该变量设为 `false`,但在合约停止后将回滚为 `true`。 +1. 表明智能合约是否处在停止状态的全局布尔变量。 设置合约时,此变量被设置为 `false`,但一旦合约停止,它将恢复为 `true`。 2. 执行过程中引用该布尔变量的函数。 此类函数在智能合约没有停止时可以访问,而当紧急停止功能触发后则无法访问。 -3. 可以访问紧急停止功能的实体,可将布尔变量设置为 `true`。 为防止恶意行为,对此功能的调用可以限制给一个可信地址(如合约所有者)。 +3. 有权访问紧急停止功能的实体,可将布尔变量设置为 `true`。 为防止恶意行为,对此功能的调用可以限制给一个可信地址(如合约所有者)。 -一旦合约操作触发紧急停止,某些函数将无法调用。 这是通过把一些函数包装在引用该全局变量的修改器中实现的。 以下[示例](https://github.com/fravoll/solidity-patterns/blob/master/EmergencyStop/EmergencyStop.sol)描述了该模式在合约中的实现: +一旦合约操作触发紧急停止,某些函数将无法调用。 这是通过把一些函数包装在引用该全局变量的修改器中实现的。 下文是描述在合约中实现此模式的[一个示例](https://github.com/fravoll/solidity-patterns/blob/master/EmergencyStop/EmergencyStop.sol): ```solidity -// 本代码未经专业审计,对安全性和正确性不做任何承诺。 如需使用,风险自负。 +// 此代码未经专业审计,不保证其安全性或正确性。使用风险自负。 contract EmergencyStop { @@ -169,7 +169,7 @@ contract EmergencyStop { } modifier onlyAuthorized { - // Check for authorization of msg.sender here + // 在此处检查 msg.sender 的授权 _; } @@ -182,28 +182,28 @@ contract EmergencyStop { } function deposit() public payable stoppedInEmergency { - // Deposit logic happening here + // 此处是存款逻辑 } function emergencyWithdraw() public onlyWhenStopped { - // Emergency withdraw happening here + // 此处是紧急取款逻辑 } } ``` 以上示例展示了紧急停止的基本特点: -- 布尔值 `isStopped` 开始时求值为 `false`,但当合约进入紧急模式时求值为 `true`。 +- `isStopped` 是一个布尔值,开始时为 `false`,当合约进入紧急模式时为 `true`。 -- 函数修改器 `onlyWhenStopped` 和 `stoppedInEmergency` 检查 `isStopped` 变量。 `stoppedInEmergency` 用于控制在合约有漏洞时应该无法访问的函数(如 `deposit()`)。 对这些函数的调用将仅仅进行回滚而已。 +- 函数修饰符 `onlyWhenStopped` 和 `stoppedInEmergency` 会检查 `isStopped` 变量。 `stoppedInEmergency` 用于控制在合约易受攻击时应无法访问的函数(例如,`deposit()`)。 对这些函数的调用将仅仅进行回滚而已。 -`onlyWhenStopped` 用于在紧急情况下应该可调用的函数(如 `emergencyWithdraw()`)。 此类函数可以帮助解决问题,因此它们不在“受限制函数”之列。 +`onlyWhenStopped` 用于在紧急情况下应可调用的函数(例如 `emergencyWithdraw()`)。 此类函数可以帮助解决问题,因此它们不在“受限制函数”之列。 紧急停止功能的应用,为处理智能合约中的严重漏洞提供了一种有效的权宜之计。 然而,这也意味着用户更需要相信开发者不会为自身利益激活这一功能。 为此,将紧急停止的控制权去中心化,使其受到链上投票机制、时间锁的约束或者需要来自多重签名钱包的批准,都是潜在的解决方案。 -#### 事件监测 {#event-monitoring} +#### 事件监控 {#event-monitoring} -[事件](https://docs.soliditylang.org/en/v0.8.15/contracts.html#events)允许用户跟踪对智能合约函数的调用并监测状态变量的变化。 最理想的做法是将智能合约编写为能够在某一方采取对安全至关重要的操作(如提取资金)时发出一个事件。 +[事件](https://docs.soliditylang.org/en/v0.8.15/contracts.html#events)允许您跟踪对智能合约函数的调用并监控状态变量的变更。 最理想的做法是将智能合约编写为能够在某一方采取对安全至关重要的操作(如提取资金)时发出一个事件。 记录事件并进行链下监测,可以深入了解合同的运作情况,有助于更快地发现恶意行为。 这意味着你的团队可以更快地应对黑客攻击并采取行动减轻对用户的影响,如暂停函数或进行升级。 @@ -213,32 +213,32 @@ contract EmergencyStop { 你可能想要通过将核心智能合约的控制权转交给社区成员来去中心化你的应用。 在这种情况下,智能合约系统将包括一个治理模块 — 一种允许社区成员通过链上治理系统批准管理行为的机制。 例如,将代理合约升级为新实现的提案可能由代币持有人投票。 -去中心化治理可能是有益的,特别是因为它符合开发者和最终用户的利益。 然而如果实现不当,智能合约治理机制可能会带来新的风险。 一种可能的场景是,攻击者通过取得[闪电贷](/defi/#flash-loans)获得了很大的投票权(以持有的代币数量衡量)并通过一条恶意提案。 +去中心化治理可能是有益的,特别是因为它符合开发者和最终用户的利益。 然而如果实现不当,智能合约治理机制可能会带来新的风险。 一个可能的情景是,攻击者通过[闪电贷](/defi/#flash-loans)获取巨大的投票权(以持有的代币数量衡量),并推动通过一项恶意提案。 -防止与链上治理有关的问题的一种方法是[使用时间锁](https://blog.openzeppelin.com/protect-your-users-with-smart-contract-timelocks/)。 时间锁阻止智能合约执行某些操作,直到经过特定的时间长度。 其他策略包括根据每个代币锁定的时间长短为其分配“投票权重”,或者检测一个地址在历史时期(例如,过去的 2-3 个区块)而不是当前区块的投票权。 这两种方法都减少了快速累积投票权以影响链上投票的可能性。 +防止与链上治理相关问题的一种方法是[使用时间锁](https://blog.openzeppelin.com/protect-your-users-with-smart-contract-timelocks/)。 时间锁阻止智能合约执行某些操作,直到经过特定的时间长度。 其他策略包括根据每个代币锁定的时间长短为其分配“投票权重”,或者检测一个地址在历史时期(例如,过去的 2-3 个区块)而不是当前区块的投票权。 这两种方法都减少了快速累积投票权以影响链上投票的可能性。 -在分享的链接中查看更多关于[设计安全的治理系统](https://blog.openzeppelin.com/smart-contract-security-guidelines-4-strategies-for-safer-governance-systems/)、[去中心化自治组织中不同的投票机制](https://hackernoon.com/governance-is-the-holy-grail-for-daos)和[利用去中心化金融的常见去中心化自治组织攻击向量](https://dacian.me/dao-governance-defi-attacks)的信息 +关于[设计安全的治理系统](https://blog.openzeppelin.com/smart-contract-security-guidelines-4-strategies-for-safer-governance-systems/)、[DAO 中的不同投票机制](https://hackernoon.com/governance-is-the-holy-grail-for-daos)以及[利用 DeFi 的常见 DAO 攻击媒介](https://dacian.me/dao-governance-defi-attacks)的更多信息,请参阅分享的链接。 -### 8. 将代码的复杂性降到最低 {#reduce-code-complexity} +### 8. 将代码复杂性降至最低 {#reduce-code-complexity} 传统的软件开发者熟悉 KISS(“保持简单、保持愚蠢”)原则,该原则建议不要将不必要的复杂性带入到软件设计中。 这与长期以来的见解“复杂的系统有着复杂的失败方式”不谋而合,而且复杂系统更容易出现代价高昂的错误。 -编写智能合约时简洁化尤其重要,因为智能合约有可能控制大量的价值。 实现简洁化的一个窍门是,编写智能合约时在允许的情况下重用已存在的库,例如 [OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/5.x/)。 因为开发者对这些库已经进行了广泛的审计和测试,使用它们会减少从零开始编写新功能时引入漏洞的几率。 +编写智能合约时简洁化尤其重要,因为智能合约有可能控制大量的价值。 编写智能合约时,实现简洁的一个技巧是尽可能重用现有库,例如 [OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/5.x/)。 因为开发者对这些库已经进行了广泛的审计和测试,使用它们会减少从零开始编写新功能时引入漏洞的几率。 另一个常见的建议是通过将业务逻辑拆分到多个合约中,编写小型函数并保持合约模块化。 编写更简单的代码不仅仅会减少智能合约中的攻击面,还让推理整个系统的正确性并及早发现可能的设计错误变得更加容易。 ### 9. 防范常见的智能合约漏洞 {#mitigate-common-smart-contract-vulnerabilities} -#### 重入攻击 {#reentrancy} +#### 重入 {#reentrancy} -以太坊虚拟机不允许并发,这意味着消息调用中涉及的两个合约不能同时运行。 外部调用暂停调用合约的执行和内存,直到调用返回,此时执行正常进行。 该过程可以正式描述为将[控制流](https://www.computerhope.com/jargon/c/contflow.htm)转向另一个合约。 +以太坊虚拟机不允许并发,这意味着消息调用中涉及的两个合约不能同时运行。 外部调用暂停调用合约的执行和内存,直到调用返回,此时执行正常进行。 此过程可以正式描述为将[控制流](https://www.computerhope.com/jargon/c/contflow.htm)转移到另一个合约。 尽管这种转向大多数情况下没有危害,但将控制流转向不受信任的合约可能引起问题,例如重入攻击。 当恶意合约在初始函数调用完成之前回调有漏洞的合约时,就会发生重入攻击。 这类攻击最好用一个例子来解释。 考虑一个简单的智能合约(“Victim”),它允许任何人存入和提取以太币: ```solidity -// This contract is vulnerable. Do not use in production +// 此合约存在漏洞。请勿在生产环境中使用 contract Victim { mapping (address => uint256) public balances; @@ -256,15 +256,15 @@ contract Victim { } ``` -该合约公开了 `withdraw()` 函数,允许用户提取先前存入合约的以太币。 当处理提款时,合约执行以下操作: +此合约公开了一个 `withdraw()` 函数,允许用户提取先前存入合约的 ETH。 当处理提款时,合约执行以下操作: 1. 检查用户的以太币余额 2. 将资金发送给调用地址 3. 将其余额重置为 0,防止用户再提取 -`Victim` 合约中的 `withdraw()` 函数遵循“检查-交互-效果”模式。 它_检查_执行所需的条件是否满足(例如,用户的以太币余额是否为正值)并通过向调用者的地址发送以太币来执行_交互_,然后再应用交易的_效果_(例如减少用户的余额)。 +`Victim` 合约中的 `withdraw()` 函数遵循“检查-交互-影响”模式。 它会_检查_执行所需条件是否满足(即用户有正的 ETH 余额),并在应用交易_影响_(即减少用户余额)之前,通过向调用者地址发送 ETH 来执行_交互_。 -如果从外部帐户调用 `withdraw()`,该函数将按预期执行:`msg.sender.call.value()` 向调用方发送以太币。 然而,如果 `msg.sender` 是智能合约帐户调用 `withdraw()`,使用 `msg.sender.call.value()` 发送资金还将使存储在该地址的代码运行。 +如果从外部持有账户 (EOA) 调用 `withdraw()`,该函数会按预期执行:`msg.sender.call.value()` 会将 ETH 发送给调用者。 但是,如果 `msg.sender` 是一个调用 `withdraw()` 的智能合约账户,使用 `msg.sender.call.value()` 发送资金也会触发存储在该地址的代码运行。 假设以下是部署在合约地址的代码: @@ -289,7 +289,7 @@ contract Victim { 2. 将 1 个以太币存入 Victim 合约 3. 提取存储在该智能合约中的 1 个以太币 -这里没有什么问题,只是 `Attacker` 有另一个函数,如果传入的 `msg.sender.call.value` 调用剩余的燃料超过 40000,它就再次调用 `Victim` 中的 `withdraw()` 函数。 这使得 `Attacker` 能够重入 `Victim` 合约并在第一次调用 `withdraw` 函数结束_之前_提取更多资金。 这个循环如下所示: +这本身没有问题,但如果传入的 `msg.sender.call.value` 剩余的燃料超过 40,000,`Attacker` 合约中的另一个函数会再次调用 `Victim` 合约中的 `withdraw()` 函数。 这使得 `Attacker` 能够在 `withdraw` 的第一次调用完成_之前_重入 `Victim` 并提取更多资金。 这个循环如下所示: ```solidity - Attacker 的外部帐户使用 1 个以太币调用 `Attacker.beginAttack()` @@ -304,13 +304,13 @@ contract Victim { - 最后 `Victim` 将第一笔交易(和后续交易)的结果应用于其状态,所以 `Attacker` 的余额被设置为 0 ``` -总结起来就是,由于调用者的余额在函数执行完成之前没有设置为 0,所以后续的调用会成功,让调用者可以多次提取他们的余额。 这种攻击可以用来提空智能合约中的资金,就像 [2016 DAO 黑客攻击](https://www.coindesk.com/learn/understanding-the-dao-attack)中发生情况的那样。 正如[公开的重入攻击列表](https://github.com/pcaversaccio/reentrancy-attacks)所示,当前重入攻击仍是智能合约所面临的一个严重问题。 +总结起来就是,由于调用者的余额在函数执行完成之前没有设置为 0,所以后续的调用会成功,让调用者可以多次提取他们的余额。 这种攻击可用于耗尽智能合约的资金,就像在 [2016 年 DAO 黑客事件](https://www.coindesk.com/learn/understanding-the-dao-attack)中发生的那样。 正如[公开的重入攻击列表](https://github.com/pcaversaccio/reentrancy-attacks)所示,重入攻击至今仍然是智能合约的一个关键问题。 ##### 如何防止重入攻击 -应对重入攻击一种方法是遵循[检查-效果-交互模式](https://docs.soliditylang.org/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern)。 这种模式要求按照以下方式执行函数:最先执行在继续执行函数前执行必要检查的代码,再执行操作合约状态的代码,最后执行与其他合约或外部帐户交互的代码。 +处理重入的一种方法是遵循[检查-影响-交互模式](https://docs.soliditylang.org/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern)。 这种模式要求按照以下方式执行函数:最先执行在继续执行函数前执行必要检查的代码,再执行操作合约状态的代码,最后执行与其他合约或外部帐户交互的代码。 -检查-效果-交互模式在 `Victim` 合约的修订版中采用,如下所示: +下所示的 `Victim` 合约修订版中使用了检查-影响-交互模式: ```solidity contract NoLongerAVictim { @@ -323,9 +323,9 @@ contract NoLongerAVictim { } ``` -该合约对用户的余额执行_检查_,应用 `withdraw()` 函数的_效果_(将用户的余额重置为 0)并继续执行_交互_(将以太币发送到用户的地址)。 这确保了合约在外部调用之前更新其存储空间,消除了导致第一次攻击的重入攻击的条件。 `Attacker` 合约可能仍然可以回调 `NoLongerAVictim`,但由于 `balances[msg.sender]` 已设置为 0,额外的提取将引发错误。 +该合约对用户的余额执行_检查_,应用 `withdraw()` 函数的_影响_(将用户余额重置为 0),然后继续执行_交互_(将 ETH 发送至用户地址)。 这确保了合约在外部调用之前更新其存储空间,消除了导致第一次攻击的重入攻击的条件。 `Attacker` 合约仍然可以回调 `NoLongerAVictim`,但由于 `balances[msg.sender]` 已被设为 0,额外的提款将引发错误。 -另一种方案是使用互斥锁(通常称为“mutex”),它锁定一部分合约状态直到函数调用完成。 互斥锁是通过布尔变量实现的,该变量在函数执行之前设置为 `true`,在调用完成后回滚为 `false`。 如下面的例子所示,使用互斥锁可以防止函数在初始调用仍在进行时不受到递归调用,从而有效地阻止重入攻击。 +另一种方案是使用互斥锁(通常称为“mutex”),它锁定一部分合约状态直到函数调用完成。 这是通过一个布尔变量实现的,该变量在函数执行前设置为 `true`,在调用完成后恢复为 `false`。 如下面的例子所示,使用互斥锁可以防止函数在初始调用仍在进行时不受到递归调用,从而有效地阻止重入攻击。 ```solidity pragma solidity ^0.7.0; @@ -335,15 +335,15 @@ contract MutexPattern { mapping(address => uint256) public balances; modifier noReentrancy() { - require(!locked, "Blocked from reentrancy."); + require(!locked, "重入被阻止。"); locked = true; _; locked = false; } - // This function is protected by a mutex, so reentrant calls from within `msg.sender.call` cannot call `withdraw` again. - // The `return` statement evaluates to `true` but still evaluates the `locked = false` statement in the modifier + // 此函数受互斥锁保护,因此来自 `msg.sender.call` 内部的重入调用无法再次调用 `withdraw`。 + // `return` 语句的计算结果为 `true`,但仍会计算修饰符中的 `locked = false` 语句 function withdraw(uint _amount) public payable noReentrancy returns(bool) { - require(balances[msg.sender] >= _amount, "No balance to withdraw."); + require(balances[msg.sender] >= _amount, "没有可供提取的余额。"); balances[msg.sender] -= _amount; (bool success, ) = msg.sender.call{value: _amount}(""); @@ -354,32 +354,32 @@ contract MutexPattern { } ``` -还可以使用[拉取支付](https://docs.openzeppelin.com/contracts/5.x/api/security#PullPayment) 系统,该系统要求用户从智能合约中提取资金,而不是使用将资金发送到帐户的“推送支付”系统。 这样就消除了意外触发未知地址中代码的可能性(还可以防止某些拒绝服务攻击)。 +你也可以使用[拉取支付](https://docs.openzeppelin.com/contracts/5.x/api/security#PullPayment)系统,该系统要求用户从智能合约中提取资金,而不是将资金发送到账户的“推送支付”系统。 这样就消除了意外触发未知地址中代码的可能性(还可以防止某些拒绝服务攻击)。 -#### 整数下溢和溢出 {#integer-underflows-and-overflows} +#### 整数下溢和上溢 {#integer-underflows-and-overflows} -当算术运算的结果超出可接受的值范围,导致其“滚动”到可表示的最小值,整数溢出发生。 例如,`uint8` 只能存储最大为 2^-1=255 的值。 算术运算的结果如果大于 `255`,即溢出并重置 `Uint` 为`0`,这类似于汽车里程表,一旦达到最大里程 (999999) 示数就重置为 0。 +当算术运算的结果超出可接受的值范围,导致其“滚动”到可表示的最小值,整数溢出发生。 例如,一个 `uint8` 类型只能存储最大为 2^8-1=255 的值。 导致值高于 `255` 的算术运算将上溢,并将 `uint` 重置为 `0`,这与汽车里程表达到最大里程 (999999) 时重置为 0 的方式类似。 -整数下溢发生的原因类似:算术运算的结果小于可接受的范围。 比方说,你尝试减少 `uint8` 中的一个`0`,结果将只会滚动到最大的可表示值 (`255`)。 +整数下溢的发生原因类似:算术运算的结果低于可接受的范围。 假设您尝试在 `uint8` 中对 `0` 进行递减,结果将直接回绕到最大可表示值 (`255`)。 整数溢出和下溢都会导致合约的状态变量出现意外变化,引发意外的执行。 以下例子说明了攻击者如何利用智能合约的算数溢出执行无效操作: ``` pragma solidity ^0.7.6; -// This contract is designed to act as a time vault. -//用户可以向合约里存款但至少在一周内无法提款。 -//用户还可以延长 1 周的等待期。 +// 此合约旨在充当时间金库。 +// 用户可以向此合约存入资金,但至少一周内不能提取。 +// 用户还可以将等待时间延长至超过 1 周的等待期。 /* 1. 部署 TimeLock -2. 使用 TimeLock 地址部署 Attack -3. 调用 Attack.attack,发送 1 个以太币。 你将能够立即 - 提取你的以太币。 +2. 用 TimeLock 的地址部署 Attack +3. 调用 Attack.attack 并发送 1 个以太币。您将能够立即 + 提取您的以太币。 发生了什么? -攻击造成了 TimeLock 溢出,并且能够在 1 周的等待期之 -前提款。 +Attack 导致 TimeLock.lockTime 上溢,从而能够在 1 周的等待期之前 +提取资金。 */ contract TimeLock { @@ -396,14 +396,14 @@ contract TimeLock { } function withdraw() public { - require(balances[msg.sender] > 0, "Insufficient funds"); - require(block.timestamp > lockTime[msg.sender], "Lock time not expired"); + require(balances[msg.sender] > 0, "资金不足"); + require(block.timestamp > lockTime[msg.sender], "锁仓时间未到"); uint amount = balances[msg.sender]; balances[msg.sender] = 0; (bool sent, ) = msg.sender.call{value: amount}(""); - require(sent, "Failed to send Ether"); + require(sent, "以太币发送失败"); } } @@ -419,11 +419,11 @@ contract Attack { function attack() public payable { timeLock.deposit{value: msg.value}(); /* - if t = current lock time then we need to find x such that + 如果 t = 当前锁仓时间,那么我们需要找到 x,使得 x + t = 2**256 = 0 - so x = -t + 所以 x = -t 2**256 = type(uint).max + 1 - so x = type(uint).max + 1 - t + 所以 x = type(uint).max + 1 - t */ timeLock.increaseLockTime( type(uint).max + 1 - timeLock.lockTime(address(this)) @@ -435,15 +435,15 @@ contract Attack { ##### 如何防止整数溢出和下溢 -从 0.8.0 版开始,Solidity 编译器禁用导致整数下溢和溢出的代码。 然而,用较低编译器版本编译的合约应当对涉及算术运算的函数执行检查,或者使用检查是否发生下溢/溢出的库(例如 [SafeMath](https://docs.openzeppelin.com/contracts/2.x/api/math))。 +从 0.8.0 版开始,Solidity 编译器禁用导致整数下溢和溢出的代码。 但是,使用较低编译器版本编译的合约,应在涉及算术运算的函数上执行检查,或使用检查下溢/上溢的库(例如,[SafeMath](https://docs.openzeppelin.com/contracts/2.x/api/math))。 #### 预言机操纵 {#oracle-manipulation} -[预言机](/developers/docs/oracles/)获取链下信息并将这些信息发送到链上供智能合约使用。 通过预言机,你可以设计出和链下系统(例如资本市场)交互的智能合约,极大地拓展它们的应用。 +[预言机](/developers/docs/oracles/)从链下获取信息并将其发送到链上供智能合约使用。 通过预言机,你可以设计出和链下系统(例如资本市场)交互的智能合约,极大地拓展它们的应用。 但如果预言机损坏并向链上发送错误信息,智能合约将基于错误的输入执行,这会造成问题。 这就是“预言机问题”的根源,它涉及确保区块链预言机提供准确、最新、即时的信息。 -相关的安全问题就是利用链上预言机(例如去中心化交易所)获取一种资产的现货价格。 [去中心化金融 (DeFi)](/defi/) 行业中的借贷平台经常利用这种方法确定用户抵押品的价值,进而确定他们能借入多少。 +相关的安全问题就是利用链上预言机(例如去中心化交易所)获取一种资产的现货价格。 [去中心化金融 (DeFi)](/defi/) 行业的借贷平台通常会这样做,以确定用户抵押品的价值,从而决定他们可以借入多少资金。 去中心化交易所 (DEX) 的价格往往是准确的,很大程度上源于套利者的套利行为帮助市场恢复平价。 然而,这样容易受到操纵,尤其当链上预言机根据历史交易模式计算资产价格时(通常是这种情况)。 @@ -451,49 +451,49 @@ contract Attack { ##### 如何防止预言机操纵 -[避免预言机操纵](https://www.cyfrin.io/blog/price-oracle-manipultion-attacks-with-examples)的最低要求是使用从多个来源查询信息的去中心化预言机网络,以避免单点故障。 在大多数情况下,去中心化预言机有內置的加密经济学激励机制,鼓励预言机节点报告正确的信息,使它们比中心化预言机更安全。 +[避免预言机操纵](https://www.cyfrin.io/blog/price-oracle-manipultion-attacks-with-examples)的最低要求是使用去中心化的预言机网络,该网络从多个来源查询信息,以避免单点故障。 在大多数情况下,去中心化预言机有內置的加密经济学激励机制,鼓励预言机节点报告正确的信息,使它们比中心化预言机更安全。 -如果你打算通过查询链上预言机获得资产价格,考虑使用实施了时间加权平均价格 (TWAP) 机制的预言机。 [时间加权平均价格预言机](https://docs.uniswap.org/contracts/v2/concepts/core-concepts/oracles)查询资产在两个不同时间点(可以修改)的价格,并计算出基于所得平均值的现货价格。 选择较长的时间段可以保护协议免受价格操纵,因为最近执行的大宗订单无法影响资产价格。 +如果你打算通过查询链上预言机获得资产价格,考虑使用实施了时间加权平均价格 (TWAP) 机制的预言机。 [时间加权平均价格 (TWAP) 预言机](https://docs.uniswap.org/contracts/v2/concepts/core-concepts/oracles)在两个不同的时间点(您可以修改)查询资产的价格,并根据获得的平均值计算现货价格。 选择较长的时间段可以保护协议免受价格操纵,因为最近执行的大宗订单无法影响资产价格。 -## 面向开发者的智能合约安全性资源 {#smart-contract-security-resources-for-developers} +## 面向开发者的智能合约安全资源 {#smart-contract-security-resources-for-developers} ### 用于分析智能合约和验证代码正确性的工具 {#code-analysis-tools} -- **[测试工具和程序库](/developers/docs/smart-contracts/testing/#testing-tools-and-libraries)** - _为智能合约进行单元测试、静态分析和动态分析的行业标准工具和程序库集合。_ +- **[测试工具和库](/developers/docs/smart-contracts/testing/#testing-tools-and-libraries)** - _用于对智能合约执行单元测试、静态分析和动态分析的行业标准工具和库的集合。_ -- **[形式化验证工具](/developers/docs/smart-contracts/formal-verification/#formal-verification-tools)** - _用于验证智能合约中的函数正确性和检查不变量的工具。_ +- **[形式化验证工具](/developers/docs/smart-contracts/formal-verification/#formal-verification-tools)** - _用于验证智能合约功能正确性和检查不变量的工具。_ -- **[智能合约审计服务](/developers/docs/smart-contracts/testing/#smart-contract-auditing-services)** - _为以太坊开发项目提供智能合约审计服务的组织的列表。_ +- **[智能合约审计服务](/developers/docs/smart-contracts/testing/#smart-contract-auditing-services)** - _为以太坊开发项目提供智能合约审计服务的组织列表。_ -- **[漏洞奖励平台](/developers/docs/smart-contracts/testing/#bug-bounty-platforms)** - _协调漏洞奖励并对发现智能合约中重大漏洞的负责人进行奖励的平台。_ +- **[漏洞赏金平台](/developers/docs/smart-contracts/testing/#bug-bounty-platforms)** - _用于协调漏洞赏金和奖励负责任地披露智能合约中关键漏洞的平台。_ -- **[Fork Checker](https://forkchecker.hashex.org/)** - _免费的在线工具,用于检查所有关于分叉合同的现有信息。_ +- **[Fork Checker](https://forkchecker.hashex.org/)** - _一个免费的在线工具,用于检查有关分叉合约的所有可用信息。_ -- **[ABI 编码器](https://abi.hashex.org/)** - _免费在线服务,用于编码你的 Solidity 合约函数和构造函数参数。_ +- **[ABI 编码器](https://abi.hashex.org/)** - _一项免费的在线服务,用于对您的 Solidity 合约函数和构造函数参数进行编码。_ -- **[Aderyn](https://github.com/Cyfrin/aderyn)** - _Solidity 静态分析器,遍历抽象语法树 (AST) 来找出可疑漏洞,并以易于使用的 Mardown 格式打印输出问题。_ +- **[Aderyn](https://github.com/Cyfrin/aderyn)** - _Solidity 静态分析器,遍历抽象语法树 (AST) 以查明可疑漏洞,并以易于使用的 Markdown 格式打印问题。_ -### 智能合约监测工具 {#smart-contract-monitoring-tools}_ +### 智能合约监控工具 {#smart-contract-monitoring-tools} -- **[Tenderly Real-Time Alerting](https://tenderly.co/alerting/)** - _一种在智能合约或钱包发生异常或意外事件时,为你获取实时通知的工具。_ +- **[Tenderly 实时警报](https://tenderly.co/monitoring)** - _一个用于在您的智能合约或钱包上发生异常或意外事件时获取实时通知的工具。_ -### 智能合约的安全管理工具 {#smart-contract-administration-tools} +### 安全管理智能合约的工具 {#smart-contract-administration-tools} -- **[Safe](https://safe.global/)** - _在以太坊上运行的智能合约钱包,需要最少人数批准交易后交易才能进行 (M-of-N)。_ +- **[Safe](https://safe.global/)** - _在以太坊上运行的智能合约钱包,需要至少 N 人中的 M 人批准才能执行交易 (M-of-N)。_ -- **[OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/5.x/)** - _用于实现管理功能的合约库,包括管理合约所有权、升级、访问限制、治理、可暂停等功能。_ +- **[OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/5.x/)** - _用于实现管理功能的合约库,包括合约所有权、升级、访问控制、治理、暂停功能等。_ ### 智能合约审计服务 {#smart-contract-auditing-services} -- **[ConsenSys Diligence](https://consensys.net/diligence/)** - _为整个区块链生态系统中的项目提供帮助的智能合约审计服务,确保其协议可直接发布并为保护用户而构建。_ +- **[ConsenSys Diligence](https://diligence.consensys.io/)** - _智能合约审计服务,帮助整个区块链生态系统中的项目确保其协议已准备好启动并为保护用户而构建。_ -- **[CertiK](https://www.certik.com/)** - _区块链安全公司,率先在智能合约和区块链网络上采用尖端的形式化验证技术。_ +- **[CertiK](https://www.certik.com/)** - _区块链安全公司,率先在智能合约和区块链网络上使用尖端的形式化验证技术。_ -- **[Trail of Bits](https://www.trailofbits.com/)** - _网络安全公司,将安全研究与攻击者心态结合起来以降低风险并强化代码。_ +- **[Trail of Bits](https://www.trailofbits.com/)** - _网络安全公司,将安全研究与攻击者思维相结合,以降低风险并加固代码。_ -- **[PeckShield](https://peckshield.com/)** - _区块链安全公司,为整个区块链生态系统的安全、隐私和可用性提供产品和服务。_ +- **[PeckShield](https://peckshield.com/)** - _区块链安全公司,为整个区块链生态系统的安全性、隐私性和可用性提供产品和服务。_ -- **[QuantStamp ](https://quantstamp.com/)** - _审计服务,通过安全和风险评估服务促进主流区块链技术的采用。_ +- **[QuantStamp](https://quantstamp.com/)** - _通过安全和风险评估服务促进区块链技术成为主流的审计服务。_ - **[OpenZeppelin](https://www.openzeppelin.com/security-audits)** - _智能合约安全公司,为分布式系统提供安全审计。_ @@ -501,67 +501,67 @@ contract Attack { - **[Hacken](https://hacken.io)** - _Web3 网络安全审计公司,为区块链安全提供全方位解决方案。_ -- **[Nethermind](https://www.nethermind.io/smart-contract-audits)** - _Solidity 和 Cairo 审计服务,确保智能合约的完整性和跨以太坊和 Starknet 的用户安全_ +- **[Nethermind](https://www.nethermind.io/smart-contract-audits)** - _Solidity 和 Cairo 审计服务,确保智能合约的完整性以及以太坊和 Starknet 上用户的安全。_ -- **[HashEx](https://hashex.org/)** - _HashEx 专注于区块链和智能合约审计,确保加密货币安全,提供智能合约开发、渗透测试、区块链咨询等服务。_ +- **[HashEx](https://hashex.org/)** - _HashEx 专注于区块链和智能合约审计,以确保加密货币的安全,提供智能合约开发、渗透测试、区块链咨询等服务。_ - **[Code4rena](https://code4rena.com/)** - _竞争性审计平台,激励智能合约安全专家查找漏洞,帮助提高 web3 的安全性。_ - **[CodeHawks](https://codehawks.com/)** - _竞争性审计平台,为安全研究者举行智能合约审计比赛。_ -- **[Cyfrin](https://cyfrin.io)** - _Web3 安全发电站,通过产品和智能合约审计服务提高加密货币安全性。_ +- **[Cyfrin](https://cyfrin.io)** - _Web3 安全巨头,通过产品和智能合约审计服务孵化加密货币安全。_ - **[ImmuneBytes](https://immunebytes.com/smart-contract-audit/)** - _Web3 安全公司,通过经验丰富的审计员团队和一流的工具,为区块链系统提供安全审计。_ -- **[Oxorio](https://oxor.io/)** - _智能合约审计和区块链安全服务,为加密货币公司和去中心化金融项目提供以太坊虚拟机、Solidity、零知识、跨链技术方面的专业知识。_ +- **[Oxorio](https://oxor.io/)** - _智能合约审计和区块链安全服务,为加密货币公司和 DeFi 项目提供以太坊虚拟机、Solidity、零知识证明、跨链技术方面的专业知识。_ -- **[Inference](https://inference.ag/)** - _安全审计公司,专注于为基于以太坊虚拟机的区块链进行智能合约审计。 多亏他们的审计专家,他们发现了潜在问题并提出了可行的解决方案,在部署之前进行修复_ +- **[Inference](https://inference.ag/)** - _安全审计公司,专注于为基于以太坊虚拟机的区块链进行智能合约审计。 多亏他们的审计专家,他们发现了潜在问题并提出了可行的解决方案,在部署之前进行修复。_ -### 漏洞奖励平台 {#bug-bounty-platforms} +### 漏洞赏金平台 {#bug-bounty-platforms} -- **[Immunefi](https://immunefi.com/)** - _智能合约和去中心化金融项目的漏洞奖励平台,安全研究人员在该平台上审查代码、披露漏洞、获得报酬并使加密应用更加安全。_ +- **[Immunefi](https://immunefi.com/)** - _智能合约和 DeFi 项目的漏洞赏金平台,安全研究人员在该平台上审查代码、披露漏洞、获得报酬并使加密货币更加安全。_ -- **[HackerOne](https://www.hackerone.com/)** - _漏洞协调和漏洞奖励平台,将企业与渗透测试人员和网络安全研究人员连接在一起。_ +- **[HackerOne](https://www.hackerone.com/)** - _漏洞协调和漏洞赏金平台,将企业与渗透测试人员和网络安全研究人员连接在一起。_ -- **[HackenProof](https://hackenproof.com/)** - _针对加密项目(去中心化金融、智能合约、钱包、中心化交易所等)的专业级漏洞奖励平台,借助这一平台,安全专家可提供漏洞诊断服务,研究人员会因为提供经过验证的相关漏洞报告获得报酬。_ +- **[HackenProof](https://hackenproof.com/)** - _针对加密货币项目(DeFi、智能合约、钱包、中心化交易所等)的专业级漏洞赏金平台,借助这一平台,安全专家可提供漏洞诊断服务,研究人员会因为提供经过验证的相关漏洞报告获得报酬。_ -- **[Sherlock](https://www.sherlock.xyz/)** - _Web3 中的智能合约安全性承销商,通过智能合约管理审计人员的报酬,以确保相关漏洞得到公平的支付。_ +- **[Sherlock](https://www.sherlock.xyz/)** - _Web3 中的智能合约安全性承销商,通过智能合约管理审计人员的报酬,以确保相关漏洞得到公平的支付。_ -- **[CodeHawks](https://www.codehawks.com/)** - _竞争性漏洞奖金平台,供审计人员参与安全竞赛和挑战,并且(很快)能够参与他们自己的私人审计。_ +- **[CodeHawks](https://www.codehawks.com/)** - _竞争性漏洞奖金平台,供审计人员参与安全竞赛和挑战,并且(很快)能够参与他们自己的私人审计。_ -### 已知智能合约漏洞及利用情况的刊物 {#common-smart-contract-vulnerabilities-and-exploits} +### 关于已知智能合约漏洞和利用的出版物{#common-smart-contract-vulnerabilities-and-exploits} -- **[ConsenSys:已知的智能合约攻击](https://consensysdiligence.github.io/smart-contract-best-practices/attacks/)** - _针对最重要的合约漏洞提供适合初学者的解释,多数案例提供了代码示例。_ +- **[ConsenSys:智能合约已知攻击](https://consensysdiligence.github.io/smart-contract-best-practices/attacks/)** - _针对最重要的合约漏洞提供适合初学者的解释,多数案例提供了代码示例。_ - **[SWC 注册表](https://swcregistry.io/)** - _适用于以太坊智能合约的常见缺陷枚举 (CWE) 的精选项目列表。_ -- **[Rekt](https://rekt.news/)** - _定期更新的著名加密领域黑客攻击和漏洞利用范例刊物,不提供详细的事后分析报告。_ +- **[Rekt](https://rekt.news/)** - _定期更新的著名加密货币领域黑客攻击和漏洞利用刊物,并提供详细的事后分析报告。_ -### 智能合约安全学习难点 {#challenges-for-learning-smart-contract-security} +### 学习智能合约安全的挑战 {#challenges-for-learning-smart-contract-security} -- **[Awesome BlockSec CTF](https://github.com/blockthreat/blocksec-ctfs)** - _精选区块链安全攻防、实战、[夺旗](https://www.webopedia.com/definitions/ctf-event/amp/)竞赛和解决方案的文章列表。_ +- **[Awesome BlockSec CTF](https://github.com/blockthreat/blocksec-ctfs)** - _精选的区块链安全“战争游戏”、挑战、[夺旗赛](https://www.webopedia.com/definitions/ctf-event/amp/)以及解题报告列表。_ -- **[Damn Vulnerable DeFi](https://www.damnvulnerabledefi.xyz/)** - _通过实战演练学习去中心化金融智能合约的攻击性安全,并培养漏洞搜查和安全审计方面的技能。_ +- **[Damn Vulnerable DeFi](https://www.damnvulnerabledefi.xyz/)** - _通过实战演练学习 DeFi 智能合约的攻击性安全,并培养漏洞搜查和安全审计方面的技能。_ -- **[Ethernaut](https://ethernaut.openzeppelin.com/)** - _基于 Web3 和 Solidity 的实战演练,其中每个等级都是一个需要“攻破”的智能合约。_ +- **[Ethernaut](https://ethernaut.openzeppelin.com/)** - _基于 Web3 和 Solidity 的“战争游戏”,其中每个级别都是一个需要“攻破”的智能合约。_ -- **[HackenProof x HackTheBox](https://app.hackthebox.com/tracks/HackenProof-Track)** - _以奇幻冒险作为背景的智能合约黑客挑战。 成功完成挑战还有机会参与私人漏洞奖金项目。_ +- **[HackenProof x HackTheBox](https://app.hackthebox.com/tracks/HackenProof-Track)** - _以奇幻冒险为背景的智能合约黑客挑战。 成功完成挑战还有机会参与私人漏洞奖金项目。_ -### 确保智能合约安全的最佳做法 {#smart-contract-security-best-practices} +### 保护智能合约的最佳实践 {#smart-contract-security-best-practices} - **[ConsenSys:以太坊智能合约安全最佳实践](https://consensys.github.io/smart-contract-best-practices/)** - _保护以太坊智能合约安全的完整指南列表。_ -- **[Nascent:简单的安全工具箱](https://github.com/nascentxyz/simple-security-toolkit)** - _智能合约开发的实用安全指南和检查清单的集合。_ +- **[Nascent:简单安全工具箱](https://github.com/nascentxyz/simple-security-toolkit)** - _智能合约开发的实用安全指南和检查清单的集合。_ - **[Solidity 模式](https://fravoll.github.io/solidity-patterns/)** - _面向智能合约编程语言 Solidity 的安全模式和最佳实践实用合集。_ -- **[Solidity文档:安全性注意事项](https://docs.soliditylang.org/en/v0.8.16/security-considerations.html)** - _用Solidity编写安全智能合约的准则。_ +- **[Solidity 文档:安全注意事项](https://docs.soliditylang.org/en/v0.8.16/security-considerations.html)** - _使用 Solidity 编写安全智能合约的指南。_ -- **[智能合约安全验证标准](https://github.com/securing/SCSVS)** - _旨在确立智能合约安全性标准的第十四部分检查清单,面向开发者、架构师、安全审核者和供应商。_ +- **[智能合约安全验证标准](https://github.com/securing/SCSVS)** - _为开发者、架构师、安全审核者和供应商创建的、由十四部分组成的检查清单,旨在确立智能合约的安全性标准。_ -- **[学习智能合约安全与审计](https://updraft.cyfrin.io/courses/security)** - _智能合约安全与审计终极课程,专为寻求提升其安全性最佳做法和希望成为安全研究者的智能合约开发者创建。_ +- **[学习智能合约安全与审计](https://updraft.cyfrin.io/courses/security)** - _智能合约安全与审计终极课程,专为寻求提升其安全性最佳做法和希望成为安全研究者的智能合约开发者创建。_ -### 智能合约安全性教程 {#tutorials-on-smart-contract-security} +### 关于智能合约安全的教程 {#tutorials-on-smart-contract-security} - [如何编写安全的智能合约](/developers/tutorials/secure-development-workflow/) @@ -569,8 +569,8 @@ contract Attack { - [如何使用 Manticore 查找智能合约漏洞](/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/) -- [智能合约安全性准则](/developers/tutorials/smart-contract-security-guidelines/) +- [智能合约安全指南](/developers/tutorials/smart-contract-security-guidelines/) -- [如何安全整合代币合约与任意代币](/developers/tutorials/token-integration-checklist/) +- [如何安全地将您的代币合约与任意代币集成](/developers/tutorials/token-integration-checklist/) - [Cyfrin Updraft - 智能合约安全与审计完整课程](https://updraft.cyfrin.io/courses/security) diff --git a/public/content/translations/zh/developers/docs/smart-contracts/testing/index.md b/public/content/translations/zh/developers/docs/smart-contracts/testing/index.md index ca885c19008..0f673a6a8d5 100644 --- a/public/content/translations/zh/developers/docs/smart-contracts/testing/index.md +++ b/public/content/translations/zh/developers/docs/smart-contracts/testing/index.md @@ -1,38 +1,38 @@ --- -title: 测试智能合约 -description: 测试以太坊智能合约的技术和注意事项概述。 +title: "测试智能合约" +description: "测试以太坊智能合约的技术和注意事项概述。" lang: zh --- -公共区块链(如以太坊)是不可变的,这使得在部署后修改智能合约代码变得很困难。 虽然存在用于执行“虚拟升级”的[合约升级模式](/developers/docs/smart-contracts/upgrading/),但这些模式很难实现,并且需要社会共识。 此外,升级只能修复_已_发现的错误 — 如果攻击者先发现了漏洞,你的智能合约就面临被利用的风险。 +公共区块链(如以太坊)是不可变的,这使得在部署后修改智能合约代码变得很困难。 虽然存在用于执行“虚拟升级”的[合约升级模式](/developers/docs/smart-contracts/upgrading/),但这些模式很难实现,并且需要社会共识。 此外,升级只能在发现错误_之后_修复——如果攻击者先发现了漏洞,你的智能合约就面临被利用的风险。 -因此,在将智能合约[部署](/developers/docs/smart-contracts/deploying/)到主网之前进行测试是确保[安全性](/developers/docs/smart-contracts/security/)的最低要求。 有许多用于测试合约和评估代码正确性的技术,你可以根据需求进行选择。 然而,由不同工具和方法组成的测试套件很适合捕捉合约代码中的细微或重大安全缺陷。 +出于这些原因,在[部署](/developers/docs/smart-contracts/deploying/)到主网之前测试智能合约是[安全](/developers/docs/smart-contracts/security/)的最低要求。 有许多用于测试合约和评估代码正确性的技术,你可以根据需求进行选择。 然而,由不同工具和方法组成的测试套件很适合捕捉合约代码中的细微或重大安全缺陷。 ## 前提条件 {#prerequisites} -本页面将解释如何在部署到以太坊网络之前进行智能合约测试。 我们假设你熟悉[智能合约](/developers/docs/smart-contracts/)。 +本页面将解释如何在部署到以太坊网络之前进行智能合约测试。 本文假设你熟悉[智能合约](/developers/docs/smart-contracts/)。 ## 什么是智能合约测试? {#what-is-smart-contract-testing} 智能合约测试是验证智能合约代码是否按预期工作的过程。 测试对于检查特定智能合约是否满足可靠性、可用性和安全性的要求非常有用。 -虽然具体的方法可能各不相同,但大多数测试方法都要求使用合约要处理的少量样本数据执行智能合约。 如果合约样本数据能产生正确的结果,就可以认为合约能正常运行。 大多数测试工具提供了编写和执行[测试用例](https://en.m.wikipedia.org/wiki/Test_case)的资源,用于检查合约的执行是否与预期结果相符。 +虽然具体的方法可能各不相同,但大多数测试方法都要求使用合约要处理的少量样本数据执行智能合约。 如果合约样本数据能产生正确的结果,就可以认为合约能正常运行。 大多数测试工具都提供了用于编写和执行[测试用例](https://en.m.wikipedia.org/wiki/Test_case)的资源,以检查合约的执行是否与预期结果相符。 ### 为什么测试智能合约很重要? {#importance-of-testing-smart-contracts} -由于智能合约通常管理高价值的金融资产,因此即使是很小的编程错误也往往会导致[用户遭受巨大的损失](https://rekt.news/leaderboard/)。 但是严格的测试可以帮助你在部署到主网之前,及早发现智能合约代码中的缺陷和问题,并进行修复。 +由于智能合约通常管理着高价值的金融资产,微小的编程错误就可能且经常导致[用户遭受巨大损失](https://rekt.news/leaderboard/)。 但是严格的测试可以帮助你在部署到主网之前,及早发现智能合约代码中的缺陷和问题,并进行修复。 -尽管发现错误后可以对合约进行升级,但升级很复杂,而且如果处理不当可能会[导致错误](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/)。 进一步升级合约会削弱不可变性原则,并给用户增加额外的信任假设。 相反,对合约进行全面测试的计划可以减轻智能合约的安全风险,并减少在部署后执行复杂逻辑升级的需求。 +虽然在发现漏洞后可以升级合约,但升级过程很复杂,如果处理不当可能会[导致错误](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/)。 进一步升级合约会削弱不可变性原则,并给用户增加额外的信任假设。 相反,对合约进行全面测试的计划可以减轻智能合约的安全风险,并减少在部署后执行复杂逻辑升级的需求。 -## 测试智能合约的方法 {#methods-for-testing-smart-contracts} +## 智能合约的测试方法 {#methods-for-testing-smart-contracts} -以太坊智能合约的测试方法可以分为两大类:**自动化测试**和**手动测试**。 自动化测试和手动测试各有独特的优点和权衡,但你可以将二者结合起来,创建强大的测试计划来分析你的合约。 +测试以太坊智能合约的方法可分为两大类:**自动化测试**和**手动测试**。 自动化测试和手动测试各有独特的优点和权衡,但你可以将二者结合起来,创建强大的测试计划来分析你的合约。 ### 自动化测试 {#automated-testing} -自动化测试使用工具来自动检查智能合约代码的执行错误。 自动化测试的好处在于使用[脚本](https://www.techtarget.com/whatis/definition/script?amp=1)来指导对合约功能的评估。 脚本化测试可以按计划重复运行,人工干预极少,因此自动化测试比手动测试更高效。 +自动化测试使用工具来自动检查智能合约代码的执行错误。 自动化测试的好处在于,它使用[脚本](https://www.techtarget.com/whatis/definition/script?amp=1)来指导对合约功能的评估。 脚本化测试可以按计划重复运行,人工干预极少,因此自动化测试比手动测试更高效。 -自动化测试特别适用于以下情况:测试重复且耗时;手动执行困难时;容易出现人为错误时;或涉及评估关键合约功能时。 但是自动化测试工具可能存在缺陷 — 它们可能会忽略某些错误并产生一些[误报](https://www.contrastsecurity.com/glossary/false-positive)。 因此,理想的方法是结合自动化测试与手动测试。 +自动化测试特别适用于以下情况:测试重复且耗时;手动执行困难时;容易出现人为错误时;或涉及评估关键合约功能时。 但自动化测试工具有其缺点——它们可能会漏掉某些漏洞,并产生许多[误报](https://www.contrastsecurity.com/glossary/false-positive)。 因此,理想的方法是结合自动化测试与手动测试。 ### 手动测试 {#manual-testing} @@ -50,13 +50,13 @@ lang: zh 单元测试对于检查函数返回预期值以及在函数执行后正确更新合约存储非常有用。 此外,在更改了合约代码库后运行单元测试,可以确保添加新逻辑不会引入错误。 以下是运行有效单元测试的一些准则: -#### 智能合约单元测试的准则 {#unit-testing-guidelines} +#### 智能合约单元测试指南 {#unit-testing-guidelines} ##### 1. 理解你的合约业务逻辑和工作流程 -在编写单元测试之前,了解智能合约提供的功能以及用户如何访问和使用这些函数很有帮助。 这对于运行 [happy path 测试](https://en.m.wikipedia.org/wiki/Happy_path)特别有用,该测试用于确定合约中的函数是否对有效的用户输入返回正确的输出。 我们将使用这个(简化版)的[拍卖合约](https://docs.soliditylang.org/en/v0.8.17/solidity-by-example.html?highlight=Auction%20contract#simple-open-auction)示例来解释此概念。 +在编写单元测试之前,了解智能合约提供的功能以及用户如何访问和使用这些函数很有帮助。 这对于运行[正常路径测试](https://en.m.wikipedia.org/wiki/Happy_path)特别有用,该测试用于确定合约中的函数是否为有效的用户输入返回正确的输出。 我们将使用这个(节选的)[拍卖合约](https://docs.soliditylang.org/en/v0.8.17/solidity-by-example.html?highlight=Auction%20contract#simple-open-auction)示例来解释这个概念。 -``` +```solidity constructor( uint biddingTime, address payable beneficiaryAddress @@ -108,11 +108,11 @@ function auctionEnd() external { } ``` -这是一个简单的拍卖合约,用于在竞标期间接收竞标。 如果 `highestBid` 增加,先前的最高出价者将收到他们的钱;一旦竞标期结束,`beneficiary` 调用合约以收取他们的钱。 +这是一个简单的拍卖合约,用于在竞标期间接收竞标。 如果 `highestBid` 增加,之前的最高出价者会收到他们的钱;一旦竞价期结束,`beneficiary` 就会调用合约来取钱。 -对这样的合约进行的单元测试将涵盖用户在与合约交互时可能调用的不同函数。 以单元测试为例,它会检查用户是否能够在拍卖进行期间出价(即调用 `bid()` 成功),或者检查用户是否能够出高于当前 `highestBid` 的价格。 +对这样的合约进行的单元测试将涵盖用户在与合约交互时可能调用的不同函数。 例如,一个单元测试可以检查用户在拍卖进行期间是否可以出价(即对 `bid()` 的调用成功),或者检查用户是否可以出比当前 `highestBid` 更高的价格。 -了解合约的运行流程还有助于编写单元测试,以检查执行是否满足要求。 例如,拍卖合约规定,在拍卖结束时(即当 `auctionEndTime` 小于 `block.timestamp` 时),用户无法进行竞标。 因此,开发者可能会运行一个单元测试,检查当拍卖结束时(即当 `auctionEndTime` > `block.timestamp` 时)对 `bid()` 函数的调用成功还是失败。 +了解合约的运行流程还有助于编写单元测试,以检查执行是否满足要求。 例如,拍卖合约规定,当拍卖结束后(即 `auctionEndTime` 小于 `block.timestamp` 时),用户不能出价。 因此,开发者可以运行一个单元测试,检查当拍卖结束时(即 `auctionEndTime` > `block.timestamp` 时),对 `bid()` 函数的调用是成功还是失败。 ##### 2. 评估与合约执行相关的所有假设 @@ -126,11 +126,11 @@ function auctionEnd() external { - 未能赢得竞标的用户将获得其资金的退款 -**注意**:测试假设的另一种方法是编写测试,触发合约中的[函数修改器](https://docs.soliditylang.org/en/v0.8.16/contracts.html#function-modifiers),特别是 `require`、`assert` 和 `if...else` 语句。 +**注意**:另一种检验假设的方法是编写测试来触发合约中的[函数修饰符](https://docs.soliditylang.org/en/v0.8.16/contracts.html#function-modifiers),尤其是 `require`、`assert` 和 `if…else` 语句。 ##### 3. 度量代码覆盖率 -[代码覆盖率](https://en.m.wikipedia.org/wiki/Code_coverage)是一种测试指标,用于跟踪在测试过程中执行的代码分支、行数和语句数量。 测试应该具有良好的代码覆盖率,以最大程度地减少未经测试漏洞的风险。 如果没有充足的代码覆盖率,你可能会误认为你的合约是安全的,因为所有测试都通过了,而未经测试的代码路径中仍存在漏洞。 记录高代码覆盖率,可以确保智能合约中的所有语句/函数都经过了足够的正确性测试。 +[代码覆盖率](https://en.m.wikipedia.org/wiki/Code_coverage)是一种测试指标,用于跟踪测试期间执行的代码中的分支、代码行和语句的数量。 测试应该具有良好的代码覆盖率,以最大程度地减少未经测试漏洞的风险。 如果没有充足的代码覆盖率,你可能会误认为你的合约是安全的,因为所有测试都通过了,而未经测试的代码路径中仍存在漏洞。 记录高代码覆盖率,可以确保智能合约中的所有语句/函数都经过了足够的正确性测试。 ##### 4. 使用完善的测试框架 @@ -143,14 +143,14 @@ function auctionEnd() external { - **[使用 Waffle 运行单元测试](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html#writing-tests)** - **[使用 Remix 运行单元测试](https://remix-ide.readthedocs.io/en/latest/unittesting.html#write-tests)** - **[使用 Ape 运行单元测试](https://docs.apeworx.io/ape/stable/userguides/testing.html)** -- **[使用安全帽运行单元测试](https://hardhat.org/hardhat-runner/docs/guides/test-contracts)** +- **[使用 Hardhat 运行单元测试](https://hardhat.org/hardhat-runner/docs/guides/test-contracts)** - **[使用 Wake 运行单元测试](https://ackeeblockchain.com/wake/docs/latest/testing-framework/overview/)** ### 集成测试 {#integration-testing-for-smart-contracts} -虽然单元测试可以独立调试合约函数,但集成测试会将智能合约的各个组件作为一个整体进行评估。 集成测试可以检测到跨合约调用或同一智能合约中不同函数之间的交互引起的问题。 例如,集成测试可以帮助检查诸如[继承](https://docs.soliditylang.org/en/v0.8.12/contracts.html#inheritance)和依赖注入等功能是否正常工作。 +虽然单元测试可以独立调试合约函数,但集成测试会将智能合约的各个组件作为一个整体进行评估。 集成测试可以检测到跨合约调用或同一智能合约中不同函数之间的交互引起的问题。 例如,集成测试可以帮助检查[继承](https://docs.soliditylang.org/en/v0.8.12/contracts.html#inheritance)和依赖注入等功能是否正常工作。 -如果合约采用模块化架构或在执行过程中与其他链上合约进行接口交互,集成测试将非常有用。 一种运行集成测试的方法是在特定的高度[让区块链分叉](/glossary/#fork)(使用 [Forge](https://book.getfoundry.sh/forge/fork-testing) 或[安全帽](https://hardhat.org/hardhat-network/docs/guides/forking-other-networks)等工具),并模拟你的合约与已部署合约之间的交互。 +如果合约采用模块化架构或在执行过程中与其他链上合约进行接口交互,集成测试将非常有用。 运行集成测试的一种方法是在特定高度[分叉区块链](/glossary/#fork)(使用 [Forge](https://book.getfoundry.sh/forge/fork-testing) 或 [Hardhat](https://hardhat.org/hardhat-network/docs/guides/forking-other-networks) 等工具),并模拟你的合约与已部署合约之间的交互。 分叉的区块链将与主网的行为类似,其帐户具有关联的状态和余额。 但是它只是一个沙盒式的本地开发环境,举例来说这意味着你不需要真正的以太币进行交易,同时你的更改也不会影响真实的以太坊协议。 @@ -158,44 +158,44 @@ function auctionEnd() external { 基于属性的测试是一种检查智能合约是否满足一些定义的属性的过程。 属性是关于合约行为的断言,预期其行为在不同的场景中始终保持为真。智能合约属性的一个例子可以是“合约中的算术运算永不溢出或下溢”。 -**静态分析**和**动态分析**是执行基于属性的测试的两种常见技术,它们都可以验证程序代码(此例中的智能合约)是否满足一些预定义的属性。 有些基于属性的测试工具提供预定义的合约属性规则,并根据这些规则检查代码,而其他工具则允许你为智能合约创建自定义属性。 +**静态分析**和**动态分析**是执行基于属性的测试的两种常用技术,二者都可以验证一个程序(在本例中为智能合约)的代码是否满足某些预定义属性。 有些基于属性的测试工具提供预定义的合约属性规则,并根据这些规则检查代码,而其他工具则允许你为智能合约创建自定义属性。 #### 静态分析 {#static-analysis} 静态分析器接受智能合约的源代码作为输入,并输出结果,声明合约是否满足某个属性 与动态分析不同,静态分析不涉及执行合约来分析其正确性。 静态分析则可以推断智能合约在执行过程中可能采取的所有路径(即通过检查源代码的结构来确定合约在运行时的操作意义)。 -[Linting](https://www.perforce.com/blog/qac/what-lint-code-and-why-linting-important) 和[静态测试](https://www.techtarget.com/whatis/definition/static-analysis-static-code-analysis)是对合约运行静态分析的常见方法。 两者都需要分析合约执行的低级表现,例如编译器输出的[抽象语法树](https://en.m.wikipedia.org/wiki/Abstract_syntax_tree)和[控制流图](https://www.geeksforgeeks.org/software-engineering-control-flow-graph-cfg/amp/)。 +[Linting](https://www.perforce.com/blog/qac/what-is-linting) 和[静态测试](https://www.techtarget.com/whatis/definition/static-analysis-static-code-analysis)是对合约运行静态分析的常用方法。 这两种方法都需要分析由编译器输出的合约执行的低级表示形式,例如[抽象语法树](https://en.m.wikipedia.org/wiki/Abstract_syntax_tree)和[控制流图](https://www.geeksforgeeks.org/software-engineering-control-flow-graph-cfg/amp/)。 在大多数情况下,静态分析对于检测合约代码中的安全问题非常有用,例如使用不安全的结构、语法错误或违反编码标准。 然而,静态分析器通常被认为在检测更深层次的漏洞方面不够准确,并且可能会产生过多的误报。 #### 动态分析 {#dynamic-analysis} -动态分析生成智能合约函数的符号输入(例如,在[symbolic execution](https://en.m.wikipedia.org/wiki/Symbolic_execution)中)或具体输入(例如,在[fuzzing](https://owasp.org/www-community/Fuzzing)中),以查看是否存在任何执行轨迹违反特定属性。 这种基于属性的测试形式与单元测试不同,因为测试用例涵盖多种场景,并且由程序处理测试用例的生成。 +动态分析为智能合约的函数生成符号输入(例如,在[符号执行](https://en.m.wikipedia.org/wiki/Symbolic_execution)中)或具体输入(例如,在[模糊测试](https://owasp.org/www-community/Fuzzing)中),以查看是否有任何执行轨迹违反了特定属性。 这种基于属性的测试形式与单元测试不同,因为测试用例涵盖多种场景,并且由程序处理测试用例的生成。 -[模糊测试](https://halborn.com/what-is-fuzz-testing-fuzzing/)是一种用于验证智能合约中任意属性的动态分析技术的示例。 模糊测试工具使用随机或畸形的变化调用目标合约中的函数,以对预定义的输入值进行测试。 如果智能合约进入错误状态(例如,断言失败),问题会被标记,并在生成的报告中包含驱动执行进入脆弱路径的输入。 +[模糊测试](https://www.halborn.com/blog/post/what-is-fuzz-testing-fuzzing)是动态分析技术的一个示例,用于验证智能合约中的任意属性。 模糊测试工具使用随机或畸形的变化调用目标合约中的函数,以对预定义的输入值进行测试。 如果智能合约进入错误状态(例如,断言失败),问题会被标记,并在生成的报告中包含驱动执行进入脆弱路径的输入。 模糊测试对于评估智能合约的输入验证机制非常有用,因为对于非预期输入的处理不当可能导致意外执行并产生危险影响。 这种基于属性的测试形式可能非常理想,原因有多种: -1. **编写涵盖多种场景的测试用例很困难。**属性测试只需要你定义一个行为和一组用于测试该行为的数据范围,程序会根据定义的属性自动生成测试用例。 +1. \*\*编写涵盖多种场景的测试用例很困难。\*\*基于属性的测试只需要你定义一个行为和用于测试该行为的数据范围——程序会根据定义的属性自动生成测试用例。 -2. **你的测试套件可能无法充分覆盖程序中的所有可能路径。**即使达到了 100% 的覆盖率,仍然有可能忽略一些极端情况。 +2. \*\*你的测试套件可能无法充分覆盖程序中的所有可能路径。\*\*即使代码覆盖率达到 100%,也可能漏掉边缘情况。 -3. **单元测试证明合约对于样本数据的执行是正确的,但是对于样本之外的输入能否正确执行仍然未知。**属性测试使用多个变化的给定输入值针对目标合约执行,以找到导致断言失败的执行轨迹。 因此,属性测试为合约在广泛的输入数据类别下正确执行提供了更多的保证。 +3. \*\*单元测试证明合约对样本数据的执行是正确的,但合约对样本之外的输入的执行是否正确仍然是未知的。\*\*基于属性的测试使用一个给定输入值的多个变体来执行目标合约,以找到导致断言失败的执行轨迹。 因此,属性测试为合约在广泛的输入数据类别下正确执行提供了更多的保证。 -### 对智能合约运行基于属性的测试的准则 {#running-property-based-tests} +### 运行智能合约的基于属性的测试指南 {#running-property-based-tests} -运行基于属性的测试通常始于定义你希望在智能合约中进行验证的一个属性(例如,[整数溢出](https://github.com/ConsenSys/mythril/wiki/Integer-Overflow)的缺失)或一组属性。 在编写属性测试时,你可能需要定义一个数值范围,程序可以在此范围生成用于交易输入的数据。 +运行基于属性的测试通常从定义要在智能合约中验证的一个或一组属性(例如,不存在[整数溢出](https://github.com/ConsenSys/mythril/wiki/Integer-Overflow))开始。 在编写属性测试时,你可能需要定义一个数值范围,程序可以在此范围生成用于交易输入的数据。 配置正确后,属性测试工具将使用随机生成的输入执行你的智能合约函数。 如果存在任何断言违规情况,你应该获得一份报告,其中包含违反正在评估的属性的具体输入数据。 请参阅下面的指南,了解如何使用不同的工具开始运行基于属性的测试: -- **[使用 Slither 进行智能合约静态分析](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/slither#slither)** -- **[使用 Wake 进行智能合约静态分析](https://ackeeblockchain.com/wake/docs/latest/static-analysis/using-detectors/)** +- **[使用 Slither 对智能合约进行静态分析](https://github.com/crytic/slither)** +- **[使用 Wake 对智能合约进行静态分析](https://ackeeblockchain.com/wake/docs/latest/static-analysis/using-detectors/)** - **[使用 Brownie 进行基于属性的测试](https://eth-brownie.readthedocs.io/en/stable/tests-hypothesis-property.html)** -- **[使用 Foundry 进行合约模糊测试](https://book.getfoundry.sh/forge/fuzz-testing)** -- **[使用 Echidna 进行合约模糊测试](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/echidna#echidna-tutorial)** -- **[使用 Wake 进行合约模糊测试](https://ackeeblockchain.com/wake/docs/latest/testing-framework/fuzzing/)** -- **[使用 Manticore 完成智能合约符号执行](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/manticore#manticore-tutorial)** -- **[使用 Mythril 完成智能合约符号执行](https://mythril-classic.readthedocs.io/en/master/tutorial.html)** +- **[使用 Foundry 对合约进行模糊测试](https://book.getfoundry.sh/forge/fuzz-testing)** +- **[使用 Echidna 对合约进行模糊测试](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/echidna#echidna-tutorial)** +- **[使用 Wake 对合约进行模糊测试](https://ackeeblockchain.com/wake/docs/latest/testing-framework/fuzzing/)** +- **[使用 Manticore 对智能合约进行符号执行](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/manticore#manticore-tutorial)** +- **[使用 Mythril 对智能合约进行符号执行](https://mythril-classic.readthedocs.io/en/master/tutorial.html)** ## 智能合约的手动测试 {#manual-testing-for-smart-contracts} @@ -205,43 +205,43 @@ function auctionEnd() external { 虽然在本地开发环境中进行的自动化测试可以提供有用的调试信息,但你需要了解你的智能合约在生产环境中的行为。 然而,部署到以太坊主链上会产生燃料费用,更不用说如果你的智能合约仍然存在错误,你或你的用户可能会损失真金白银。 -在本地区块链(也称为[开发网络](/developers/docs/development-networks/))测试你的合约是在主网上测试的推荐替代方法。 本地区块链是在你的计算机本地运行的以太坊区块链副本,模拟以太坊执行层的行为。 因此,你可以编程交易与合约进行交互,而不会产生大量开销。 +在本地区块链(也称为[开发网络](/developers/docs/development-networks/))上测试合约,是主网测试之外的另一个推荐选择。 本地区块链是在你的计算机本地运行的以太坊区块链副本,模拟以太坊执行层的行为。 因此,你可以编程交易与合约进行交互,而不会产生大量开销。 -在本地区块链上运行合约可以作为一种有用的手动集成测试的方式。 [智能合约具有高度的可组合性](/developers/docs/smart-contracts/composability/),使你能够与现有协议进行集成,但你仍需要确保这种复杂的链上交互能够产生正确的结果。 +在本地区块链上运行合约可以作为一种有用的手动集成测试的方式。 [智能合约具有高度的可组合性](/developers/docs/smart-contracts/composability/),允许你与现有协议集成——但你仍需确保这类复杂的链上交互能产生正确结果。 -[更多关于开发网络的信息。](/developers/docs/development-networks/) +[关于开发网络的更多信息。](/developers/docs/development-networks/) ### 在测试网上测试合约 {#testing-contracts-on-testnets} -测试网络或测试网的运行方式与以太坊主网完全相同,唯一的区别在于它使用的是没有现实价值的以太币 (ETH)。 在[测试网](/developers/docs/networks/#ethereum-testnets)上部署你的合约意味着任何人都可以与之交互(例如,通过去中心化应用程序的前端界面),而无需承担资金风险。 +测试网络或测试网的运行方式与以太坊主网完全相同,唯一的区别在于它使用的是没有现实价值的以太币 (ETH)。 将你的合约部署在[测试网](/developers/docs/networks/#ethereum-testnets)上,意味着任何人都可以与它交互(例如通过去中心化应用程序的前端),而无需冒资金风险。 这种手动测试形式对于从用户角度评估应用程序的端到端流程非常有用。 在这里,测试人员还可以进行试运行,并报告与合约的业务逻辑和整体功能有关的任何问题。 在本地区块链上进行测试后,部署到测试网是理想的选择,因为测试网更接近以太坊虚拟机的行为。 因此,许多以太坊原生项目通常会在测试网上部署去中心化应用程序,以在真实环境条件下评估智能合约的运行。 -[更多关于以太坊测试网的信息。](/developers/docs/development-networks/#public-beacon-testchains) +[关于以太坊测试网的更多信息。](/developers/docs/development-networks/#public-beacon-testchains) ## 测试与形式化验证 {#testing-vs-formal-verification} -虽然测试有助于确认合约返回某些数据输入的预期结果,但它不能最终证明测试期间未使用的输入也是如此。 因此,测试智能合约无法保证“功能正确性”(即无法证明程序在_所有_输入值集合上都按照要求运行)。 +虽然测试有助于确认合约返回某些数据输入的预期结果,但它不能最终证明测试期间未使用的输入也是如此。 因此,测试智能合约不能保证“功能正确性”(即无法证明程序在_所有_输入值集合上都按要求运行)。 形式化验证是一种通过检查程序的形式模型是否与形式规范相匹配来评估软件正确性的方法。 形式模型是对程序的抽象数学表述,而形式规范则定义了程序的属性(即关于程序执行的逻辑断言)。 由于属性以数学术语编写,因此可以使用逻辑推理规则验证系统的形式(数学)模型是否满足规范。 因此,形式化验证工具被称为能够提供系统正确性的“数学证明”。 -与测试不同,形式化验证可以用于验证智能合约的执行是否满足_所有_执行情况的形式规范的要求(即,没有缺陷),而无需使用样本数据来执行。 这不仅减少了运行数十个单元测试所花费的时间,而且在发现隐藏的漏洞方面也更加有效。 话虽如此,形式化验证技术在实施难度和实用性上存在一定的变化程度。 +与测试不同,形式化验证可用于证明智能合约的执行在_所有_执行中都满足形式规范(即没有漏洞),而无需使用样本数据来执行。 这不仅减少了运行数十个单元测试所花费的时间,而且在发现隐藏的漏洞方面也更加有效。 话虽如此,形式化验证技术在实施难度和实用性上存在一定的变化程度。 -[更多关于智能合约的形式化验证的信息。](/developers/docs/smart-contracts/formal-verification) +[关于智能合约形式化验证的更多信息。](/developers/docs/smart-contracts/formal-verification) -## 测试与审计以及漏洞奖金计划 {#testing-vs-audits-bug-bounties} +## 测试、审计与漏洞赏金 {#testing-vs-audits-bug-bounties} 正如前面提到的,严格的测试很少能够保证合约中没有错误;形式化验证方法可以提供更强的正确性保证,但目前使用起来困难且成本相当高昂。 -尽管如此,你仍可通过进行独立的代码审查来进一步增加捕获合约漏洞的可能性。 [智能合约审查](https://www.immunebytes.com/blog/what-is-a-smart-contract-audit/)和[漏洞奖励](https://medium.com/immunefi/a-defi-security-standard-the-scaling-bug-bounty-9b83dfdc1ba7)是让他人分析你的合约的两种方式。 +尽管如此,你仍可通过进行独立的代码审查来进一步增加捕获合约漏洞的可能性。 [智能合约审计](https://www.immunebytes.com/blog/what-is-a-smart-contract-audit/)和[漏洞赏金](https://medium.com/immunefi/a-defi-security-standard-the-scaling-bug-bounty-9b83dfdc1ba7)是让他人分析你的合约的两种方式。 审查由具有在智能合约中发现安全漏洞和开发不良实践案例经验的审查人员进行。 审核通常包括对整个代码库进行测试(可能包括形式化验证)以及手动审查。 -相反,漏洞奖励计划通常涉及向发现智能合约漏洞并向开发者披露的个人(通常称为[白帽黑客](https://en.wikipedia.org/wiki/White_hat_(computer_security)))提供财务奖励的做法。 漏洞奖励类似于审查,因为它涉及要求其他人帮助发现智能合约中的缺陷。 +相反,漏洞赏金计划通常会向发现智能合约漏洞并向开发者披露的个人(通常称为[白帽黑客](https://en.wikipedia.org/wiki/White_hat_\(computer_security\)))提供经济奖励。 漏洞奖励类似于审查,因为它涉及要求其他人帮助发现智能合约中的缺陷。 主要的区别在于漏洞奖励计划对更广泛的开发者/黑客社区开放,并吸引了一批具有独特技能和经验的道德黑客和独立安全专业人员。 与主要依赖可能拥有有限或狭窄专业知识的团队的智能合约审查相比,这可能是一个优势。 @@ -249,47 +249,49 @@ function auctionEnd() external { ### 单元测试工具 {#unit-testing-tools} -- **[solidity-coverage](https://github.com/sc-forks/solidity-coverage)** - _用 Solidity 编写的智能合约的代码覆盖率工具。_ +- **[solidity-coverage](https://github.com/sc-forks/solidity-coverage)** - _用于以 Solidity 编写的智能合约的代码覆盖率工具。_ - **[Waffle](https://ethereum-waffle.readthedocs.io/en/latest/)** - _用于高级智能合约开发和测试的框架(基于 ethers.js)_。 -- **[Remix 测试](https://github.com/ethereum/remix-project/tree/master/libs/remix-tests)** - _用于测试 Solidity 智能合约的工具。 在 Remix IDE 的“Solidity Unit Testing”插件下工作,该插件用于编写和运行合约的测试用例。_ +- **[Remix Tests](https://github.com/ethereum/remix-project/tree/master/libs/remix-tests)** - _用于测试 Solidity 智能合约的工具。 在 Remix IDE 的“Solidity 单元测试”插件下工作,该插件用于为合约编写和运行测试用例。_ -- **[OpenZeppelin Test Helpers](https://github.com/OpenZeppelin/openzeppelin-test-helpers)** - _用于以太坊智能合约测试的断言库。 确保你的合约按预期运行!_ +- **[OpenZeppelin Test Helpers](https://github.com/OpenZeppelin/openzeppelin-test-helpers)** - _用于以太坊智能合约测试的断言库。 确保您的合约按预期运行!_ -- **[Brownie 单元测试框架](https://eth-brownie.readthedocs.io/en/v1.0.0_a/tests.html)** - _Brownie 采用了 Pytest,这是一个功能丰富的测试框架,让你只需使用最少的代码即可编写小型测试,并能有效地扩展以用于大型项目,而且具有很强的可扩展性。_ +- **[Brownie 单元测试框架](https://eth-brownie.readthedocs.io/en/v1.0.0_a/tests.html)** - _Brownie 使用 Pytest,这是一个功能丰富的测试框架,可让你用最少的代码编写小型测试,能够很好地扩展到大型项目,并且具有高度可扩展性。_ -- **[Foundry 测试](https://github.com/foundry-rs/foundry/tree/master/crates/forge)** - _Foundry 提供了 Forge,这是一个快速灵活的以太坊测试框架,能够执行简单的单元测试、燃料优化检查和合约模糊测试。_ +- **[Foundry 测试](https://github.com/foundry-rs/foundry/tree/master/crates/forge)** - _Foundry 提供 Forge,一个快速灵活的以太坊测试框架,能够执行简单的单元测试、燃料优化检查和合约模糊测试。_ -- **[Hardhat 测试](https://hardhat.org/hardhat-runner/docs/guides/test-contracts)** - _基于 ethers.js、Mocha 和 Chai 的智能合约测试框架。_ +- **[Hardhat Tests](https://hardhat.org/hardhat-runner/docs/guides/test-contracts)** - _基于 ethers.js、Mocha 和 Chai,用于测试智能合约的框架。_ -- **[ApeWorx](https://docs.apeworx.io/ape/stable/userguides/testing.html)** - _基于 Python 的智能合约开发和测试框架,针对太坊虚拟机。_ +- **[ApeWorx](https://docs.apeworx.io/ape/stable/userguides/testing.html)** - _基于 Python 的开发和测试框架,用于面向以太坊虚拟机的智能合约。_ -- **[Wake](https://ackeeblockchain.com/wake/docs/latest/testing-framework/overview/)** - _基于 Python 的单元测试和模糊测试框架,具有强大的调试功能和跨链测试支持,利用 pytest 和 Anvil 实现最佳用户体验和性能。_ +- **[Wake](https://ackeeblockchain.com/wake/docs/latest/testing-framework/overview/)** - _一个基于 Python 的框架,用于单元测试和模糊测试,具有强大的调试功能和跨链测试支持,利用 pytest和 Anvil 实现最佳用户体验和性能。_ -### 基于属性测试的工具 {#property-based-testing-tools} +### 基于属性的测试工具 {#property-based-testing-tools} #### 静态分析工具 {#static-analysis-tools} -- **[Slither](https://github.com/crytic/slither)** - _基于 Python 的 Solidity 静态分析框架,用于查找漏洞、增强代码理解以及为智能合约编写自定义分析。_ +- **[Slither](https://github.com/crytic/slither)** - _一个基于 Python 的 Solidity 静态分析框架,用于发现漏洞、增强代码理解以及为智能合约编写自定义分析。_ + +- **[Ethlint](https://ethlint.readthedocs.io/en/latest/)** - _用于为 Solidity 智能合约编程语言强制执行样式和安全最佳实践的 Linter。_ -- **[Ethlint](https://ethlint.readthedocs.io/en/latest/)** - _用于执行Solidity 智能合约编程语言的风格和安全最佳实践的 Linter。_ +- **[Cyfrin Aderyn](https://cyfrin.io/tools/aderyn)** - _一个基于 Rust 的静态分析器,专为 Web3 智能合约的安全和开发而设计。_ -- **[Cyfrin Aderyn](https://cyfrin.io/tools/aderyn)** - _基于 Rust 的静态分析器,专为 Web3 智能合约安全和开发而设计。_ +- **[Wake](https://ackeeblockchain.com/wake/docs/latest/static-analysis/using-detectors/)** - _一个基于 Python 的静态分析框架,具有漏洞和代码质量检测器、用于从代码中提取有用信息的打印机以及对编写自定义子模块的支持。_ -- **[Wake](https://ackeeblockchain.com/wake/docs/latest/static-analysis/using-detectors/)** - _基于 Python 的静态分析框架,具有漏洞和代码质量检测器,用于从代码中提取有用信息的打印机以及对编写自定义子模块的支持。_ +- **[Slippy](https://github.com/fvictorio/slippy)** - _一个简单而强大的 Solidity linter。_ #### 动态分析工具 {#dynamic-analysis-tools} -- **[Echidna](https://github.com/crytic/echidna/)** - _通过基于属性的测试来检测智能合约漏洞的快速合约模糊测试工具。_ +- **[Echidna](https://github.com/crytic/echidna/)** - _快速的合约模糊测试器,通过基于属性的测试来检测智能合约中的漏洞。_ -- **[Diligence Fuzzing](https://consensys.net/diligence/fuzzing/)** - _自动化模糊测试工具,用于检测智能合约代码中的属性违规行为。_ +- **[Diligence Fuzzing](https://consensys.net/diligence/fuzzing/)** - _自动化模糊测试工具,可用于检测智能合约代码中的属性违规。_ -- **[Manticore](https://manticore.readthedocs.io/en/latest/index.html)** - _用于分析以太坊虚拟机 (EVM) 字节码的动态符号执行框架。_ +- **[Manticore](https://manticore.readthedocs.io/en/latest/index.html)** - _用于分析 EVM 字节码的动态符号执行框架。_ -- **[Mythril](https://github.com/ConsenSys/mythril-classic)** - _以太坊虚拟机 (EVM) 字节码评估工具,利用污点分析、混合执行分析和控制流检查来检测合约漏洞。_ +- **[Mythril](https://github.com/ConsenSys/mythril-classic)** - _EVM 字节码评估工具,使用污点分析、混合执行分析和控制流检查来检测合约漏洞。_ -- **[Diligence Scribble](https://consensys.net/diligence/scribble/)** - _Scribble 是一种规约语言和运行时验证工具,可让你为智能合约批注属性,从而使用 Diligence Fuzzing 或 MythX 等工具自动测试合约。_ +- **[Diligence Scribble](https://consensys.net/diligence/scribble/)** - _Scribble 是一种规范语言和运行时验证工具,可让你为智能合约添加属性注释,以便使用 Diligence Fuzzing或 MythX 等工具自动测试合约。_ ## 相关教程 {#related-tutorials} @@ -297,12 +299,12 @@ function auctionEnd() external { - [如何使用 Echidna 测试智能合约](/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/) - [如何使用 Manticore 查找智能合约漏洞](/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/) - [如何使用 Slither 查找智能合约漏洞](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/) -- [如何模拟测试 Solidity 合约](/developers/tutorials/how-to-mock-solidity-contracts-for-testing/) -- [如何利用 Foundry 在 Solidity 中运行单元测试](https://www.rareskills.io/post/foundry-testing-solidity) +- [如何模拟 Solidity 合约以进行测试](/developers/tutorials/how-to-mock-solidity-contracts-for-testing/) +- [如何使用 Foundry 在 Solidity 中运行单元测试](https://www.rareskills.io/post/foundry-testing-solidity) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [以太坊智能合约测试深度指南](https://iamdefinitelyahuman.medium.com/an-in-depth-guide-to-testing-ethereum-smart-contracts-2e41b2770297) +- [以太坊智能合约深度测试指南](https://iamdefinitelyahuman.medium.com/an-in-depth-guide-to-testing-ethereum-smart-contracts-2e41b2770297) - [如何测试以太坊智能合约](https://betterprogramming.pub/how-to-test-ethereum-smart-contracts-35abc8fa199d) -- [MolochDAO 开发者单元测试指南](https://github.com/MolochVentures/moloch/tree/4e786db8a4aa3158287e0935dcbc7b1e43416e38/test#moloch-testing-guide) -- [如何像专家一样测试智能合约](https://forum.openzeppelin.com/t/test-smart-contracts-like-a-rockstar/1001) +- [MolochDAO 的开发者单元测试指南](https://github.com/MolochVentures/moloch/tree/4e786db8a4aa3158287e0935dcbc7b1e43416e38/test#moloch-testing-guide) +- [如何像摇滚明星一样测试智能合约](https://forum.openzeppelin.com/t/test-smart-contracts-like-a-rockstar/1001) diff --git a/public/content/translations/zh/developers/docs/smart-contracts/upgrading/index.md b/public/content/translations/zh/developers/docs/smart-contracts/upgrading/index.md index 23590b5f85e..fab52f8ef96 100644 --- a/public/content/translations/zh/developers/docs/smart-contracts/upgrading/index.md +++ b/public/content/translations/zh/developers/docs/smart-contracts/upgrading/index.md @@ -1,6 +1,6 @@ --- -title: 升级智能合约 -description: 以太坊智能合约的升级模式概述 +title: "升级智能合约" +description: "以太坊智能合约的升级模式概述" lang: zh --- @@ -12,10 +12,9 @@ lang: zh ## 前提条件 {#prerequisites} -你应当充分了解[智能合约](/developers/docs/smart-contracts/)、[智能合约结构](/developers/docs/smart-contracts/anatomy/)以及[以太坊虚拟机 (EVM)](/developers/docs/evm/)。 本指南还假定读者掌握了编写智能合约的知识。 +你应该对[智能合约](/developers/docs/smart-contracts/)、[智能合约剖析](/developers/docs/smart-contracts/anatomy/)和[以太坊虚拟机 (EVM)](/developers/docs/evm/) 有深入的了解。 本指南还假定读者掌握了编写智能合约的知识。 ## 什么是智能合约升级? {#what-is-a-smart-contract-upgrade} - 智能合约升级涉及更改智能合约的业务逻辑,同时保留合约的状态。 重要的是要澄清,可升级性和可变性并不是相同的概念,尤其是在智能合约的背景下。 你仍然无法更改在以太坊网络地址上部署的程序。 但是你可以更改与用户交互时执行的智能合约代码。 @@ -66,17 +65,17 @@ lang: zh 1. 用户与代理合约进行交互,代理合约存储数据,但不保存业务逻辑。 -2. 代理合约存储逻辑合约的地址,并使用 `delegatecall` 函数将所有函数调用委托给逻辑合约(逻辑合约保存业务逻辑)。 +2. 代理合约存储逻辑合约的地址,并使用 `delegatecall` 函数将所有函数调用委托给逻辑合约(其中包含业务逻辑)。 3. 调用转移到逻辑合约后,逻辑合约返回的数据将被检索并返回给用户。 -使用代理模式需要了解 **delegatecall** 函数。 基本上,`delegatecall` 是一个操作码,它允许一个合约调用另一个合约,而实际的代码执行在调用合约过程中进行。 在代理模式中使用 `delegatecall` 的意义是,代理合约会读写其存储,并执行存储在逻辑合约中的逻辑,就像调用内部函数一样。 +使用代理模式需要了解 **delegatecall** 函数。 基本上,`delegatecall` 是一个操作码,它允许一个合约调用另一个合约,而实际的代码执行发生在调用合约的上下文中。 在代理模式中使用 `delegatecall` 的一个意义在于,代理合约读写其存储,并执行存储在逻辑合约中的逻辑,就像调用内部函数一样。 摘自 [Solidity 文档](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html#delegatecall-callcode-and-libraries): -> _存在一种消息调用的特殊变体,名为 **delegatecall**,它与消息调用相同,但是目标地址的代码在调用合约的语境(即地址)下执行,并且 `msg.sender` 和 `msg.value` 不会更改其值。__这意味着合约在运行时可以从不同的地址动态加载代码。 存储、当前地址和余额仍参考调用合约,只是代码取自被调用地址。_ +> _存在一种特殊的消息调用变体,名为 **delegatecall**,它与消息调用相同,不同之处在于目标地址的代码在调用合约的上下文(即地址)中执行,并且 `msg.sender` 和 `msg.value` 的值不会改变。_ _这意味着合约可以在运行时从不同的地址动态加载代码。_ 存储、当前地址和余额仍参考调用合约,只是代码取自被调用地址。 -每当用户调用函数时,代理合约就会调用 `delegatecall`,因为它内置了一个 `fallback` 函数。 在 Solidity 编程中,当函数调用与合约中指定的函数不匹配时,将执行[回退函数](https://docs.soliditylang.org/en/latest/contracts.html#fallback-function)。 +每当用户调用函数时,代理合约就会调用 delegatecall,因为它内置了一个 fallback 函数。 在 Solidity 编程中,当一个函数调用与合约中指定的函数不匹配时,就会执行[回退函数](https://docs.soliditylang.org/en/latest/contracts.html#fallback-function)。 要使代理模式正常工作,需要编写一个自定义的回退函数,指定代理合约应如何处理它不支持的函数调用。 在这种情况下,代理的回退函数被编程为启动委托调用,并将用户的请求转发给当前的逻辑合约实现。 @@ -84,7 +83,7 @@ lang: zh 通过将代理合约指向新的逻辑合约,用户调用代理合约函数时执行的代码就会发生变化。 这样,我们就可以在不要求用户与新合约进行交互的情况下,升级合约的逻辑。 -代理模式是一种流行的智能合约升级方法,因为它消除了与合约迁移相关的困难。 但是,代理模式的使用更为复杂,如果使用不当,可能会带来严重缺陷,例如[函数选择器冲突](https://medium.com/nomic-foundation-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357)。 +代理模式是一种流行的智能合约升级方法,因为它消除了与合约迁移相关的困难。 但是,代理模式使用起来更复杂,如果使用不当,可能会引入严重缺陷,例如[函数选择器冲突](https://medium.com/nomic-foundation-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357)。 [更多关于代理模式的信息](https://blog.openzeppelin.com/proxy-patterns/)。 @@ -94,7 +93,7 @@ lang: zh 在这种情况下,主合约包含核心业务逻辑,但与其他智能合约(“卫星合约”)进行接口交互,以执行某些功能。 该主合约还存储每个卫星合约的地址,并可在卫星合约的不同实现之间切换。 -你可以构建一个新的卫星合约,并为主合约配置新地址。 这允许你更改智能合约的_策略_(即实现新的逻辑)。 +你可以构建一个新的卫星合约,并为主合约配置新地址。 这允许你为智能合约更改_策略_(即实现新逻辑)。 虽然策略模式与前面讨论的代理模式类似,但不同之处在于,与用户交互的主合约中包含了业务逻辑。 使用这种模式可以让你有机会在不影响核心基础架构的情况下对智能合约进行有限的更改。 @@ -104,9 +103,9 @@ lang: zh 钻石模式可以说是代理模式的改进。 钻石模式不同于代理模式,因为钻石代理合约可以将函数调用委托给多个逻辑合约。 -钻石模式中的逻辑合约被称为_“切面”_ 。 要使钻石模式发挥作用,你需要在代理合约中创建一个映射,将[函数选择器](https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector)映射到不同的“切面”地址。 +钻石模式中的逻辑合约被称为_切面_。 要使钻石模式生效,你需要在代理合约中创建一个映射,将[函数选择器](https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector)映射到不同的切面地址。 -当用户调用函数时,代理合约会检查映射,以找到负责执行该函数的“切面”。 然后,它会调用 `delegatecall`(使用回退函数),并将调用重定向到相应的逻辑合约。 +当用户调用函数时,代理合约会检查映射,以找到负责执行该函数的“切面”。 然后,它会调用 delegatecall(使用回退函数),并将调用重定向到相应的逻辑合约。 与传统的代理升级模式相比,钻石升级模式有一些优势: @@ -114,7 +113,7 @@ lang: zh 2. 所有智能合约(包括代理模式下使用的逻辑合约)的大小限制为 24KB,这可能是一个限制 — 特别是对于需要更多函数的复杂合约。 钻石模式通过在多个逻辑合约中拆分函数,轻松解决了这一问题。 -3. 代理模式采用了一种一揽子的访问控制方法。 可访问升级功能的实体能够更改_整个_合约。 但是,钻石模式支持模块化权限方法,可以限制实体升级智能合约中的某些功能。 +3. 代理模式采用了一种一揽子的访问控制方法。 有权访问升级功能的实体可以更改_整个_合约。 但是,钻石模式支持模块化权限方法,可以限制实体升级智能合约中的某些功能。 [更多关于钻石模式的信息](https://eip2535diamonds.substack.com/p/introduction-to-the-diamond-standard?s=w)。 @@ -128,13 +127,13 @@ lang: zh | 合约升级为开发者提供了更广阔的空间来试验不同的功能和不断改进去中心化应用程序。 | 升级智能合约的机会可能会促使开发者更快启动项目,但在开发阶段不进行尽职审查。 | | | 智能合约中不安全的访问控制或中心化会让恶意行为者更容易执行未经授权的升级。 | -## 升级智能合约的考量 {#considerations-for-upgrading-smart-contracts} +## 升级智能合约的注意事项 {#considerations-for-upgrading-smart-contracts} 1. 使用安全的访问控制或授权机制,防止未经授权的智能合约升级,尤其是在使用代理模式、策略模式或数据分离的情况下。 例如,限制升级功能的访问权限,只有合约所有者才能调用该功能。 2. 升级智能合约是一项复杂的活动,需要高度谨慎以防止引入漏洞。 -3. 通过分散实施升级的流程,减少信任假设。 可行策略包括使用[多重签名钱包合约](/developers/docs/smart-contracts/#multisig)来控制升级,或要求[去中心化自治组织的成员](/dao/)投票批准升级。 +3. 通过分散实施升级的流程,减少信任假设。 可能的策略包括使用[多签钱包合约](/developers/docs/smart-contracts/#multisig)来控制升级,或要求 [DAO 的成员](/dao/)投票批准升级。 4. 了解合约升级所涉及的费用。 例如,在合约迁移过程中,将状态(如用户余额)从旧合约复制到新合约可能需要不止一次交易,这意味着更多的燃料费用。 @@ -142,24 +141,24 @@ lang: zh 如果用户不同意拟议的更改(如逻辑升级或新的收费方案),时间锁会给他们一些时间退出系统。 如果没有时间锁,用户就需要相信开发者不会在没有事先通知的情况下对智能合约进行任意更改。 缺点是,时间锁限制了快速修补漏洞的能力。 -## 资源 {#resources} +## 资源{#resources} **OpenZeppelin 升级插件 - _一套用于部署和保护可升级智能合约的工具。_** - [GitHub](https://github.com/OpenZeppelin/openzeppelin-upgrades) -- [相关文档](https://docs.openzeppelin.com/upgrades) +- [文档](https://docs.openzeppelin.com/upgrades) ## 教程 {#tutorials} -- [升级智能合约 | YouTube 教程](https://www.youtube.com/watch?v=bdXJmWajZRY) - Patrick Collins -- [以太坊智能合约迁移教程](https://medium.com/coinmonks/ethereum-smart-contract-migration-13f6f12539bd) - Austin Griffith -- [使用 UUPS 代理模式升级智能合约](https://blog.logrocket.com/author/praneshas/) - Pranesh A.S -- [Web3 教程:使用 OpenZeppelin 编写可升级智能合约(代理)](https://dev.to/yakult/tutorial-write-upgradeable-smart-contract-proxy-contract-with-openzeppelin-1916)- fangjun.eth +- [升级你的智能合约 | YouTube 教程](https://www.youtube.com/watch?v=bdXJmWajZRY) by Patrick Collins +- [以太坊智能合约迁移教程](https://medium.com/coinmonks/ethereum-smart-contract-migration-13f6f12539bd) by Austin Griffith +- [使用 UUPS 代理模式升级智能合约](https://blog.logrocket.com/author/praneshas/) by Pranesh A.S +- [Web3 教程:使用 OpenZeppelin 编写可升级智能合约(代理)](https://dev.to/yakult/tutorial-write-upgradeable-smart-contract-proxy-contract-with-openzeppelin-1916) by fangjun.eth -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [智能合约升级的现状](https://blog.openzeppelin.com/the-state-of-smart-contract-upgrades/) - Santiago Palladino -- [升级 Solidity 智能合约的多种方法](https://cryptomarketpool.com/multiple-ways-to-upgrade-a-solidity-smart-contract/) - Crypto Market Pool 博客 +- [智能合约升级现状](https://blog.openzeppelin.com/the-state-of-smart-contract-upgrades/) by Santiago Palladino +- [升级 Solidity 智能合约的多种方式](https://cryptomarketpool.com/multiple-ways-to-upgrade-a-solidity-smart-contract/) - Crypto Market Pool 博客 - [学习:升级智能合约](https://docs.openzeppelin.com/learn/upgrading-smart-contracts) - OpenZeppelin 文档 -- [实现 Solidity 合约可升级性的代理模式:透明代理与 UUPS代理](https://mirror.xyz/0xB38709B8198d147cc9Ff9C133838a044d78B064B/M7oTptQkBGXxox-tk9VJjL66E1V8BUF0GF79MMK4YG0) - Naveen Sahu -- [钻石升级如何运作](https://dev.to/mudgen/how-diamond-upgrades-work-417j) - Nick Mudge +- [用于 Solidity 合约可升级性的代理模式:透明代理与 UUPS 代理](https://mirror.xyz/0xB38709B8198d147cc9Ff9C133838a044d78B064B/M7oTptQkBGXxox-tk9VJjL66E1V8BUF0GF79MMK4YG0) by Naveen Sahu +- [钻石升级如何运作](https://dev.to/mudgen/how-diamond-upgrades-work-417j) by Nick Mudge diff --git a/public/content/translations/zh/developers/docs/smart-contracts/verifying/index.md b/public/content/translations/zh/developers/docs/smart-contracts/verifying/index.md index edf98cdd826..e9dac8375f6 100644 --- a/public/content/translations/zh/developers/docs/smart-contracts/verifying/index.md +++ b/public/content/translations/zh/developers/docs/smart-contracts/verifying/index.md @@ -1,36 +1,36 @@ --- -title: 验证智能合约 -description: 以太坊智能合约源代码验证概述 +title: "验证智能合约" +description: "以太坊智能合约源代码验证概述" lang: zh --- -[智能合约](/developers/docs/smart-contracts/)被设计成“去信任”,即用户去信任第三方(例如,开发者和团体)便可与智能合约交互。 去信任的一个必要条件就是用户和其他开发者必须能够验证智能合约的源代码。 而验证源代码能够向用户和开发者保证已发布的合约代码和以太坊区块链上运行的代码相同。 +[智能合约](/developers/docs/smart-contracts/)被设计为“去信任”的,这意味着用户在与合约交互之前,不必信任第三方(例如,开发者和公司)。 去信任的一个必要条件就是用户和其他开发者必须能够验证智能合约的源代码。 而验证源代码能够向用户和开发者保证已发布的合约代码和以太坊区块链上运行的代码相同。 区分“源代码验证”和“[形式化验证](/developers/docs/smart-contracts/formal-verification/)”很重要。 源代码验证指的是验证用高级语言(例如 Solidity)编写的智能合约的给定源代码是否能编译成在合约地址执行的相同字节码,下文将会详细说明。 而形式化验证则是验证智能合约的正确性,即验证合约行为是否符合预期。 合约验证尽管要视上下文而定,但是通常是指源代码验证。 ## 什么是源代码验证? {#what-is-source-code-verification} -在将智能合约部署在[以太坊虚拟机 (EVM)](/developers/docs/evm/) 中前,开发者会将合约源代码(即[用 Solidity](/developers/docs/smart-contracts/languages/) 或其他高级编程语言编写的指令)[编译](/developers/docs/smart-contracts/compiling/)成字节码。 不过,由于以太坊虚拟机无法解释高级指令,为了在以太坊虚拟机中执行合约逻辑,必须将源代码编译成字节码(即低级机器指令)。 +在将智能合约部署在[以太坊虚拟机 (EVM)](/developers/docs/evm/) 中前,开发者会[编译](/developers/docs/smart-contracts/compiling/)合约源代码(即用 [Solidity](/developers/docs/smart-contracts/languages/) 或其他高级编程语言编写的指令)成字节码。 不过,由于以太坊虚拟机无法解释高级指令,为了在以太坊虚拟机中执行合约逻辑,必须将源代码编译成字节码(即低级机器指令)。 为检测差异,源代码验证会对智能合约的源代码与合约创建过程中使用的编译字节码进行比较处理。 由于广告合约代码与区块链上运行的代码可能不同,因此验证智能合约极为重要。 通过智能合约验证,用户无需阅读机器代码就能通过编写合约所使用的高级语言来研究合约的行为。 函数、值以及变量名和评论与编译和部署的原始源代码一般是相同的。 这就让代码阅读变得更加容易了。 源代码验证还对代码文档做出了规定,以便最终用户了解智能合约的用途。 -### 什么是完全验证? {#full-verification} +### 什么是完全验证? 完全验证 {#full-verification} 源代码的某些部分不会影响编译好的字节码,如评论和变量名。 也就是说两段变量名和评论都不同的源代码能验证同一份合约。 这样一来,恶意行为者便能在源代码中添加欺骗性评论或给出误导性变量名,也能用与原始源代码不同的源代码来验证合约。 -要想避免这种情况,可以在字节码中添加额外数据作为源代码准确性的_加密保障_和编译信息的_指纹_。 必要的信息可以在 [Solidity 合约元数据](https://docs.soliditylang.org/en/v0.8.15/metadata.html)中找到,并且此文件的哈希值附在了合约的字节码中。 你可以在[元数据训练场](https://playground.sourcify.dev)中检查运行情况。 +要想避免这种情况,可以在字节码中添加额外数据,作为源代码准确性的_加密保障_和编译信息的_指纹_。 必要的信息可以在 [Solidity 的合约元数据](https://docs.soliditylang.org/en/v0.8.15/metadata.html)中找到,并且此文件的哈希会附加到合约的字节码中。 你可以在[元数据演练场](https://playground.sourcify.dev)中查看它的实际运行情况。 元数据文件包含有关合约的编译信息,合约中包括源文件和源文件的哈希值。 也就是说,一旦有任何源文件中的编译设置甚至是某个字节有所更改,整个元数据文件也会发生变化。 因此,附在字节码上的元数据文件的哈希值也会变化。 也就意味着只要合约的字节码和所附元数据哈希值与给定的源代码和编译设置相匹配,我们就能确定这就是原始编译中所使用的源代码,丝毫不差。 -这种利用元数据哈希值的验证方法就叫做**“[完全验证](https://docs.sourcify.dev/docs/full-vs-partial-match/)”**(也叫“完美验证”)。 如果元数据哈希值不匹配或是未用于验证,那就叫做“部分验证”,也是目前更为常见的合约验证方法。 可能会[植入恶意代码](https://samczsun.com/hiding-in-plain-sight/),如果不进行完全验证这些恶意代码未必会显现在经过验证的源代码中。 由于大多数开发者不了解完全验证,也不会保留自己编译的元数据文件,因此部分验证实际上才是目前验证合约的常用方法。 +这种利用元数据哈希的验证类型被称为\*\*“[完全验证](https://docs.sourcify.dev/docs/full-vs-partial-match/)”\*\*(也称“完美验证”)。 如果元数据哈希值不匹配或是未用于验证,那就叫做“部分验证”,也是目前更为常见的合约验证方法。 如果不进行完全验证,就可能[插入恶意代码](https://samczsun.com/hiding-in-plain-sight/),而这些代码不会在已验证的源代码中反映出来。 由于大多数开发者不了解完全验证,也不会保留自己编译的元数据文件,因此部分验证实际上才是目前验证合约的常用方法。 -## 为什么源代码验证如此重要? {#importance-of-source-code-verification} +## 为什么源代码验证如此重要? 源代码验证的重要性 {#importance-of-source-code-verification} ### 去信任 {#trustlessness} -去信任可以说是智能合约和[去中心化应用程序 (dapp)](/developers/docs/dapps/) 的最重要的先决条件。 智能合约是“不可变”的,无法更改;合约只会执行部署时代码中定义的业务逻辑。 这意味着开发者和企业在以太坊上部署合约后无法篡改合约代码。 +去信任可以说是智能合约和[去中心化应用程序 (dapps)](/developers/docs/dapps/) 最重要的前提。 智能合约是“不可变”的,无法更改;合约只会执行部署时代码中定义的业务逻辑。 这意味着开发者和企业在以太坊上部署合约后无法篡改合约代码。 为了让智能合约去信任,合约代码应可供独立验证。 虽然每份智能合约的编译字节码都可以在区块链上公开获取,但低级语言对于开发者和用户来说都难以理解。 @@ -40,13 +40,13 @@ lang: zh ### 用户安全 {#user-safety} -智能合约通常涉及大量质押资金。 这就需要更高的安全保证,并在使用智能合约前对其逻辑进行验证。 问题在于,不法开发者可以通过在智能合约中插入恶意代码来欺骗用户。 如果不进行验证,恶意智能合约就可能存在[后门](https://www.trustnodes.com/2018/11/10/concerns-rise-over-backdoored-smart-contracts)、矛盾的访问控制机制、可被利用的漏洞以及其他危害用户安全的问题,而这些问题甚至难以察觉。 +智能合约通常涉及大量质押资金。 这就需要更高的安全保证,并在使用智能合约前对其逻辑进行验证。 问题在于,不法开发者可以通过在智能合约中插入恶意代码来欺骗用户。 若不经验证,恶意智能合约可能包含[后门](https://www.trustnodes.com/2018/11/10/concerns-rise-over-backdoored-smart-contracts)、有争议的访问控制机制、可利用的漏洞,以及其他危及用户安全却未被发现的问题。 公布智能合约的源代码文件可以让审查人员等相关人员更容易评估合约,预防潜在攻击向量。 通过多方独立验证智能合约,用户可以获得更加强有力的安全性保障。 ## 如何验证以太坊智能合约的源代码 {#source-code-verification-for-ethereum-smart-contracts} -[在以太坊上部署智能合约](/developers/docs/smart-contracts/deploying/)需要向一个特殊地址发送包含数据有效载荷(编译字节码)的交易。 数据有效载荷通过编译源代码以及附加到交易中的数据有效载荷的合约实例的[构造函数参数](https://docs.soliditylang.org/en/v0.8.14/contracts.html#constructor)来生成。 编译是确定性的,这意味着如果使用相同的源文件和编译设置(如编译器版本、优化器),它总是产生相同的输出(即合约字节码)。 +[在以太坊上部署智能合约](/developers/docs/smart-contracts/deploying/)需要向一个特殊地址发送一笔包含数据负载(已编译的字节码)的交易。 数据负载由编译源代码生成,合约实例的[构造函数参数](https://docs.soliditylang.org/en/v0.8.14/contracts.html#constructor)会附加到交易数据负载的末尾。 编译是确定性的,这意味着如果使用相同的源文件和编译设置(例如,编译器版本、优化器),它总是产生相同的输出(即合约字节码)。 ![智能合约源代码验证示意图](./source-code-verification.png) @@ -62,7 +62,7 @@ lang: zh 5. 此外,如果字节码末尾的元数据哈希值匹配,则将是完全匹配。 -请注意,这只是对智能合约验证过于简单的描述,还有像具有[不可变变量](https://docs.sourcify.dev/docs/immutables/)等许多例外情况不适用。 +请注意,这只是对验证的简单描述,有很多例外情况(例如存在[不可变变量](https://docs.sourcify.dev/docs/immutables/))不适用于此方法。 ## 源代码验证工具 {#source-code-verification-tools} @@ -70,38 +70,44 @@ lang: zh ### Etherscan {#etherscan} -尽管 Etherscan 通常作为[以太坊区块链浏览器](/developers/docs/data-and-analytics/block-explorers/)被大众所知晓,但它也能为智能合约开发者和用户提供[源代码验证服务](https://etherscan.io/verifyContract)。 +虽然 Etherscan 主要作为[以太坊区块链浏览器](/developers/docs/data-and-analytics/block-explorers/)而闻名,但它也为智能合约开发者和用户提供[源代码验证服务](https://etherscan.io/verifyContract)。 -Etherscan 允许你根据原始数据有效载荷(源代码、库地址、编译器设置、合约地址等)重新编译合约字节码。 如果重新编译的字节码与链上合约的字节码(和构造函数参数)相关联,那么[合约就通过了验证](https://info.etherscan.com/types-of-contract-verification/)。 +Etherscan 允许你根据原始数据有效载荷(源代码、库地址、编译器设置、合约地址等)重新编译合约字节码。 如果重新编译的字节码与链上合约的字节码(和构造函数参数)匹配,则[该合约通过验证](https://info.etherscan.com/types-of-contract-verification/)。 -一旦通过验证,你的合约源代码将获得“已验证”标签,并发布在 Etherscan 上供他人审查。 它还会被添加到[已验证合约](https://etherscan.io/contractsVerified/)部分 — 这是包含源代码已验证的智能合约的存储库。 +一旦通过验证,你的合约源代码将获得“已验证”标签,并发布在 Etherscan 上供他人审查。 它还会被添加到[已验证合约](https://etherscan.io/contractsVerified/)部分——一个存储已验证源代码的智能合约的存储库。 -Etherscan 是最常用的合约验证工具。 但是,Etherscan 的合约验证有一个缺点:它无法比较链上字节码和重新编译字节码的**元数据哈希值**。 因此,Etherscan 中的匹配结果是部分匹配。 +Etherscan 是最常用的合约验证工具。 然而,Etherscan 的合约验证有一个缺点:它无法比较链上字节码和重新编译字节码的**元数据哈希**。 因此,Etherscan 中的匹配结果是部分匹配。 [更多关于在 Etherscan 上验证合约的信息](https://medium.com/etherscan-blog/verifying-contracts-on-etherscan-f995ab772327)。 +### Blockscout {#blockscout} + +[Blockscout](https://blockscout.com/) 是一个开源区块链浏览器,也为智能合约开发者和用户提供[合约验证服务](https://eth.blockscout.com/contract-verification)。 作为一个开源替代方案,Blockscout 提供了验证过程的透明性,并支持社区通过贡献来改进验证过程。 + +与其他验证服务类似,Blockscout 允许你通过重新编译字节码并将其与已部署的合约比较来验证合约的源代码。 一旦验证通过,你的合约将收到验证状态,并且源代码将被公开以便审计和交互。 已验证的合约也会在 Blockscout 的[已验证合约存储库](https://eth.blockscout.com/verified-contracts)中列出,以便轻松浏览和发现。 + ### Sourcify {#sourcify} -[Sourcify](https://sourcify.dev/#/verifier) 是另一种用于验证开源和去中心化合约的工具。 它不是区块浏览器,只能在[不同的基于以太坊虚拟机的网络](https://docs.sourcify.dev/docs/chains)上验证合约。 它充当公共基础设施,作为其他工具的构建基础,旨在使用元数据文件中的[应用程序二进制接口](/developers/docs/smart-contracts/compiling/#web-applications)和 [NatSpec](https://docs.soliditylang.org/en/v0.8.15/natspec-format.html) 注释来实现更人性化的合约交互。 +[Sourcify](https://sourcify.dev/#/verifier)是另一个用于验证合约的工具,它是开源和去中心化的。 它不是区块浏览器,只在[不同的基于 EVM 的网络](https://docs.sourcify.dev/docs/chains)上验证合约。 它可作为其他工具在其上构建的公共基础设施,旨在使用元数据文件中的[ABI](/developers/docs/smart-contracts/compiling/#web-applications) 和 [NatSpec](https://docs.soliditylang.org/en/v0.8.15/natspec-format.html) 注释,实现更方便用户的合约交互。 -与 Etherscan 不同,Sourcify 支持与元数据哈希值完全匹配。 经过验证的合约在超文本传输协议和 [星际文件系统](https://docs.ipfs.io/concepts/what-is-ipfs/#what-is-ipfs) 上的[公共存储库](https://docs.sourcify.dev/docs/repository/)中访问,这是一种去中心化的[内容寻址](https://web3.storage/docs/concepts/content-addressing/)存储。 由于附加的元数据哈希值是 IPFS 哈希值,因此可以通过 IPFS 获取合约的元数据文件。 +与 Etherscan 不同,Sourcify 支持与元数据哈希值完全匹配。 已验证的合约通过 HTTP 和 [IPFS](https://docs.ipfs.io/concepts/what-is-ipfs/#what-is-ipfs) 在其[公共存储库](https://docs.sourcify.dev/docs/repository/)中提供,IPFS 是一种去中心化的[内容寻址](https://docs.storacha.network/concepts/content-addressing/)存储。 由于附加的元数据哈希值是 IPFS 哈希值,因此可以通过 IPFS 获取合约的元数据文件。 -此外,人们还可以通过星际文件系统检索源代码文件,因为这些文件的星际文件系统哈希值也可以在元数据中找到。 可以通过应用程序接口或[用户界面](https://sourcify.dev/#/verifier)或使用插件提供元数据文件和源文件来验证合约。 Sourcify 监控工具还会监查新区块上的合约创建情况,并尝试验证合约是否在 IPFS 上公布了元数据和源文件。 +此外,人们还可以通过星际文件系统检索源代码文件,因为这些文件的星际文件系统哈希值也可以在元数据中找到。 可以通过其 API 或[用户界面](https://sourcify.dev/#/verifier)提供元数据文件和源文件,或使用插件来验证合约。 Sourcify 监控工具还会监查新区块上的合约创建情况,并尝试验证合约是否在 IPFS 上公布了元数据和源文件。 -[有关在 Sourcify 上验证合约的更多信息](https://blog.soliditylang.org/2020/06/25/sourcify-faq/)。 +[更多关于在 Sourcify 上验证合约的信息](https://soliditylang.org/blog/2020/06/25/sourcify-faq/)。 ### Tenderly {#tenderly} -[Tenderly 平台](https://tenderly.co/)使 Web3 开发者能够构建、测试、监控和操作智能合约。 Tenderly 将调试工具、可观测性和构建区块的基础设施相结合,帮助开发者加快智能合约的开发。 要完全启用 Tenderly 功能,开发者需要使用多种方法[执行源代码验证](https://docs.tenderly.co/monitoring/contract-verification)。 +[Tenderly 平台](https://tenderly.co/)使 Web3 开发者能够构建、测试、监控和操作智能合约。 Tenderly 将调试工具、可观测性和构建区块的基础设施相结合,帮助开发者加快智能合约的开发。 要完全启用 Tenderly 的功能,开发者需要使用多种方法来[执行源代码验证](https://docs.tenderly.co/monitoring/contract-verification)。 可以私下或公开验证合约。 如果是私下验证,智能合约只有你(和项目中的其他成员)可见。 而公开验证合约可让使用 Tenderly 平台的每个人都能看到。 -你可以使用[仪表板](https://docs.tenderly.co/monitoring/smart-contract-verification/verifying-a-smart-contract)、[Tenderly Hardhat 插件](https://docs.tenderly.co/monitoring/smart-contract-verification/verifying-contracts-using-the-tenderly-hardhat-plugin)或 [CLI](https://docs.tenderly.co/monitoring/smart-contract-verification/verifying-contracts-using-cli) 来验证你的合约。 +你可以使用[仪表板](https://docs.tenderly.co/contract-verification)、[Tenderly Hardhat 插件](https://docs.tenderly.co/contract-verification/hardhat)或 [CLI](https://docs.tenderly.co/monitoring/smart-contract-verification/verifying-contracts-using-cli) 来验证你的合约。 通过仪表板验证合约时,需要导入源文件或 Solidity 编译器生成的元数据文件、地址/网络和编译器设置。 使用 Tenderly Hardhat 插件可以更轻松地控制验证过程,让你可以在自动(无代码)和手动(基于代码)验证之间做出选择。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [验证合约源代码](https://programtheblockchain.com/posts/2018/01/16/verifying-contract-source-code/) diff --git a/public/content/translations/zh/developers/docs/standards/index.md b/public/content/translations/zh/developers/docs/standards/index.md index aaa86fe559e..9ae199ae805 100644 --- a/public/content/translations/zh/developers/docs/standards/index.md +++ b/public/content/translations/zh/developers/docs/standards/index.md @@ -1,59 +1,59 @@ --- -title: 以太坊开发标准 -description: +title: "以太坊开发标准" +description: "了解以太坊标准,包括 EIP、代币标准 (ERC-20 和 ERC-721) 以及开发惯例。" lang: zh incomplete: true --- ## 标准概述 {#standards-overview} -以太坊社区已经采用了许多标准,这有助于在项目的不同实现中保持互操作性(例如[以太坊客户端](/developers/docs/nodes-and-clients/)和钱包),并确保智能合约和去中心化应用程序保持可组合性。 +以太坊社区已经采用了许多标准,这有助于在项目的不同实现中保持互操作性(例如 [以太坊客户端](/developers/docs/nodes-and-clients/) 和钱包),并确保智能合约和去中心化应用程序保持可组合性。 -通常,标准作为[以太坊改进提案](/eips/) (EIP) 提出,由社区成员通过[标准流程](https://eips.ethereum.org/EIPS/eip-1)讨论确定。 +通常,标准以[以太坊改进提案](/eips/) (EIP) 的形式提出,由社区成员通过[标准流程](https://eips.ethereum.org/EIPS/eip-1)进行讨论。 -- [以太坊改进提案介绍](/eips/) +- [EIP 简介](/eips/) - [EIP 列表](https://eips.ethereum.org/) -- [EIP GitHub 存储库](https://github.com/ethereum/EIPs) -- [EIP 讨论板](https://ethereum-magicians.org/c/eips) +- [EIP GitHub 仓库](https://github.com/ethereum/EIPs) +- [EIP 讨论区](https://ethereum-magicians.org/c/eips) - [以太坊治理简介](/governance/) - [以太坊治理概述](https://web.archive.org/web/20201107234050/https://blog.bmannconsulting.com/ethereum-governance/) _2019 年 3 月 31 日 - Boris Mann_ - [以太坊协议开发治理和网络升级协调](https://hudsonjameson.com/posts/2020-03-23-ethereum-protocol-development-governance-and-network-upgrade-coordination/) _2020 年 3 月 23 日 - Hudson Jameson_ -- [以太坊核心开发者会议播放列表](https://www.youtube.com/@EthereumProtocol)_(YouTube 播放列表)_ +- [所有以太坊核心开发者会议的播放列表](https://www.youtube.com/@EthereumProtocol) _(YouTube 播放列表)_ -## 标准的类型 {#types-of-standards} +## 标准类型 {#types-of-standards} EIP 有 3 种类型: - 标准方向:描述影响大多数或所有以太坊实现的任何更改 -- [元方向](https://eips.ethereum.org/meta):描述围绕以太坊的流程或提议对流程的更改 -- [信息方向](https://eips.ethereum.org/informational):描述以太坊设计问题或向以太坊社区提供一般指南或信息 +- [元类别](https://eips.ethereum.org/meta):描述关于以太坊的流程或提议对流程的更改 +- [信息类别](https://eips.ethereum.org/informational):描述以太坊的设计问题,或向以太坊社区提供一般性指导或信息 此外,标准跟踪细分为 4 类: - [核心](https://eips.ethereum.org/core):需要共识分叉的改进 -- [网络](https://eips.ethereum.org/networking):围绕 devp2p 和轻量级以太坊 Subprotocol 的改进,以及对 Whisper 和 Swarm 的网络协议规范提议的改进。 -- [接口](https://eips.ethereum.org/interface):围绕客户端应用程序接口/远程过程调用规范和标准以及某些语言级标准(如方法名称和合约应用程序二进制接口)的改进。 -- [以太坊意见征求](https://eips.ethereum.org/erc):应用程序级标准和约定 +- [网络](https://eips.ethereum.org/networking):关于 devp2p 和轻量级以太坊子协议的改进,以及对 Whisper 和 Swarm 网络协议规范的建议改进。 +- [接口](https://eips.ethereum.org/interface):关于客户端 API/RPC 规范和标准的改进,以及某些语言级别的标准,例如方法名称和合约 ABI。 +- [ERC](https://eips.ethereum.org/erc):应用级标准和惯例 -关于这些不同类型和类别的更多详细信息,请参见 [EIP-1](https://eips.ethereum.org/EIPS/eip-1#eip-types) +关于这些不同类型和类别的更多详细信息,请参阅 [EIP-1](https://eips.ethereum.org/EIPS/eip-1#eip-types) ### 代币标准 {#token-standards} -- [ERC-20](/developers/docs/standards/tokens/erc-20/) - 同质化(可互换)代币的标准接口,比如投票代币、质押代币或虚拟货币。 - - [ERC-223](/developers/docs/standards/tokens/erc-223/) - 一个同质化代币标准,使代币的行为与以太币行为相同,并支持在接收方处理代币转账。 - - [ERC-1363](/developers/docs/standards/tokens/erc-1363/) - 为 ERC-20 代币定义一个代币接口,支持在转账函数或 transferFrom 函数后执行接收者代码,或在批准后执行消费者代码。 -- [ERC-721](/developers/docs/standards/tokens/erc-721/) - 非同质化代币的标准接口,比如艺术作品或歌曲的契约。 - - [ERC-2309](https://eips.ethereum.org/EIPS/eip-2309) - 使用连续的代币标识符创建/转移一个或多个非同质化代币时,触发的标准事件。 +- [ERC-20](/developers/docs/standards/tokens/erc-20/) - 一种同质化(可互换)代币的标准接口,例如投票代币、质押代币或虚拟货币。 + - [ERC-223](/developers/docs/standards/tokens/erc-223/) - 一种同质化代币标准,使代币的行为与以太币相同,并支持在接收方处理代币转账。 + - [ERC-1363](/developers/docs/standards/tokens/erc-1363/) - ERC-20 代币的扩展接口,支持在单笔交易中对接收方合约执行回调。 +- [ERC-721](/developers/docs/standards/tokens/erc-721/) - 一种非同质化代币的标准接口,例如艺术品或歌曲的契约。 + - [ERC-2309](https://eips.ethereum.org/EIPS/eip-2309) - 在使用连续的代币标识符创建/转移一个或多个非同质化代币时发出的标准化事件。 - [ERC-4400](https://eips.ethereum.org/EIPS/eip-4400) - EIP-721 消费者角色的接口扩展。 - [ERC-4907](https://eips.ethereum.org/EIPS/eip-4907) - 为 ERC-721 代币添加一个具有受限权限的限时角色。 -- [ERC-777](/developers/docs/standards/tokens/erc-777/) - **(不推荐)**在 ERC-20 基础上改进的代币标准。 -- [ERC-1155](/developers/docs/standards/tokens/erc-1155/) - 可包含同质化和非同质化资产的代币标准。 -- [ERC-4626](/developers/docs/standards/tokens/erc-4626/) - 一个代币化的资金库标准,旨在优化和统一收益资金库的技术参数。 +- [ERC-777](/developers/docs/standards/tokens/erc-777/) - **(不推荐)** 一种在 ERC-20 基础上改进的代币标准。 +- [ERC-1155](/developers/docs/standards/tokens/erc-1155/) - 一种可同时包含同质化和非同质化资产的代币标准。 +- [ERC-4626](/developers/docs/standards/tokens/erc-4626/) - 一种代币化金库标准,旨在优化和统一生息金库的技术参数。 -了解更多关于[代币标准](/developers/docs/standards/tokens/)的信息。 +进一步了解[代币标准](/developers/docs/standards/tokens/)。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [以太坊改进提案 (EIP)](/eips/) -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ diff --git a/public/content/translations/zh/developers/docs/standards/tokens/erc-1155/index.md b/public/content/translations/zh/developers/docs/standards/tokens/erc-1155/index.md index fc96040abb1..bda93f2c180 100644 --- a/public/content/translations/zh/developers/docs/standards/tokens/erc-1155/index.md +++ b/public/content/translations/zh/developers/docs/standards/tokens/erc-1155/index.md @@ -1,35 +1,35 @@ --- -title: ERC-1155 多代币标准 -description: +title: "ERC-1155 多代币标准" +description: "了解 ERC-1155,这是一种多代币标准,可在单个合约中组合同质化代币和非同质化代币。" lang: zh --- -## 介绍 {#introduction} +## 简介 {#introduction} -用于多种代币管理的合约标准接口。 单个部署的合约可以包括同质化代币、非同质化代币或其他配置(如半同质化代币)的任何组合。 +用于多种代币管理的合约标准接口。 单个已部署的合约可以包含同质化代币、非同质化代币或其他配置(例如半同质化代币)的任何组合。 -**多代币标准是什么?** +**什么是多代币标准?** -它的目的很单纯,就是创建一个智能合约接口,可以代表和控制任何数量的同质化和非同质化代币类型。 这样一来,ERC-1155 代币就具有与 [ERC-20](/developers/docs/standards/tokens/erc-20/) 和 [ERC-721](/developers/docs/standards/tokens/erc-721/) 代币相同的功能,甚至可以同时使用这两者的功能。 它改进了 ERC-20 和 ERC-721 标准的功能,提升了效率并纠正了实现中的明显错误。 +它的目的很单纯,就是创建一个智能合约接口,可以代表和控制任何数量的同质化和非同质化代币类型。 通过这种方式,ERC-1155 代币可以执行与 [ERC-20](/developers/docs/standards/tokens/erc-20/) 和 [ERC-721](/developers/docs/standards/tokens/erc-721/) 代币相同的功能,甚至可以同时执行这两种功能。 它改进了 ERC-20 和 ERC-721 标准的功能,提升了效率并纠正了实现中的明显错误。 -[EIP-1155](https://eips.ethereum.org/EIPS/eip-1155) 中对 ERC-1155 代币进行了全面的描述。 +[EIP-1155](https://eips.ethereum.org/EIPS/eip-1155) 中对 ERC-1155 代币有全面说明。 ## 前提条件 {#prerequisites} -为了更好地理解这一页面的内容,我们建议你先阅读[代币标准](/developers/docs/standards/tokens/)、[ERC-20](/developers/docs/standards/tokens/erc-20/) 和 [ERC-721](/developers/docs/standards/tokens/erc-721/)。 +为了更好地理解本页面,我们建议您首先阅读有关[代币标准](/developers/docs/standards/tokens/)、[ERC-20](/developers/docs/standards/tokens/erc-20/) 和 [ERC-721](/developers/docs/standards/tokens/erc-721/) 的内容。 -## ERC-1155 的功能和特点: {#body} +## ERC-1155 的功能和特点:{#body} -- [批量传输](#batch_transfers):通过一次合约调用传输多种资产。 -- [批量余额](#batch_balance):在一次调用中获取多个资产的余额。 -- [批量审批](#batch_approval):审批同一地址的所有代币。 -- [Hook](#receive_hook):接收代币的钩子函数。 -- [支持非同质化代币](#nft_support):如果供应量仅为 1,将其作为非同质化代币处理。 -- [安全转账规则](#safe_transfer_rule):安全转账规则集。 +- [批量转账](#batch_transfers):在单次调用中转账多个资产。 +- [批量余额](#batch_balance):在单次调用中获取多个资产的余额。 +- [批量批准](#batch_approval):向一个地址批准所有代币。 +- [钩子](#receive_hook):接收代币的钩子。 +- [NFT 支持](#nft_support):如果供应量仅为 1,则将其视为 NFT。 +- [安全转账规则](#safe_transfer_rule):用于安全转账的一套规则。 -### 批量传输 {#batch-transfers} +### 批量转账 {#batch-transfers} -批量传输与常规 ERC-20 传输非常相似。 让我们看看常规 ERC-20 `transferFrom` 函数: +批量传输与常规 ERC-20 传输非常相似。 让我们看看常规的 ERC-20 `transferFrom` 函数: ```solidity // ERC-20 @@ -45,17 +45,17 @@ function safeBatchTransferFrom( ) external; ``` -ERC-1155 中唯一的区别是我们将值作为数组传递,同时也传递了 ids 数组。 例如,给出 `ids=[3, 6, 13]` 和 `values=[100, 200, 5]`,传输结果将是 +ERC-1155 中唯一的区别是我们将值作为数组传递,同时也传递了 ids 数组。 例如,给定 `ids=[3, 6, 13]` 和 `values=[100, 200, 5]`,产生的转账将是 -1. 将 id 3 的 100 个代币从 `_from` 传输到 `_to`。 -2. 将 id 6 的 200 个代币从 `_from` 传输到 `_to`。 -3. 将 id 13 的 5 个代币从 `_from` 转移到 `_to`。 +1. 将 100 个 ID 为 3 的代币从 `_from` 转账到 `_to`。 +2. 将 200 个 ID 为 6 的代币从 `_from` 转账到 `_to`。 +3. 将 5 个 ID 为 13 的代币从 `_from` 转账到 `_to`。 -在 ERC-1155 中,我们只有 `transferFrom`,没有 `transfer`。 要像常规的 `transfer`一样使用它,只需将 "from" 地址设为调用该函数的地址。 +在 ERC-1155 中,我们只有 `transferFrom`,没有 `transfer`。 要像常规 `transfer` 一样使用它,只需将 from 地址设置为调用该函数的地址。 ### 批量余额 {#batch-balance} -相应的 ERC-20 `balanceOf` 调用同样具有支持批处理的相应函数。 作为对比,这是 ERC-20 版本: +相应的 ERC-20 `balanceOf` 调用同样有其支持批量处理的伙伴函数。 作为对比,这是 ERC-20 版本: ```solidity // ERC-20 @@ -70,7 +70,7 @@ function balanceOfBatch( 调用余额查询更简单的是,我们可以在单次调用中获取多个余额。 参数中传递所有者帐户数组和代币的 id 数组。 -例如,对于给出的 `_ids=[3, 6, 13]` 和 `_owners=[0xbeef..., 0x1337..., 0x1111...]`,返回值将为: +例如,给定 `_ids=[3, 6, 13]` 和 `_owners=[0xbeef..., 0x1337..., 0x1111...]`,返回值将是 ```solidity [ @@ -80,7 +80,7 @@ function balanceOfBatch( ] ``` -### 批量审批 {#batch-approval} +### 批量批准 {#batch-approval} ```solidity // ERC-1155 @@ -95,9 +95,9 @@ function isApprovedForAll( ) external view returns (bool); ``` -审批过程与 ERC-20 略有不同。 这里不是批准特定金额,而是通过 `setApprovalForAll` 函数设置操作帐户为已批准或未批准。 +审批过程与 ERC-20 略有不同。 无需批准特定数额,你可以通过 `setApprovalForAll` 将一个操作员设置为“已批准”或“未批准”。 -查看当前的审批状态可以通过 `isApprovedForAll` 完成。 如你所见,要么全部批准,要么不批准。 不能定义要批准代币的数量,甚至代币类型。 +可通过 `isApprovedForAll` 读取当前状态。 如你所见,要么全部批准,要么不批准。 不能定义要批准代币的数量,甚至代币类型。 这是考虑到简洁性而故意设计的。 你只能批准一个地址的所有代币。 @@ -113,7 +113,7 @@ function onERC1155BatchReceived( ) external returns(bytes4); ``` -基于 [EIP-165](https://eips.ethereum.org/EIPS/eip-165) 的协议支持,ERC-1155 只支持智能合约的接收钩子函数。 钩子函数必须返回一个事先预定义的 4 字节值,这个值被指定为: +有了 [EIP-165](https://eips.ethereum.org/EIPS/eip-165) 支持,ERC-1155 仅支持智能合约的接收钩子。 钩子函数必须返回一个事先预定义的 4 字节值,这个值被指定为: ```solidity bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)")) @@ -121,26 +121,26 @@ bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],byt 当接收合约返回这一值时,意味着合约知道如何处理 ERC-1155 代币并接受转账。 太好了,代币不会再卡在合约中了! -### 支持非同质化代币 {#nft-support} +### NFT 支持 {#nft-support} -当供应量仅为 1 时,代币本质上就是一个非同质化的代币 (NFT)。 按照 ERC-721 的标准,你可以定义一个元数据网址。 客户端可以读取并修改网址,请参阅[这里](https://eips.ethereum.org/EIPS/eip-1155#metadata)。 +当供应量仅为 1 时,代币本质上就是一个非同质化的代币 (NFT)。 按照 ERC-721 的标准,你可以定义一个元数据网址。 客户端可以读取和修改该 URL,请参阅[此处](https://eips.ethereum.org/EIPS/eip-1155#metadata)。 ### 安全转账规则 {#safe-transfer-rule} 在前面的解释中,我们已经提到过一些安全转账规则。 现在我们来看一下最重要的规则: -1. 调用者必须获得批准才能从 `_from` 的帐户地址消费代币,或者调用者帐户地址必须与 `_from` 的帐户地址相同。 +1. 调用者必须被批准可为 `_from` 地址消费代币,或者调用者必须等于 `_from`。 2. 在以下情况下,转账调用将回退 - 1. `_to` 地址为 0; - 2. `_ids` 的长度与 `_values` 的长度不同; - 3. `_ids` 中代币持有者的任何余额低于发送给接收者的相应 `_value` 金额。 + 1. `_to` 地址是 0。 + 2. `_ids` 的长度与 `_values` 的长度不同。 + 3. `_ids` 中代币持有者的任何余额低于发送给接收者的 `_values` 中的相应数额。 4. 出现任何其他错误。 -_注意_:包括钩子在内的所有批处理函数也均作为非批处理的版本存在。 这样做是为了提高燃料效率,考虑到只转移一种资产可能仍然是最常用的方式。 简洁起见,我们没有在这里介绍这些非批处理的版本,包括安全转账规则。 名称是相同的,只需移除 'Batch'。 +_注意_:所有批量处理函数(包括钩子)也都存在非批量处理的版本。 这样做是为了提高燃料效率,考虑到只转移一种资产可能仍然是最常用的方式。 简洁起见,我们没有在这里介绍这些非批处理的版本,包括安全转账规则。 名称是相同的,只需移除 'Batch'。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [EIP-1155:多代币标准](https://eips.ethereum.org/EIPS/eip-1155) -- [ERC-1155:OpenZeppelin 文档](https://docs.openzeppelin.com/contracts/3.x/erc1155) -- [ERC-1155: GitHub Repo](https://github.com/enjin/erc-1155) -- [Alchemy NFT API](https://docs.alchemy.com/alchemy/enhanced-apis/nft-api) +- [ERC-1155:OpenZeppelin 文档](https://docs.openzeppelin.com/contracts/5.x/erc1155) +- [ERC-1155:GitHub 代码库](https://github.com/enjin/erc-1155) +- [Alchemy NFT API](https://www.alchemy.com/docs/reference/nft-api-quickstart) diff --git a/public/content/translations/zh/developers/docs/standards/tokens/erc-1363/index.md b/public/content/translations/zh/developers/docs/standards/tokens/erc-1363/index.md new file mode 100644 index 00000000000..6f38f88b08f --- /dev/null +++ b/public/content/translations/zh/developers/docs/standards/tokens/erc-1363/index.md @@ -0,0 +1,204 @@ +--- +title: "ERC-1363 可支付代币标准" +description: "ERC-1363 是 ERC-20 代币的一种扩展接口,支持在转账后于接收方合约上执行自定义逻辑,或在批准后于支出方合约上执行自定义逻辑,所有操作都在单笔交易中完成。" +lang: zh +--- + +## 简介 {#introduction} + +### 什么是 ERC-1363? {#what-is-erc1363} + +ERC-1363 是 ERC-20 代币的一种扩展接口,支持在转账后于接收方合约上执行自定义逻辑,或在批准后于支出方合约上执行自定义逻辑,所有操作都在单笔交易中完成。 + +### 与 ERC-20 的区别 {#erc20-differences} + +标准的 ERC-20 操作(如 `transfer`、`transferFrom` 和 `approve`)不允许在没有单独交易的情况下,在接收方或支出方合约上执行代码。 +这给 UI 开发带来了复杂性,也给应用推广带来了阻力,因为用户必须等待第一笔交易执行完毕,然后才能提交第二笔交易。 +他们还必须支付两次燃料费用。 + +ERC-1363 使同质化代币能够更轻松地执行操作,并且无需使用任何链下侦听器即可工作。 +它允许在单笔交易中,于转账或批准后,对接收方或支出方合约进行回调。 + +## 前提条件 {#prerequisites} + +为更好地理解本页面,我们建议你先阅读以下内容: + +- [代币标准](/developers/docs/standards/tokens/) +- [ERC-20](/developers/docs/standards/tokens/erc-20/) + +## 正文 {#body} + +ERC-1363 为 ERC-20 代币引入了一个标准应用程序接口 (API),用于在 `transfer`、`transferFrom` 或 `approve` 之后与智能合约交互。 + +该标准提供了转移代币的基本功能,并允许代币被批准,以便链上第三方可以使用它们,然后在接收方或支出方合约上进行回调。 + +有很多关于可接受 ERC-20 回调的智能合约的提议用例。 + +例如: + +- **众筹**:发送代币会触发即时奖励分配。 +- **服务**:付款一步即可激活服务访问权限。 +- **发票**:代币自动结算发票。 +- **订阅**:批准年费率会在支付第一个月费用时激活订阅。 + +因此,它最初被命名为\*\*“可支付代币”\*\*。 + +回调行为进一步扩展了其效用,实现了无缝交互,例如: + +- **质押**:转移的代币会触发在质押合约中自动锁定。 +- **投票**:收到的代币在治理系统中登记为投票。 +- **交换**:代币批准一步即可激活交换逻辑。 + +在所有需要在收到转账或批准后执行回调的情况下,ERC-1363 代币都可用于特定效用。 +通过验证接收方处理代币的能力,ERC-1363 还有助于避免智能合约中的代币丢失或代币锁定。 + +与其他 ERC-20 扩展提案不同,ERC-1363 不会覆盖 ERC-20 的 `transfer` 和 `transferFrom` 方法,而是定义了要实现的接口 ID,从而保持与 ERC-20 的向后兼容性。 + +来自 [EIP-1363](https://eips.ethereum.org/EIPS/eip-1363): + +### 方法 {#methods} + +实现 ERC-1363 标准的智能合约**必须**实现 `ERC1363` 接口以及 `ERC20` 和 `ERC165` 接口中的所有函数。 + +```solidity +pragma solidity ^0.8.0; + +/** + * @title ERC1363 + * @dev ERC-20 代币的扩展接口,支持在单笔交易中,于 `transfer` 或 `transferFrom` 后在接收方合约上执行代码,或于 `approve` 后在支出方合约上执行代码。 + */ +interface ERC1363 is ERC20, ERC165 { + /* + * 注意:此接口的 ERC-165 标识符是 0xb0202a11。 + * 0xb0202a11 === + * bytes4(keccak256('transferAndCall(address,uint256)')) ^ + * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ + * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ + * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ + * bytes4(keccak256('approveAndCall(address,uint256)')) ^ + * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) + */ + + /** + * @dev 从调用者的帐户向 `to` 转移 `value` 数量的代币,然后在 `to` 上调用 `ERC1363Receiver::onTransferReceived`。 + * @param to 代币转入的地址。 + * @param value 要转移的代币数量。 + * @return 一个布尔值,表示操作成功,除非抛出错误。 + */ + function transferAndCall(address to, uint256 value) external returns (bool); + + /** + * @dev 从调用者的帐户向 `to` 转移 `value` 数量的代币,然后在 `to` 上调用 `ERC1363Receiver::onTransferReceived`。 + * @param to 代币转入的地址。 + * @param value 要转移的代币数量。 + * @param data 额外数据,无特定格式,在对 `to` 的调用中发送。 + * @return 一个布尔值,表示操作成功,除非抛出错误。 + */ + function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); + + /** + * @dev 使用授权机制将 `value` 数量的代币从 `from` 转移到 `to`,然后在 `to` 上调用 `ERC1363Receiver::onTransferReceived`。 + * @param from 发送代币的地址。 + * @param to 代币转入的地址。 + * @param value 要转移的代币数量。 + * @return 一个布尔值,表示操作成功,除非抛出错误。 + */ + function transferFromAndCall(address from, address to, uint256 value) external returns (bool); + + /** + * @dev 使用授权机制将 `value` 数量的代币从 `from` 转移到 `to`,然后在 `to` 上调用 `ERC1363Receiver::onTransferReceived`。 + * @param from 发送代币的地址。 + * @param to 代币转入的地址。 + * @param value 要转移的代币数量。 + * @param data 额外数据,无特定格式,在对 `to` 的调用中发送。 + * @return 一个布尔值,表示操作成功,除非抛出错误。 + */ + function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); + + /** + * @dev 将调用者代币的 `value` 数量设置为 `spender` 的授权额度,然后在 `spender` 上调用 `ERC1363Spender::onApprovalReceived`。 + * @param spender 将使用资金的地址。 + * @param value 要使用的代币数量。 + * @return 一个布尔值,表示操作成功,除非抛出错误。 + */ + function approveAndCall(address spender, uint256 value) external returns (bool); + + /** + * @dev 将调用者代币的 `value` 数量设置为 `spender` 的授权额度,然后在 `spender` 上调用 `ERC1363Spender::onApprovalReceived`。 + * @param spender 将使用资金的地址。 + * @param value 要使用的代币数量。 + * @param data 额外数据,无特定格式,在对 `spender` 的调用中发送。 + * @return 一个布尔值,表示操作成功,除非抛出错误。 + */ + function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); +} + +interface ERC20 { + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); + function transfer(address to, uint256 value) external returns (bool); + function transferFrom(address from, address to, uint256 value) external returns (bool); + function approve(address spender, uint256 value) external returns (bool); + function totalSupply() external view returns (uint256); + function balanceOf(address account) external view returns (uint256); + function allowance(address owner, address spender) external view returns (uint256); +} + +interface ERC165 { + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} +``` + +想要通过 `transferAndCall` 或 `transferFromAndCall` 接受 ERC-1363 代币的智能合约**必须**实现 `ERC1363Receiver` 接口: + +```solidity +/** + * @title ERC1363Receiver + * @dev 任何想要支持 ERC-1363 代币合约的 `transferAndCall` 或 `transferFromAndCall` 的合约接口。 + */ +interface ERC1363Receiver { + /** + * @dev 每当 `operator` 从 `from` 通过 `ERC1363::transferAndCall` 或 `ERC1363::transferFromAndCall` 将 ERC-1363 代币转移到此合约时,都会调用此函数。 + * + * 注意:要接受转账,此函数必须返回 + * `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))` + * (即 0x88a7ca5c,或其自身的函数选择器)。 + * + * @param operator 调用 `transferAndCall` 或 `transferFromAndCall` 函数的地址。 + * @param from 代币转出的地址。 + * @param value 转移的代币数量。 + * @param data 额外数据,无特定格式。 + * @return 如果允许转账,则返回 `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))`,除非抛出错误。 + */ + function onTransferReceived(address operator, address from, uint256 value, bytes calldata data) external returns (bytes4); +} +``` + +想要通过 `approveAndCall` 接受 ERC-1363 代币的智能合约**必须**实现 `ERC1363Spender` 接口: + +```solidity +/** + * @title ERC1363Spender + * @dev 任何想要支持来自 ERC-1363 代币合约的 `approveAndCall` 的合约接口。 + */ +interface ERC1363Spender { + /** + * @dev 每当 ERC-1363 代币的 `owner` 通过 `ERC1363::approveAndCall` 批准此合约使用其代币时,都会调用此函数。 + * + * 注意:要接受批准,此函数必须返回 + * `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))` + * (即 0x7b04a2d0,或其自身的函数选择器)。 + * + * @param owner 调用 `approveAndCall` 函数且之前拥有代币的地址。 + * @param value 要使用的代币数量。 + * @param data 额外数据,无特定格式。 + * @return 如果允许批准,则返回 `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))`,除非抛出错误。 + */ + function onApprovalReceived(address owner, uint256 value, bytes calldata data) external returns (bytes4); +} +``` + +## 扩展阅读{#further-reading} + +- [ERC-1363:可支付代币标准](https://eips.ethereum.org/EIPS/eip-1363) +- [ERC-1363:GitHub 代码库](https://github.com/vittominacori/erc1363-payable-token) diff --git a/public/content/translations/zh/developers/docs/standards/tokens/erc-20/index.md b/public/content/translations/zh/developers/docs/standards/tokens/erc-20/index.md index f14e45fac76..a13148bd9b8 100644 --- a/public/content/translations/zh/developers/docs/standards/tokens/erc-20/index.md +++ b/public/content/translations/zh/developers/docs/standards/tokens/erc-20/index.md @@ -1,12 +1,12 @@ --- -title: ERC-20 代币标准 -description: +title: "ERC-20 代币标准" +description: "了解 ERC-20,这是以太坊上的同质化代币标准,可实现代币应用程序的互操作。" lang: zh --- -## 介绍 {#introduction} +## 简介 {#introduction} -**什么叫做代币?** +**什么是代币?** 代币可以在以太坊中表示任何东西: @@ -15,9 +15,10 @@ lang: zh - 金融资产类似于公司股份的资产 - 像美元一样的法定货币 - 一盎司黄金 -- 及更多... +- 以及更多... -以太坊的这种强大特点必须以强有力的标准来处理,对吗? 这正是 ERC-20 发挥其作用的地方! 此标准允许开发者构建可与其他产品和服务互相操作的代币应用程序。 ERC-20 标准还被用于为[以太币](/glossary/#ether)提供附加功能。 +以太坊的这种强大特点必须以强有力的标准来处理,对吗? 这正是 +ERC-20 发挥其作用的地方! 此标准允许开发者构建可与其他产品和服务互相操作的代币应用程序。 ERC-20 标准还可用于为[以太币](/glossary/#ether)提供附加功能。 **什么是 ERC-20?** @@ -67,11 +68,12 @@ event Approval(address indexed _owner, address indexed _spender, uint256 _value) ### 示例 {#web3py-example} -让我们看看如此重要的一个标准是如何使我们能够简单地检查以太坊上的任何 ERC-20 代币合约。 我们只需要合约的应用程序二进制接口 (ABI) 来创造一个 ERC-20 代币界面。 下面我们将使用一个简化的应用程序二进制接口,让例子变得更为简单。 +让我们看看如此重要的一个标准是如何使我们能够简单地检查以太坊上的任何 ERC-20 代币合约。 +我们只需要合约的应用程序二进制接口 (ABI) 来创造一个 ERC-20 代币界面。 下面我们将使用一个简化的应用程序二进制接口,让例子变得更为简单。 #### Web3.py 示例 {#web3py-example} -首先,请确保你已安装 [Web3.py](https://web3py.readthedocs.io/en/stable/quickstart.html#installation) Python 库: +首先,请确保您已安装 [Web3.py](https://web3py.readthedocs.io/en/stable/quickstart.html#installation) Python 程序库: ``` pip install web3 @@ -84,12 +86,12 @@ from web3 import Web3 w3 = Web3(Web3.HTTPProvider("https://cloudflare-eth.com")) dai_token_addr = "0x6B175474E89094C44Da98b954EedeAC495271d0F" # DAI -weth_token_addr = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" # Wrapped ether (WETH) +weth_token_addr = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" # 包装的以太币 (WETH) acc_address = "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11" # Uniswap V2: DAI 2 -# This is a simplified Contract Application Binary Interface (ABI) of an ERC-20 Token Contract. -# It will expose only the methods: balanceOf(address), decimals(), symbol() and totalSupply() +# 这是 ERC-20 代币合约的简化版合约应用程序二进制接口 (ABI)。 +# 它只会公开以下方法:balanceOf(address)、decimals()、symbol() 和 totalSupply() simplified_abi = [ { 'inputs': [{'internalType': 'address', 'name': 'account', 'type': 'address'}], @@ -144,30 +146,42 @@ print("Addr Balance:", addr_balance) ### ERC-20 代币接收问题 {#reception-issue} +**截至 2024 年 6 月 20 日,因该问题损失的 ERC-20 代币价值至少达 83,656,418 美元。** **请注意,纯粹的 ERC-20 实现很容易出现此问题,除非您在标准之上实施下面列出的一组额外限制。** + 当 ERC-20 代币被发送到并非为处理 ERC-20 代币而设计的智能合约时,这些代币可能会永久丢失。 出现这种情况的原因是,接收合约无法识别或回应所传入的代币,而且 ERC-20 标准中也没有通知接受合约所传入代币的机制。 导致这一问题的主要原因包括: -1. 代币转移机制 - - ERC-20 代币使用 transfer 或 transferFrom 函数进行转移 - - 当用户使用这些函数将代币发送到合约地址时,无论接收合约是否是为处理它们而设计,代币都会被转移 -2. 缺乏通知 - - 接收合约不会收到已向其发送代币的通知或回调 - - 如果接收合约缺乏处理代币的机制(例如,回退函数或专门用于处理代币接收的函数),则代币实际上会卡在合约的地址中 -3. 无内置处理 - - ERC-20 标准不包含用于接收待实现合约的强制函数,导致许多合约无法正确管理传入的代币 +1. 代币转移机制 + +- ERC-20 代币使用 transfer 或 transferFrom 函数进行转移 + - 当用户使用这些函数将代币发送到合约地址时,无论接收合约是否是为处理它们而设计,代币都会被转移 + +2. 缺乏通知 + - 接收合约不会收到已向其发送代币的通知或回调 + - 如果接收合约缺乏处理代币的机制(例如,回退函数或专门用于处理代币接收的函数),则代币实际上会卡在合约的地址中 +3. 无内置处理 + - ERC-20 标准不包含用于接收待实现合约的强制函数,导致许多合约无法正确管理传入的代币 + +**潜在解决方案** -为了解决这些问题,出现了 [ERC-223](/developers/docs/standards/tokens/erc-223) [ERC-1363](/developers/docs/standards/tokens/erc-1363) 等替代标准。 +虽然无法通过 ERC-20 完全避免此问题,但有一些方法可以显著降低最终用户遭遇代币损失的可能性: -## 延伸阅读 {#further-reading} +- 最常见的问题是当用户将代币发送到代币合约地址本身时(例如,将 USDT 存入 USDT 代币合约的地址)。 建议限制 `transfer(..)` 函数,以撤销此类转账尝试。 考虑在 `transfer(..)` 函数的实现中添加 `require(_to != address(this));` 检查。 +- 通常,`transfer(..)` 函数并非为向合约存入代币而设计。 `approve(..) 和 `transferFrom(..)`模式是向合约存入 ERC-20 代币的替代方法。 可以通过限制 transfer 函数以禁止用其向任何合约存入代币,但这可能会破坏与那些假设可以用`trasnfer(..)` 函数向合约存入代币的合约的兼容性(例如,Uniswap 流动性池)。 +- 必须预设ERC-20代币可能会意外地转入您的合约,即便该合约理应不接收任何的代币​。 接收的人没有办法阻止或拒绝意外的存款。 建议实现一个功能,允许提取出那些被意外转入的ERC-20代币。 +- 考虑使用替代的代币标准。 + +为解决此问题,出现了一些替代标准,例如 [ERC-223](/developers/docs/standards/tokens/erc-223) 或 [ERC-1363](/developers/docs/standards/tokens/erc-1363)。 + +## 扩展阅读{#further-reading} - [EIP-20:ERC-20 代币标准](https://eips.ethereum.org/EIPS/eip-20) - [OpenZeppelin - 代币](https://docs.openzeppelin.com/contracts/3.x/tokens#ERC20) -- [OpenZeppelin - ERC-20 实施](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol) +- [OpenZeppelin - ERC-20 实现](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol) - [Alchemy - Solidity ERC20 代币指南](https://www.alchemy.com/overviews/erc20-solidity) - ## 其他同质化代币标准 {#fungible-token-standards} - [ERC-223](/developers/docs/standards/tokens/erc-223) - [ERC-1363](/developers/docs/standards/tokens/erc-1363) - [ERC-777](/developers/docs/standards/tokens/erc-777) -- [ERC-4626 - 代币化资金库](/developers/docs/standards/tokens/erc-4626) \ No newline at end of file +- [ERC-4626 - 代币化金库](/developers/docs/standards/tokens/erc-4626) diff --git a/public/content/translations/zh/developers/docs/standards/tokens/erc-223/index.md b/public/content/translations/zh/developers/docs/standards/tokens/erc-223/index.md index aecb499aa5d..03173ac2fc2 100644 --- a/public/content/translations/zh/developers/docs/standards/tokens/erc-223/index.md +++ b/public/content/translations/zh/developers/docs/standards/tokens/erc-223/index.md @@ -1,6 +1,6 @@ --- -title: ERC-223 代币标准 -description: 关于 ERC-223 同质化代币标准的概述、它的运作方式以及与 ERC-20 的对比。 +title: "ERC-223 代币标准" +description: "关于 ERC-223 同质化代币标准的概述、它的运作方式以及与 ERC-20 的对比。" lang: zh --- diff --git a/public/content/translations/zh/developers/docs/standards/tokens/erc-4626/index.md b/public/content/translations/zh/developers/docs/standards/tokens/erc-4626/index.md index 74e8ab03ea0..b602f8427dd 100644 --- a/public/content/translations/zh/developers/docs/standards/tokens/erc-4626/index.md +++ b/public/content/translations/zh/developers/docs/standards/tokens/erc-4626/index.md @@ -1,10 +1,10 @@ --- -title: ERC-4626 代币化资金库标准 -description: 收益资金库的标准 +title: "ERC-4626 代币化资金库标准" +description: "收益资金库的标准" lang: zh --- -## 介绍 {#introduction} +## 简介 {#introduction} ERC-4626 是优化和统一收益资金库技术参数的标准。 它为表示单个底层 ERC-20 代币的份额的代币化收益资金库提供标准应用程序接口。 ERC-4626 还概述了使用 ERC-20 的代币化资金库的可选扩展,提供存款、提取代币和读取余额的基本功能。 @@ -14,15 +14,15 @@ ERC-4626 是优化和统一收益资金库技术参数的标准。 它为表示 收益资金库的 ERC-4626 标准通过创建更加一致和健壮的实现模式,无需开发者提供专门的工作,就能减少集成工作量并解锁在各种应用程序中获取收益的途径。 -[EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) 中对 ERC-4626 代币进行了全面的描述。 +ERC-4626 代币在 [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) 中有完整描述。 **异步资金库扩展 (ERC-7540)** -ERC-4626 针对原子存款和赎回上限进行了优化。 如果达到上限,则无法提交新的存款或赎回。 该上限不适用于任何以异步操作或延迟作为与资金库交互的先决条件的智能合约(例如现实世界资产协议、非足额抵押贷款协议、跨链贷款协议、流动性质押代币或保险安全模块)。 +ERC-4626 针对原子存款和赎回上限进行了优化。 如果达到上限,则无法提交新的存款或赎回。 此限制不适用于任何将异步操作或延迟作为与资金库交互先决条件的智能合约系统(例如,真实世界资产协议、非足额抵押借贷协议、跨链借贷协议、流动性质押代币或保险安全模块)。 -ERC-7540 拓展了 ERC-4626 资金库在异步用例中的实用性。 充分利用现有的资金库接口 (`deposit`/`withdraw`/`mint`/`redeem`) 来声明异步请求。 +ERC-7540 拓展了 ERC-4626 资金库在异步用例中的实用性。 充分利用现有的资金库接口(`deposit`/`withdraw`/`mint`/`redeem`)来声明异步请求。 -[ERC-7540](https://eips.ethereum.org/EIPS/eip-7540) 中完整描述了 ERC-7540 扩展。 +ERC-7540 扩展在 [ERC-7540](https://eips.ethereum.org/EIPS/eip-7540) 中有完整描述。 **多资产资金库扩展 (ERC-7575)** @@ -30,13 +30,13 @@ ERC-4626 不支持的一个缺失用例是具有多种资产或入口点的资 ERC-7575 通过从 ERC-4626 实现外部化 ERC-20 代币实现,增加了对多资产资金库的支持。 -[ERC-7575](https://eips.ethereum.org/EIPS/eip-7575) 中完整描述了 ERC-7575 扩展。 +ERC-7575 扩展在 [ERC-7575](https://eips.ethereum.org/EIPS/eip-7575) 中有完整描述。 ## 前提条件 {#prerequisites} -为了更好地理解这个页面,我们建议你首先阅读[代币标准](/developers/docs/standards/tokens/)和 [ERC-20](/developers/docs/standards/tokens/erc-20/)。 +为了更好地理解本页内容,我们建议您先阅读有关[代币标准](/developers/docs/standards/tokens/)和 [ERC-20](/developers/docs/standards/tokens/erc-20/) 的内容。 -## ERC-4626 的函数和功能: {#body} +## ERC-4626 函数和功能:{#body} ### 方法 {#methods} @@ -78,7 +78,7 @@ function convertToAssets(uint256 shares) public view returns (uint256 assets) function maxDeposit(address receiver) public view returns (uint256 maxAssets) ``` -此函数返回 `receiver` 的一次 [`deposit`](#deposit) 调用中可以存入的最大标的资产数量。 +此函数返回在单次 [`deposit`](#deposit) 调用中可存入的最大底层资产数量,这些份额将为 `receiver` 铸造。 #### previewDeposit {#previewdeposit} @@ -94,7 +94,7 @@ function previewDeposit(uint256 assets) public view returns (uint256 shares) function deposit(uint256 assets, address receiver) public returns (uint256 shares) ``` -此函数将标的代币的 `assets` 存入资金库,并将 `shares` 的所有权授予 `receiver`。 +此函数将底层代币的 `assets` 存入资金库,并将 `shares` 的所有权授予 `receiver`。 #### maxMint {#maxmint} @@ -102,7 +102,7 @@ function deposit(uint256 assets, address receiver) public returns (uint256 share function maxMint(address receiver) public view returns (uint256 maxShares) ``` -此函数返回 `receiver` 在单次 [`mint`](#mint) 调用中可以铸造的最大份额。 +此函数返回在单次 [`mint`](#mint) 调用中可铸造的最大份额数量,这些份额将为 `receiver` 铸造。 #### previewMint {#previewmint} @@ -118,7 +118,7 @@ function maxMint(address receiver) public view returns (uint256 maxShares) function mint(uint256 shares, address receiver) public returns (uint256 assets) ``` -此函数通过存入标的代币的 `assets`,将 `shares` 资金库份额准确铸造到 `receiver`。 +此函数通过存入底层代币的 `assets`,将 `shares` 数量的资金库份额精确地铸造给 `receiver`。 #### maxWithdraw {#maxwithdraw} @@ -126,7 +126,7 @@ function mint(uint256 shares, address receiver) public returns (uint256 assets) function maxWithdraw(address owner) public view returns (uint256 maxAssets) ``` -此函数返回可以通过单次 [`withdraw`](#withdraw) 调用从 `owner` 余额中提取的最大标的资产数量。 +此函数返回通过单次 [`withdraw`](#withdraw) 调用可从 `owner` 余额中提取的最大底层资产数量。 #### previewWithdraw {#previewwithdraw} @@ -142,7 +142,7 @@ function previewWithdraw(uint256 assets) public view returns (uint256 shares) function withdraw(uint256 assets, address receiver, address owner) public returns (uint256 shares) ``` -此函数从 `owner` 烧录 `shares`,并将 `assets` 代币从资金库准确发送到 `receiver`。 +此函数从 `owner` 处销毁 `shares`,并从资金库向 `receiver` 准确发送 `assets` 数量的代币。 #### maxRedeem {#maxredeem} @@ -150,7 +150,7 @@ function withdraw(uint256 assets, address receiver, address owner) public return function maxRedeem(address owner) public view returns (uint256 maxShares) ``` -此函数返回可以通过 [`redeem`](#redeem) 调用从 `owner` 余额中赎回的最大份额。 +此函数返回通过 [`redeem`](#redeem) 调用可从 `owner` 余额中赎回的最大份额数量。 #### previewRedeem {#previewredeem} @@ -166,7 +166,7 @@ function previewRedeem(uint256 shares) public view returns (uint256 assets) function redeem(uint256 shares, address receiver, address owner) public returns (uint256 assets) ``` -此函数从 `owner` 赎回特定数量的 `shares` 并将底层代币的 `assets` 从资金库发送到 `receiver`。 +此函数从 `owner` 赎回特定数量的 `shares`,并将底层代币的 `assets` 从资金库发送到 `receiver`。 #### totalSupply {#totalsupply} @@ -192,7 +192,7 @@ function balanceOf(address owner) public view returns (uint256) #### Deposit 事件 -**必须**在通过 [`mint`](#mint) 和 [`deposit`](#deposit) 方法将代币存入资金库之前发出。 +**必须**在通过 [`mint`](#mint) 和 [`deposit`](#deposit) 方法将代币存入资金库时发出。 ```solidity event Deposit( @@ -207,7 +207,7 @@ event Deposit( #### 提款事件 -**必须**在存款人用 [`redeem`](#redeem) 或 [`withdraw`](#withdraw) 方法从资金库中取出份额时发出。 +**必须**在存款人使用 [`redeem`](#redeem) 或 [`withdraw`](#withdraw) 方法从资金库提取份额时发出。 ```solidity event Withdraw( @@ -221,7 +221,7 @@ event Withdraw( 其中 `sender` 是触发取款并将 `owner` 拥有的 `shares` 兑换为 `assets` 的用户。 `receiver` 是收到提取的 `assets` 的用户。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [EIP-4626:代币化资金库标准](https://eips.ethereum.org/EIPS/eip-4626) -- [ERC-4626: GitHub Repo](https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC4626.sol) +- [ERC-4626:GitHub 代码库](https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC4626.sol) diff --git a/public/content/translations/zh/developers/docs/standards/tokens/erc-721/index.md b/public/content/translations/zh/developers/docs/standards/tokens/erc-721/index.md index ca55529622b..707b2695f9b 100644 --- a/public/content/translations/zh/developers/docs/standards/tokens/erc-721/index.md +++ b/public/content/translations/zh/developers/docs/standards/tokens/erc-721/index.md @@ -1,20 +1,24 @@ --- -title: ERC-721 非同质化代币标准 -description: +title: "ERC-721 非同质化代币标准" +description: "了解 ERC-721,非同质化代币 (NTF) 的标准,用于表示以太坊上的独特数字资产。" lang: zh --- -## 介绍 {#introduction} +## 简介 {#introduction} **什么是非同质化代币?** -非同质化代币(NFT)用于以唯一的方式标识某人或者某物。 此类型的代币可以被完美地用于出售下列物品的平台:收藏品、密钥、彩票、音乐会座位编号、体育比赛等。 这种类型的代币有着惊人的潜力,因此它需要一个适当的标准。ERC-721 就是为解决这个问题而来! +非同质化代币(NFT)用于以唯一的方式标识某人或者某物。 此类型的代币可以被完美地用于出售下列物品的平台:收藏品、密钥、彩票、音乐会座位编号、体育比赛等。 这种类型的代币有着惊人的潜力,因此它需要一个适当的标准。ERC-721 +就是为解决这个问题而来! **ERC-721 是什么?** -ERC-721 为 NFT 引入了一个标准,换言之,这种类型的代币是独一无二的,并且可能与来自同一智能合约的另一代币有不同的价值,也许是因为它的年份、稀有性、甚至是它的观感。 稍等,看起来怎么样呢? +ERC-721 为 NFT 引入了一个标准,换言之,这种类型的代币是独一无二的,并且可能与来自同一智能合约的另一代币有不同的价值,也许是因为它的年份、稀有性、甚至是它的观感。 +稍等,看起来怎么样呢? -是的。 所有 NFTs 都有一个 `uint256` 变量,名为 `tokenId`,所以对于任何 ERC-721 合约,这对值` contract address, tokenId ` 必须是全局唯一的。 也就是说,去中心化应用程序可以有一个“转换器”, 使用 `tokenId` 作为输入并输出一些很酷的事物图像,例如僵尸、武器、技能或神奇的小猫咪! +可以! 所有 NFT 都有一个名为 `tokenId` 的 `uint256` 变量,因此对于任何 ERC-721 合约,该配对 +`contract address, uint256 tokenId` 必须是全局唯一的。 也就是说,一个去中心化应用程序可以有一个“转换器”,它 +使用 `tokenId` 作为输入并输出一些很酷的东西的图像,比如僵尸、武器、技能或超棒的猫咪! ## 前提条件 {#prerequisites} @@ -26,11 +30,12 @@ ERC-721 为 NFT 引入了一个标准,换言之,这种类型的代币是独 ERC-721(Ethereum Request for Comments 721),由 William Entriken、Dieter Shirley、Jacob Evans、Nastassia Sachs 在 2018 年 1 月提出,是一个在智能合约中实现代币 API 的非同质化代币标准。 -它提供了一些功能,例如将代币从一个帐户转移到另一个帐户,获取帐户的当前代币余额,获取代币的所有者,以及整个网络的可用代币总供应量。 除此之外,它还具有其他功能,例如批准帐户中一定数量的代币可以被第三方帐户转移。 +它提供了一些功能,例如将代币从一个帐户转移到另一个帐户,获取帐户的当前代币余额,获取代币的所有者,以及整个网络的可用代币总供应量。 +除此之外,它还具有其他功能,例如批准帐户中一定数量的代币可以被第三方帐户转移。 如果一个智能合约实现了下列方法和事件,它就可以被称为 ERC-721 非同质化代币合约。 一旦被部署,它将负责跟踪在以太坊上创建的代币。 -来自[ EIP-721 ](https://eips.ethereum.org/EIPS/eip-721): +来自 [EIP-721](https://eips.ethereum.org/EIPS/eip-721): ### 方法 {#methods} @@ -56,11 +61,12 @@ ERC-721(Ethereum Request for Comments 721),由 William Entriken、Dieter S ### 示例 {#web3py-example} -让我们看看一个标准是多么重要,它使我们能够简单地在以太坊上检查任何 ERC-721 代币合约。 我们只需要合约的应用程序二进制接口(ABI)就可以创造任何 ERC-721 代币的接口。 下面我们将使用一个简化的应用程序二进制接口,让例子变得更为简单。 +让我们看看一个标准是多么重要,它使我们能够简单地在以太坊上检查任何 ERC-721 代币合约。 +我们只需要合约的应用程序二进制接口(ABI)就可以创造任何 ERC-721 代币的接口。 下面我们将使用一个简化的应用程序二进制接口,让例子变得更为简单。 #### Web3.py 示例 {#web3py-example} -首先,请确保你已安装 [Web3.py](https://web3py.readthedocs.io/en/stable/quickstart.html#installation) Python 库: +首先,请确保您已安装 [Web3.py](https://web3py.readthedocs.io/en/stable/quickstart.html#installation) Python 程序库: ``` pip install web3 @@ -73,12 +79,12 @@ from web3._utils.events import get_event_data w3 = Web3(Web3.HTTPProvider("https://cloudflare-eth.com")) -ck_token_addr = "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d" # CryptoKitties Contract +ck_token_addr = "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d" # CryptoKitties 合约 -acc_address = "0xb1690C08E213a35Ed9bAb7B318DE14420FB57d8C" # CryptoKitties Sales Auction +acc_address = "0xb1690C08E213a35Ed9bAb7B318DE14420FB57d8C" # CryptoKitties 销售拍卖 -# This is a simplified Contract Application Binary Interface (ABI) of an ERC-721 NFT Contract. -# It will expose only the methods: balanceOf(address), name(), ownerOf(tokenId), symbol(), totalSupply() +# 这是一个 ERC-721 NFT 合约的简化版合约应用程序二进制接口 (ABI)。 +# 它只会公开以下方法:balanceOf(address)、name()、ownerOf(tokenId)、symbol()、totalSupply() simplified_abi = [ { 'inputs': [{'internalType': 'address', 'name': 'owner', 'type': 'address'}], @@ -131,12 +137,12 @@ ck_contract = w3.eth.contract(address=w3.to_checksum_address(ck_token_addr), abi name = ck_contract.functions.name().call() symbol = ck_contract.functions.symbol().call() kitties_auctions = ck_contract.functions.balanceOf(acc_address).call() -print(f"{name} [{symbol}] NFTs in Auctions: {kitties_auctions}") +print(f"{name} [{symbol}] 在拍卖中的 NFT:{kitties_auctions}") pregnant_kitties = ck_contract.functions.pregnantKitties().call() -print(f"{name} [{symbol}] NFTs Pregnants: {pregnant_kitties}") +print(f"{name} [{symbol}] 怀孕的 NFT:{pregnant_kitties}") -# Using the Transfer Event ABI to get info about transferred Kitties. +# 使用 Transfer 事件 ABI 获取已转移的 Kitties 的信息。 tx_event_abi = { 'anonymous': False, 'inputs': [ @@ -147,7 +153,7 @@ tx_event_abi = { 'type': 'event' } -# We need the event's signature to filter the logs +# 我们需要事件签名来筛选日志 event_signature = w3.keccak(text="Transfer(address,address,uint256)").hex() logs = w3.eth.get_logs({ @@ -156,25 +162,25 @@ logs = w3.eth.get_logs({ "topics": [event_signature] }) -# Notes: -# - Increase the number of blocks up from 120 if no Transfer event is returned. -# - If you didn't find any Transfer event you can also try to get a tokenId at: +# 注意: +# - 如果没有返回 Transfer 事件,请将区块数从 120 调高。 +# - 如果没有找到任何 Transfer 事件,你也可以尝试在此处获取一个 tokenId: # https://etherscan.io/address/0x06012c8cf97BEaD5deAe237070F9587f8E7A266d#events -# Click to expand the event's logs and copy its "tokenId" argument +# 点击展开事件日志并复制其 "tokenId" 参数 recent_tx = [get_event_data(w3.codec, tx_event_abi, log)["args"] for log in logs] if recent_tx: - kitty_id = recent_tx[0]['tokenId'] # Paste the "tokenId" here from the link above + kitty_id = recent_tx[0]['tokenId'] # 从上面的链接在此处粘贴 "tokenId" is_pregnant = ck_contract.functions.isPregnant(kitty_id).call() - print(f"{name} [{symbol}] NFTs {kitty_id} is pregnant: {is_pregnant}") + print(f"{name} [{symbol}] NFT {kitty_id} 是否怀孕:{is_pregnant}") ``` 除了标准事件之外,CryptoKitties 合约还有其它一些有趣的事件。 -让我们看看其中的两个,`Pregnant` 和 `Birth`。 +我们来看看其中的两个:`Pregnant` 和 `Birth`。 ```python -# Using the Pregnant and Birth Events ABI to get info about new Kitties. +# 使用 Pregnant 和 Birth 事件 ABI 获取关于新 Kitties 的信息。 ck_extra_events_abi = [ { 'anonymous': False, @@ -198,13 +204,13 @@ ck_extra_events_abi = [ 'type': 'event' }] -# We need the event's signature to filter the logs +# 我们需要事件签名来筛选日志 ck_event_signatures = [ w3.keccak(text="Pregnant(address,uint256,uint256,uint256)").hex(), w3.keccak(text="Birth(address,uint256,uint256,uint256,uint256)").hex(), ] -# Here is a Pregnant Event: +# 这是一个 Pregnant 事件: # - https://etherscan.io/tx/0xc97eb514a41004acc447ac9d0d6a27ea6da305ac8b877dff37e49db42e1f8cef#eventlog pregnant_logs = w3.eth.get_logs({ "fromBlock": w3.eth.block_number - 120, @@ -214,7 +220,7 @@ pregnant_logs = w3.eth.get_logs({ recent_pregnants = [get_event_data(w3.codec, ck_extra_events_abi[0], log)["args"] for log in pregnant_logs] -# Here is a Birth Event: +# 这是一个 Birth 事件: # - https://etherscan.io/tx/0x3978028e08a25bb4c44f7877eb3573b9644309c044bf087e335397f16356340a birth_logs = w3.eth.get_logs({ "fromBlock": w3.eth.block_number - 120, @@ -225,20 +231,26 @@ birth_logs = w3.eth.get_logs({ recent_births = [get_event_data(w3.codec, ck_extra_events_abi[1], log)["args"] for log in birth_logs] ``` -## 热门的 NFT {#popular-nfts} - -- [Etherscan NFT Tracker](https://etherscan.io/tokens-nft) 列出了以太坊上交易量最大的 NFT。 -- [CryptoKitties](https://www.cryptokitties.co/) 是一个围绕着我们称之为加密猫的可繁殖、可收藏和可爱的生物游戏。 -- [Sorare](https://sorare.com/) 是一场全球迷幻足球赛,你可以在这里收集有限版本的收藏品,管理你的球队,参加比赛以获得奖品。 -- [以太坊域名服务 (ENS)](https://ens.domains/) 提供了一种安全和去中心化的方式,用人类可读的名字来处理链上和链下的资源。 -- [POAP](https://poap.xyz) 向参加事件或完成特定行动的人免费提供非同质化代币。 POAP 的创建和分发是免费的。 -- [Unstoppable Domains](https://unstoppabledomains.com/) 总部设在旧金山,是一家在区块链上创建域的公司。 区块链域将加密货币地址替换为人类可读的名称,并且可用于支持抗审查的网站。 -- [Gods Unchained Cards](https://godsunchained.com/) 是以太坊区块链上的一款集换式卡牌游戏,它使用非同质化代币来为游戏中的资产提供真实所有权。 -- [无聊猿游艇俱乐部](https://boredapeyachtclub.com)是一件由 10,000 个独一无二的非同质化代币构成的收藏品,也是一件非常罕见的艺术品,它作为俱乐部会员资格代币,可为成员提供多种特权和福利,而且在社区的努力下,这些特权和福利还会随着时间的推移不断增加。 - -## 延伸阅读 {#further-reading} +## 热门 NFT {#popular-nfts} + +- [Etherscan NFT Tracker](https://etherscan.io/nft-top-contracts) 按转账量列出了以太坊上的顶尖 NFT。 +- [CryptoKitties](https://www.cryptokitties.co/) 是一款游戏,围绕着我们称之为“加密猫”的、可繁殖、可收藏且非常可爱的 + 生物。 +- [Sorare](https://sorare.com/) 是一款全球性的梦幻足球游戏,你可以在其中收集限量版收藏品、 + 管理你的球队并参加比赛以赢取奖品。 +- [以太坊域名服务 (ENS)](https://ens.domains/) 提供了一种安全和去中心化的方式,可以使用简单的、人类可读的名称来定位 + 链上和链下的资源。 +- [POAP](https://poap.xyz) 向参加活动或完成特定操作的人免费发放 NFT。 POAP 的创建和分发是免费的。 +- [Unstoppable Domains](https://unstoppabledomains.com/) 是一家总部位于旧金山的公司,在 + 区块链上构建域名。 区块链域名将加密货币地址替换为人类可读的名称,并可用于启用 + 抗审查网站。 +- [Gods Unchained Cards](https://godsunchained.com/) 是以太坊区块链上的一款集换式卡牌游戏 (TCG),它使用 NFT 为 + 游戏内资产带来真正的所有权。 +- [Bored Ape Yacht Club](https://boredapeyachtclub.com) 是一个由 10,000 个独特 NFT 组成的收藏系列。它既是可证明其稀有性的艺术品,也充当俱乐部的会员代币,可为成员提供多种特权和福利,而且在社区的努力下,这些特权和福利还会随着时间的推移不断增加。 + +## 扩展阅读{#further-reading} - [EIP-721:ERC-721 非同质化代币标准](https://eips.ethereum.org/EIPS/eip-721) - [OpenZeppelin - ERC-721 文档](https://docs.openzeppelin.com/contracts/3.x/erc721) -- [OpenZeppelin - ERC-721 实施](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol) -- [Alchemy NFT API](https://docs.alchemy.com/alchemy/enhanced-apis/nft-api) +- [OpenZeppelin - ERC-721 实现](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol) +- [Alchemy NFT API](https://www.alchemy.com/docs/reference/nft-api-quickstart) diff --git a/public/content/translations/zh/developers/docs/standards/tokens/erc-777/index.md b/public/content/translations/zh/developers/docs/standards/tokens/erc-777/index.md index 43cbdd65ffb..08e77103e63 100644 --- a/public/content/translations/zh/developers/docs/standards/tokens/erc-777/index.md +++ b/public/content/translations/zh/developers/docs/standards/tokens/erc-777/index.md @@ -1,6 +1,6 @@ --- -title: ERC-777 代币标准 -description: null +title: "ERC-777 代币标准" +description: "了解 ERC-777,带有钩子的改进的同质化代币标准,不过仍然推荐使用 ERC-20 以确保安全。" lang: zh --- diff --git a/public/content/translations/zh/developers/docs/standards/tokens/index.md b/public/content/translations/zh/developers/docs/standards/tokens/index.md index c32d6d5dc48..d009c2b09d3 100644 --- a/public/content/translations/zh/developers/docs/standards/tokens/index.md +++ b/public/content/translations/zh/developers/docs/standards/tokens/index.md @@ -1,13 +1,15 @@ --- -title: 代币标准 -description: +title: "代币标准" +description: "探索同质化和非同质化代币的以太坊代币标准,包括 ERC-20、ERC-721 和 ERC-1155。" lang: zh incomplete: true --- -## 介绍 {#introduction} +## 简介 {#introduction} -许多以太坊开发标准都集中在代币接口上。 这些标准有助于确保智能合约仍然可以被撰写,例如,当新项目签发代币时,它与现有分散化的交易是兼容的。 +许多以太坊开发标准都集中在代币接口上。 这些标准有助于确保智能合约保持可组合性,因此,当一个新项目发行代币时,该代币能与现有的去中心化交易所和应用程序兼容。 + +代币标准定义了代币在以太坊生态系统中的行为和交互方式。 它们让开发者可以更轻松地进行构建,而无需重复造轮子,从而确保代币能与钱包、交易所和 DeFi 平台无缝协作。 无论是在游戏、治理还是其他用例中,这些标准都提供了一致性,使以太坊的互联程度更高。 ## 前提条件 {#prerequisites} @@ -18,22 +20,22 @@ incomplete: true 以下是以太坊上最受欢迎的一些代币标准: -- [ERC-20](/developers/docs/standards/tokens/erc-20/) - 同质化(可互换)代币的标准接口,比如投票代币、质押代币或虚拟货币。 +- [ERC-20](/developers/docs/standards/tokens/erc-20/) - 一种同质化(可互换)代币的标准接口,例如投票代币、质押代币或虚拟货币。 -### 非同质化代币标准 {#nft-standards} +### NFT 标准 {#nft-standards} -- [ERC-721](/developers/docs/standards/tokens/erc-721/) - 非同质化代币的标准接口,比如艺术作品或歌曲的契约。 -- [ERC-1155](/developers/docs/standards/tokens/erc-1155/) - ERC-1155 允许更有效的交易和交易捆绑,从而节省燃料成本。 此代币标准允许创建实用代币(例如 $BNB 或 $BAT)和加密朋克之类的非同质化代币。 +- [ERC-721](/developers/docs/standards/tokens/erc-721/) - 一种非同质化代币的标准接口,例如艺术品或歌曲的契约。 +- [ERC-1155](/developers/docs/standards/tokens/erc-1155/) - ERC-1155 允许更高效的交易和交易捆绑,从而节省成本。 此代币标准允许创建实用代币(例如 $BNB 或 $BAT)和加密朋克之类的非同质化代币。 -完整的[以太坊意见征求](https://eips.ethereum.org/erc)提案列表。 +[ERC](https://eips.ethereum.org/erc) 提案的完整列表。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ ## 相关教程 {#related-tutorials} -- [代币集成清单](/developers/tutorials/token-integration-checklist/) _- 与代币互动时要考虑的事项清单。_ -- [了解 ERC20 代币智能合约](/developers/tutorials/understand-the-erc-20-token-smart-contract/) _— — 介绍如何在以太坊测试网络上部署你的第一个智能合约。_ -- [通过 Solidity 智能合约转账和批准 ERC20 代币](/developers/tutorials/transfers-and-approval-of-erc-20-tokens-from-a-solidity-smart-contract/)_ - 如何使用智能合约与使用 Solidity 语言的代币进行交互。_ -- [实现 ERC721 市场[指导手册]](/developers/tutorials/how-to-implement-an-erc721-market/) _- 如何将代币化的物品放在分散的分类板上。_ +- [代币集成清单](/developers/tutorials/token-integration-checklist/) _– 与代币交互时需要考虑的事项清单。_ +- [了解 ERC20 代币智能合约](/developers/tutorials/understand-the-erc-20-token-smart-contract/) _– 介绍如何在以太坊测试网上部署您的第一个智能合约。_ +- [通过 Solidity 智能合约转账和批准 ERC20 代币](/developers/tutorials/transfers-and-approval-of-erc-20-tokens-from-a-solidity-smart-contract/) _– 如何使用智能合约通过 Solidity 语言与代币进行交互。_ +- [实现 ERC721 市场 [操作指南]](/developers/tutorials/how-to-implement-an-erc721-market/)_ – 如何在去中心化的分类广告板上出售代币化物品。_ diff --git a/public/content/translations/zh/developers/docs/storage/index.md b/public/content/translations/zh/developers/docs/storage/index.md index 95f91cf9e30..359f385f553 100644 --- a/public/content/translations/zh/developers/docs/storage/index.md +++ b/public/content/translations/zh/developers/docs/storage/index.md @@ -1,12 +1,12 @@ --- -title: 去中心化存储 -description: 概述什么是分布式存储和集成到去中心化应用程序中的相关工具。 +title: "去中心化存储" +description: "概述什么是分布式存储和集成到去中心化应用程序中的相关工具。" lang: zh --- 不同于由一个公司或组织控制的中心服务器,分布式存储系统由分别持有全局数据中部分数据的用户操作者组成 P2P 网络,形成了一个具有弹性的文件储存、共享系统。 这些可以应用于基于区块链的应用程序或任何 P2P 网络中。 -以太坊本身可以用作分布式存储系统,所有智能合约的编码储存就是一种分布式存储。 然而,当涉及大量的数据存储时,就不太符合以太坊的最初目标。 这一区块链正在稳步增长,在本报告撰写之时,以太坊区块链约为 500GB - 1TB([取决于客户端](https://etherscan.io/chartsync/chaindefault)),而网络上的每个节点都需要存储所有这些数据。 如果链上数据量继续扩大(例如 5TB),那么将导致所有节点都无法继续运行。 而且,由于[燃料](/developers/docs/gas)费用,将这么多数据部署到主网的费用将非常昂贵。 +以太坊本身可以用作分布式存储系统,所有智能合约的编码储存就是一种分布式存储。 然而,当涉及大量的数据存储时,就不太符合以太坊的最初目标。 这一区块链正在稳步增长,但在撰写本文时,以太坊区块链的大小约为 500GB - 1TB([取决于客户端](https://etherscan.io/chartsync/chaindefault)),而网络上的每个节点都需要存储所有这些数据。 如果链上数据量继续扩大(例如 5TB),那么将导致所有节点都无法继续运行。 而且,由于 [gas](/developers/docs/gas) 费用,将这么多数据部署到主网的成本将高得令人望而却步。 由于这些制约因素,我们需要使用不同的区块链或方法,以分布式的方式储存大量数据。 @@ -23,27 +23,27 @@ lang: zh 为了使某个数据永久保存,我们需要使用一种持久性机制。 例如,在以太坊中,持久性机制是当运行一个节点时,需要考虑整条链的情况。 新建的数据持续不断地堆积到链的末端,并且要求每个节点复制所有新加入的数据。 -这被称为**基于区块链**的持久性机制。 +这被称为 **基于区块链** 的持久性。 -区块链的持久性存储机制会出现区块链过大,维护和存储所有数据十分困难的问题(比如[许多机构](https://healthit.com.au/how-big-is-the-internet-and-how-do-we-measure-it/)预测整个区块链网络需要 40ZB 的存储容量)。 +基于区块链的持久性的问题在于,区块链可能会变得过大,以至于无法切实地维护和存储所有数据(例如,[许多资料](https://healthit.com.au/how-big-is-the-internet-and-how-do-we-measure-it/)估计,互联网需要超过 40 ZB 的存储容量)。 区块链还必须有某种类型的激励结构。 为获得基于区块链的持久性,需要向验证者付款。 数据被添加到链上后,向验证者付款以继续添加数据。 基于区块链持久性的平台: -- 以太坊 +- 以太坊(Ethereum) - [Arweave](https://www.arweave.org/) ### 基于合约 {#contract-based} -我们能直观地感受到,**基于合约**的持久性使得数据不能被每个节点复制并永久存储,而必须根据合约协议进行维护。 这些是与多个节点达成的协议,这些节点承诺在一段时间内保存一份数据。 每当费用耗尽或数据更新时,就必须向这些节点续费,以保持数据的持续性。 +**基于合约** 的持久性直观地意味着数据无法由每个节点复制和永久存储,而是必须通过合约协议进行维护。 这些是与多个节点达成的协议,这些节点承诺在一段时间内保存一份数据。 每当费用耗尽或数据更新时,就必须向这些节点续费,以保持数据的持续性。 -在大多数情况下,不是在链上储存所有数据,而是在链上存储定位数据的哈希值。 这样,整条链不需要扩大规模,就能保存所有数据。 +在大多数情况下,不是在链上储存所有数据,而是在链上存储数据对应位置的哈希值。 这样,整条链不需要扩大规模,就能保存所有数据。 基于合约持久性的平台: -- [Filecoin](https://docs.filecoin.io/about-filecoin/what-is-filecoin/) -- [Skynet](https://siasky.net/) +- [Filecoin](https://docs.filecoin.io/basics/what-is-filecoin) +- [Skynet](https://sia.tech/) - [Storj](https://storj.io/) - [Züs](https://zus.network/) - [Crust Network](https://crust.network) @@ -54,22 +54,22 @@ lang: zh 星际文件系统是一个储存和访问文件、网站、应用程序和数据的分布式系统。 虽然它没有内置激励计划,但可以与上述任何基于合同的激励解决方案一起使用,以获得更长期的持久性。 另一个将数据持久存储在星际文件系统上的办法是与某项固定服务(表示将你的数据固定在某处)一起使用。 你甚至可以运行自己的星际文件系统节点来为该网络做出贡献,从而将你和/或他人的数据免费持久地存储在星际文件系统上。 -- [星际文件系统](https://docs.ipfs.io/concepts/what-is-ipfs/) -- [Pinata](https://www.pinata.cloud/)_(星际文件系统固定服务)_ -- [web3.storage](https://web3.storage/)_(星际文件系统/菲乐币固定服务)_ -- [Infura](https://infura.io/product/ipfs)_(星际文件系统固定服务)_ -- [IPFS Scan](https://ipfs-scan.io) _(星际文件系统固定浏览器)_ -- [4EVERLAND](https://www.4everland.org/)_(星际文件系统固定服务)_ -- [Filebase](https://filebase.com)_(星际文件系统固定服务)_ -- [Spheron Network](https://spheron.network/)_(星际文件系统/菲乐币固定服务)_ +- [IPFS](https://docs.ipfs.io/concepts/what-is-ipfs/) +- [Pinata](https://www.pinata.cloud/) _(IPFS 固定服务)_ +- [web3.storage](https://web3.storage/) _(IPFS/Filecoin 固定服务)_ +- [Infura](https://infura.io/product/ipfs) _(IPFS 固定服务)_ +- [IPFS Scan](https://ipfs-scan.io) _(IPFS 固定浏览器)_ +- [4EVERLAND](https://www.4everland.org/)_(IPFS 固定服务)_ +- [Filebase](https://filebase.com) _(IPFS 固定服务)_ +- [Spheron Network](https://spheron.network/) _(IPFS/Filecoin 固定服务)_ -SWARM 是一种去中心化的数据存储和分发技术,具有存储激励系统和存储空间租金价格预言机。 +SWARM 是一种去中心化的数据存储和分发技术,具有存储激励系统和存储租金价格预言机。 -## 数据留存 {#data-retention} +## 数据保留 {#data-retention} 为了保留数据,系统必须有某种机制,确保数据得到保留。 -### 质疑机制 {#challenge-mechanism} +### 挑战机制 {#challenge-mechanism} 一种最常见的确保保留数据的方法是使用某种类型的密码质询,这种加密质询向节点发出,确保它们仍然持有数据。 一种简单的方法是查看 Arweave 的访问证明。 他们向节点发出质询,查看它们是否在最近的区块和过去的随机区块中都具有数据。 如果节点无法给出答案,则会受到惩罚。 @@ -92,13 +92,13 @@ SWARM 是一种去中心化的数据存储和分发技术,具有存储激励 - Arweave - Filecoin - 星际文件系统 -- 以太坊 +- 以太坊(Ethereum) - Crust Network - 4EVERLAND ### 共识 {#consensus} -这些工具大多有自己的[共识机制](/developers/docs/consensus-mechanisms/)版本,但一般都是基于[**工作量证明 (PoW)**](/developers/docs/consensus-mechanisms/pow/) 或[**权益证明 (PoS)**](/developers/docs/consensus-mechanisms/pos/)。 +这些工具大多有自己的[共识机制](/developers/docs/consensus-mechanisms/)版本,但通常都基于[**工作量证明 (PoW)**](/developers/docs/consensus-mechanisms/pow/)或[**权益证明 (PoS)**](/developers/docs/consensus-mechanisms/pos/)。 基于工作量证明的工具: @@ -107,110 +107,110 @@ SWARM 是一种去中心化的数据存储和分发技术,具有存储激励 基于权益证明的工具: -- 以太坊 +- 以太坊(Ethereum) - Filecoin - Züs - Crust Network ## 相关工具 {#related-tools} -**IPFS - _即星际文件系统,是以太坊的去中心化存储和文件引用系统。_** +**IPFS - _星际文件系统,是以太坊的去中心化存储和文件引用系统。_** - [Ipfs.io](https://ipfs.io/) - [相关文档](https://docs.ipfs.io/) - [GitHub](https://github.com/ipfs/ipfs) -**Storj DCS - _安全、私有、与 S3 兼容的去中心化云对象存储,供开发者使用。_** +**Storj DCS - _安全、私有且与 S3 兼容的去中心化云对象存储,专为开发者打造。_** - [Storj.io](https://storj.io/) - [相关文档](https://docs.storj.io/) - [GitHub](https://github.com/storj/storj) -**Skynet - _Skynet 是一条去中心化的工作量证明链,专用于去中心化网络。_** +**Sia - _利用密码学创建了一个无需信任的云存储市场,允许买卖双方直接交易。_** -- [Skynet.net](https://siasky.net/) -- [相关文档](https://siasky.net/docs/) -- [GitHub](https://github.com/SkynetLabs/) +- [Skynet.net](https://sia.tech/) +- [相关文档](https://docs.sia.tech/) +- [GitHub](https://github.com/SiaFoundation/) -**Filecoin - _Filecoin 由星际文件系统背后的同一团队打造。 它是星际文件系统概念之上的一个激励层。_** +**Filecoin - _Filecoin 由 IPFS 幕后的同一个团队创建。 它是在 IPFS 理念之上构建的激励层。_** - [Filecoin.io](https://filecoin.io/) - [相关文档](https://docs.filecoin.io/) - [GitHub](https://github.com/filecoin-project/) -**Arweave - _Arweave 是去中心化数据存储平台。_** +**Arweave - _Arweave 是一个用于存储数据的去中心化存储 (dStorage) 平台。_** - [Arweave.org](https://www.arweave.org/) - [相关文档](https://docs.arweave.org/info/) - [Arweave](https://github.com/ArweaveTeam/arweave/) -**Züs - _Züs 是一个具有分片和 blobber 的权益证明去中心化存储平台。_** +**Züs - _Züs 是一个采用权益证明、带有分片和 blobber 的去中心化存储 (dStorage) 平台。_** - [zus.network](https://zus.network/) -- [相关文档](https://0chaindocs.gitbook.io/zus-docs) +- [相关文档](https://docs.zus.network/zus-docs/) - [GitHub](https://github.com/0chain/) -**Crust Network - _Crust 是基于星际文件系统的去中心化存储平台。_** +**Crust Network - _Crust 是一个基于 IPFS 的去中心化存储 (dStorage) 平台。_** - [Crust.network](https://crust.network) - [相关文档](https://wiki.crust.network) - [GitHub](https://github.com/crustio) -**Swarm - _以太坊 Web3 堆栈的分布式存储平台和内容分发服务。_** +**Swarm - _一个为以太坊 Web3 堆栈服务的分布式存储平台和内容分发服务。_** - [EthSwarm.org](https://www.ethswarm.org/) -- [相关文档](https://docs.ethswarm.org/docs/) +- [相关文档](https://docs.ethswarm.org/) - [GitHub](https://github.com/ethersphere/) -**OrbitDB - _基于星际文件系统的去中心化点对点数据库。_** +**OrbitDB - _一个基于 IPFS 的去中心化点对点数据库。_** - [OrbitDB.org](https://orbitdb.org/) - [相关文档](https://github.com/orbitdb/field-manual/) - [GitHub](https://github.com/orbitdb/orbit-db/) -**Aleph.im - _去中心化云项目(数据库、文件存储、计算和去中心化身份)。 独特的链下和链上点对点技术融合。 星际文件系统以及多链兼容性。_** +**Aleph.im - _去中心化云项目(数据库、文件存储、计算和 DID)。 独特的链下和链上点对点技术融合。 兼容 IPFS 和多链。_** -- [Aleph.im](https://aleph.im/) -- [相关文档](https://aleph.im/#/developers/) +- [Aleph.im](https://aleph.cloud/) +- [相关文档](https://docs.aleph.cloud/) - [GitHub](https://github.com/aleph-im/) -**Ceramic - _用户控制的星际文件系统数据库存储,用于数据丰富和吸引人的应用程序。_** +**Ceramic - _用于构建数据丰富、引人入胜的应用程序的用户控制型 IPFS 数据库存储。_** - [Ceramic.network](https://ceramic.network/) -- [相关文档](https://developers.ceramic.network/learn/welcome/) +- [相关文档](https://developers.ceramic.network/) - [GitHub](https://github.com/ceramicnetwork/js-ceramic/) -**Filebase - _ S3 兼容的去中心化存储和地理冗余星际文件系统固定服务。 所有通过 Filebase 上传到星际文件系统的文件都会自动被固定到 Filebase 基础设施,在全球复制 3 份。_** +**Filebase - _与 S3 兼容的去中心化存储和异地冗余 IPFS 固定服务。 所有通过 Filebase 上传到 IPFS 的文件都会自动固定到 Filebase 基础设施,并在全球进行 3 倍复制。_** - [Filebase.com](https://filebase.com/) - [相关文档](https://docs.filebase.com/) - [GitHub](https://github.com/filebase) -**4EVERLAND - _Web 3.0 云计算平台,集存储、计算和网络核心能力于一体,兼容 S3,在星际文件系统和 Arweave 等去中心化存储网络上提供同步数据存储。_** +**4EVERLAND - _一个集成了存储、计算和网络核心能力的 Web3.0 云计算平台,兼容 S3,并可在 IPFS 和 Arweave 等去中心化存储网络上提供同步数据存储。_** - [4everland.org](https://www.4everland.org/) - [相关文档](https://docs.4everland.org/) - [GitHub](https://github.com/4everland) -**Kaleido - _一个具有点击按钮星际文件系统节点的区块链即服务平台_** +**Kaleido - _一个提供一键式 IPFS 节点的区块链即服务平台_** - [Kaleido](https://kaleido.io/) - [相关文档](https://docs.kaleido.io/kaleido-services/ipfs/) - [GitHub](https://github.com/kaleido-io) -**Spheron Network - _Spheron 是一项平台即服务 (PaaS),专为希望在去中心化基础设施上启动其应用程序并获得最佳性能的去中心化应用程序而设计。 它提供开箱即用的计算、去中心化存储、内容分发网络和虚拟主机。_** +**Spheron Network - _Spheron 是一个平台即服务 (PaaS),专为希望在具有最佳性能的去中心化基础设施上启动其应用程序的去中心化应用程序 (dApp) 而设计。 它提供开箱即用的计算、去中心化存储、CDN 和 Web 托管服务。_** - [spheron.network](https://spheron.network/) - [相关文档](https://docs.spheron.network/) - [GitHub](https://github.com/spheronFdn) -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [什么是去中心化存储?](https://coinmarketcap.com/alexandria/article/what-is-decentralized-storage-a-deep-dive-by-filecoin) - _CoinMarketCap_ -- [打破关于去中心化存储的五种谣传](https://www.storj.io/blog/busting-five-common-myths-about-decentralized-storage) - _Storj_ +- [什么是去中心化存储?](https://coinmarketcap.com/academy/article/what-is-decentralized-storage-a-deep-dive-by-filecoin) - _CoinMarketCap_ +- [揭穿关于去中心化存储的五个常见迷思](https://www.storj.io/blog/busting-five-common-myths-about-decentralized-storage) - _Storj_ -_还有哪些社区资源对你有所帮助? 请编辑本页面并添加!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [开发框架](/developers/docs/frameworks/) diff --git a/public/content/translations/zh/developers/docs/transactions/index.md b/public/content/translations/zh/developers/docs/transactions/index.md index 89e41c94efd..95f15426126 100644 --- a/public/content/translations/zh/developers/docs/transactions/index.md +++ b/public/content/translations/zh/developers/docs/transactions/index.md @@ -1,6 +1,6 @@ --- -title: 交易 -description: 以太坊交易 – 工作原理、数据结构以及如何通过应用发送。 +title: "交易" +description: "以太坊交易 – 工作原理、数据结构以及如何通过应用发送。" lang: zh --- @@ -8,13 +8,14 @@ lang: zh ## 前提条件 {#prerequisites} -为了帮助你更好地理解这个页面,我们建议先阅读[帐户](/developers/docs/accounts/)和我们的[以太坊简介](/developers/docs/intro-to-ethereum/)。 +为了帮助你更好地理解本页面,我们建议你先阅读[帐户](/developers/docs/accounts/)和我们的[以太坊简介](/developers/docs/intro-to-ethereum/)。 ## 什么是交易? {#whats-a-transaction} 以太坊交易是指由外部持有帐户发起的行动,换句话说,是指由人管理而不是智能合约管理的帐户。 例如,如果 Bob 发送 Alice 1 ETH,则 Bob 的帐户必须减少 1 ETH,而 Alice 的帐户必须增加 1 ETH。 交易会造成状态的改变。 -![显示交易导致状态更改的图表](./tx.png) _示意图节选自[以太坊虚拟机图解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![显示交易导致状态变化的图表](./tx.png) +_图表改编自 [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ 改变 EVM 状态的交易需要广播到整个网络。 任何节点都可以广播在以太坊虚拟机上执行交易的请求;此后,验证者将执行交易并将由此产生的状态变化传播到网络的其他部分。 @@ -22,17 +23,17 @@ lang: zh 所提交的交易包括下列信息: -- `from` - 发送者的地址,该地址将签署交易。 这将是一个外部帐户,因为合约帐户无法发送交易 -- `to` — 接收地址(如果是外部帐户,交易将传输值。 如果是合约帐户,交易将执行合约代码) +- `from` – 发送者的地址,该地址将签署交易。 这将是一个外部帐户,因为合约帐户无法发送交易 +- `to` – 接收地址(如果是外部所有的帐户,交易将转移价值。 如果是合约帐户,交易将执行合约代码) - `signature` – 发送者的标识符。 当发送者的私钥签署交易并确保发送者已授权此交易时,生成此签名。 -- `nonce` - 一个有序递增的计数器,表示来自帐户的交易数量 -- `value` – 发送者向接收者转移的以太币数量(面值为 WEI,1 个以太币 = 1e+18wei) -- `input data` – 可包括任意数据的可选字段 -- `gasLimit` – 交易可以消耗的最大数量的燃料单位。 [以太坊虚拟机](/developers/docs/evm/opcodes)指定每个计算步骤所需的燃料单位 -- `maxPriorityFeePerGas` - 作为小费提供给验证者的已消耗燃料的最高价格 +- `nonce` - 一个顺序递增的计数器,表示来自该帐户的交易序号 +- `value` – 从发送者转移到接收者的 ETH 数量(以 WEI 为单位,其中 1ETH 等于 1e+18wei) +- `input data` – 包含任意数据的可选字段 +- `gasLimit` – 交易可消耗的最大燃料单位数量。 [EVM](/developers/docs/evm/opcodes) 指定了每个计算步骤所需的燃料单位 +- `maxPriorityFeePerGas` - 作为给验证者的小费,愿意为每单位燃料支付的最高价格 - `maxFeePerGas` - 愿意为交易支付的每单位燃料的最高费用(包括 `baseFeePerGas` 和 `maxPriorityFeePerGas`) -燃料是指验证者处理交易所需的计算。 用户必须为此计算支付费用。 `gasLimit` 和 `maxPriorityFeePerGas` 决定支付给验证者的最高交易费。 [关于燃料的更多信息](/developers/docs/gas/)。 +燃料是指验证者处理交易所需的计算。 用户必须为此计算支付费用。 `gasLimit` 和 `maxPriorityFeePerGas` 决定了支付给验证者的最高交易费用。 [更多关于燃料的信息](/developers/docs/gas/) 交易对象看起来像这样: @@ -41,10 +42,10 @@ lang: zh from: "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", to: "0xac03bb73b6a9e108530aff4df5077c2b3d481e5a", gasLimit: "21000", - maxFeePerGas: "300" - maxPriorityFeePerGas: "10" + maxFeePerGas: "300", + maxPriorityFeePerGas: "10", nonce: "0", - value: "10000000000", + value: "10000000000" } ``` @@ -99,22 +100,26 @@ Geth 这样的以太坊客户端将处理此签名过程。 } ``` -- `raw` 是采用[递归长度前缀 (RLP) ](/developers/docs/data-structures-and-encoding/rlp)编码形式的签名交易 -- `tx` 是已签名交易的 JSON 形式。 +- `raw` 是以[递归长度前缀 (RLP)](/developers/docs/data-structures-and-encoding/rlp) 编码格式表示的已签名交易 +- `tx` 是 JSON 格式的已签名交易 如有签名哈希,可通过加密技术证明交易来自发送者并提交网络。 -### `data`字段 {#the-data-field} +### 数据字段 {#the-data-field} -绝大多数交易都是从外部所有的帐户访问合约。 大多数合约用 Solidity 语言编写,并根据[应用程序二进制接口 (ABI)](/glossary/#abi) 解释其`data`字段。 +绝大多数交易都是从外部所有的帐户访问合约。 +大多数合约用 Solidity 编写,并根据[应用程序二进制接口 (ABI)](/glossary/#abi) 来解析其数据字段。 -前四个字节使用函数名称和参数的哈希指定要调用的函数。 有时可以使用[本数据库](https://www.4byte.directory/signatures/)根据选择器识别函数。 +前四个字节使用函数名称和参数的哈希指定要调用的函数。 +有时,你可以使用[这个数据库](https://www.4byte.directory/signatures/)从选择器中识别函数。 -调用数据的其余部分是参数,[按照应用程序二进制接口规范中的规定进行编码](https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding)。 +calldata 的其余部分是参数,[按照 ABI 规范中的指定进行编码](https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding)。 -例如,我们来看一下[这笔交易](https://etherscan.io/tx/0xd0dcbe007569fcfa1902dae0ab8b4e078efe42e231786312289b1eee5590f6a1)。 使用 **Click to see More(单击查看更多)**查看调用数据。 +例如,我们来看[这笔交易](https://etherscan.io/tx/0xd0dcbe007569fcfa1902dae0ab8b4e078efe42e231786312289b1eee5590f6a1)。 +点击 **Click to see More** 查看 calldata。 -函数选择器是 `0xa9059cbb`。 有几个[具有此签名的已知函数](https://www.4byte.directory/signatures/?bytes4_signature=0xa9059cbb)。 本例中[合约源代码](https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#code)已经上传到 Etherscan,所以我们知道该函数是 `transfer(address, uint256)`。 +函数选择器是 `0xa9059cbb`。 [具有此签名的已知函数](https://www.4byte.directory/signatures/?bytes4_signature=0xa9059cbb)有多个。 +在本例中,[合约源代码](https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#code)已上传至 Etherscan,因此我们知道函数是 `transfer(address,uint256)`。 其余数据如下: @@ -123,7 +128,9 @@ Geth 这样的以太坊客户端将处理此签名过程。 000000000000000000000000000000000000000000000000000000003b0559f4 ``` -根据应用程序二进制接口规范,整型值(例如地址,它是 20 字节整型)在应用程序二进制接口中显示为 32 字节的字,前面用零填充。 所以我们知道 `to` 地址是 [`4f6742badb049791cd9a37ea913f2bac38d01279`](https://etherscan.io/address/0x4f6742badb049791cd9a37ea913f2bac38d01279)。 `value` 是 0x3b0559f4 = 990206452。 +根据应用程序二进制接口规范,整型值(例如地址,它是 20 字节整型)在应用程序二进制接口中显示为 32 字节的字,前面用零填充。 +所以我们知道 `to` 地址是 [`4f6742badb049791cd9a37ea913f2bac38d01279`](https://etherscan.io/address/0x4f6742badb049791cd9a37ea913f2bac38d01279)。 +`value` 是 0x3b0559f4 = 990206452。 ## 交易类型 {#types-of-transactions} @@ -135,9 +142,9 @@ Geth 这样的以太坊客户端将处理此签名过程。 ### 关于燃料 {#on-gas} -如上所述,执行交易需要耗费[燃料](/developers/docs/gas/)。 简单的转账交易需要 21000 单位燃料。 +如前所述,执行交易需要花费[燃料](/developers/docs/gas/)。 简单的转账交易需要 21000 单位燃料。 -因此,如果 Bob 要在 `baseFeePerGas` 为 190 Gwei 且 `maxPriorityFeePerGas` 为 10 Gwei 时给 Alice 发送一个以太币,Bob 需要支付以下费用: +因此,如果 Bob 在 `baseFeePerGas` 为 190 gwei、`maxPriorityFeePerGas` 为 10 gwei 的情况下,要发送 1 ETH 给 Alice,Bob 需要支付以下费用: ``` (190 + 10) * 21000 = 4,200,000 gwei @@ -145,16 +152,16 @@ Geth 这样的以太坊客户端将处理此签名过程。 0.0042 ETH ``` -Bob 的帐户将会扣除 **1.0042 个以太币**(1 个以太币给 Alice,0.0042 个以太币作为燃料费用) +Bob 的帐户将被扣除 **-1.0042 ETH**(1 ETH 给 Alice + 0.0042 ETH 作为燃料费) -Alice 的帐户将会增加 **+1.0 ETH** +Alice 的帐户将计入 **+1.0 ETH** -基础费将会燃烧 **-0.00399 ETH** +基本费用将被销毁 **-0.00399 ETH** -验证者获得 **0.000210 个以太币**的小费 +验证者保留小费 **+0.000210 ETH** - -![未使用燃料退还示意图](./gas-tx.png) _示意图节选自[以太坊虚拟机图解](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ +![显示未用燃料如何退还的图表](./gas-tx.png) +_图表改编自 [Ethereum EVM illustrated](https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)_ 任何未用于交易的燃料都会退还给用户帐户。 @@ -162,59 +169,64 @@ Alice 的帐户将会增加 **+1.0 ETH** 任何涉及智能合约的交易都需要燃料。 -智能合约还可以包含被称为 [`view`](https://docs.soliditylang.org/en/latest/contracts.html#view-functions) 或 [`pure`](https://docs.soliditylang.org/en/latest/contracts.html#pure-functions) 的函数,这不会改变合约的状态。 像这样,从外部帐户调用这些函数不需要任何燃料。 此场景的底层远程过程调用 (RPC) 为 [`eth_call`](/developers/docs/apis/json-rpc#eth_call)。 +智能合约也可以包含称为 [`view`](https://docs.soliditylang.org/en/latest/contracts.html#view-functions) 或 [`pure`](https://docs.soliditylang.org/en/latest/contracts.html#pure-functions) 的函数,它们不改变合约的状态。 像这样,从外部帐户调用这些函数不需要任何燃料。 此场景的底层 RPC 调用是 [`eth_call`](/developers/docs/apis/json-rpc#eth_call)。 -不同于使用 `eth_call` 进行访问,`view` 或 `pure` 函数通常也在内部(即从合约自身或其他合约)调用并消耗燃料。 +与使用 `eth_call` 访问不同,这些 `view` 或 `pure` 函数也常在内部(即从合约本身或从另一个合约)调用,这会消耗燃料。 ## 交易生命周期 {#transaction-lifecycle} 交易提交后,就会发生以下情况: -1. 以加密方式生成的交易哈希: `0x97d99bc7729211111a21b12c933c949d4f31684f1d6954ff477d0477538ff017` +1. 交易哈希是通过加密方式生成的: + `0x97d99bc7729211111a21b12c933c949d4f31684f1d6954ff477d0477538ff017` 2. 然后,该交易被广播到网络,并添加到由所有其他待处理的网络交易组成的交易池中。 3. 验证者必须选择你的交易并将它包含在一个区块中,以便验证交易并认为它“成功”。 -4. 随着时间的流逝,包含你的交易的区块将升级成“合理”状态,然后变成“最后确定”状态。 通过这些升级,可以进一步确定 你的交易已经成功并将无法更改。 区块一旦“最终确定”,只能通过耗费数十亿美元 的网络级攻击来更改。 +4. 随着时间的流逝,包含你的交易的区块将升级成“合理”状态,然后变成“最后确定”状态。 这些升级让你更加确信 + 你的交易已成功,并且永远不会被更改。 一旦区块被“最终敲定”,它只能被 + 耗资数十亿美元的网络级攻击所更改。 -## 视频演示 {#a-visual-demo} +## 可视化演示 {#a-visual-demo} 跟随 Austin 了解交易、燃料和挖矿。 -## Typed Transaction Envelope交易 {#typed-transaction-envelope} +## 类型化交易信封 {#typed-transaction-envelope} -以太坊最初有一种交易形式。 每笔交易都包含 Nonce、燃料价格、燃料限制、目的地地址、价值、数据、v、r 和 s。 这些字段为 [RLP 编码](/developers/docs/data-structures-and-encoding/rlp/),看起来像这样: +以太坊最初有一种交易形式。 每笔交易都包含 Nonce、燃料价格、燃料限制、目的地地址、价值、数据、v、r 和 s。 这些字段经过 [RLP 编码](/developers/docs/data-structures-and-encoding/rlP/)后,看起来像这样: `RLP([nonce, gasPrice, gasLimit, to, value, data, v, r, s])` -以太坊经过演变,已经支持多种类型的交易,从而能够在不影响传统交易形式的情况下实现访问列表和 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 等新功能。 +以太坊已经发展到支持多种类型的交易,以便在不影响旧有交易格式的情况下,实现访问列表和 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 等新功能。 -[EIP-2718](https://eips.ethereum.org/EIPS/eip-2718)是允许这种行为的。 交易解释如下: +[EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) 实现了这一行为。 交易解释如下: `TransactionType || TransactionPayload` 其中,字段定义如下: -- `TransactionType` - 一个在 0 到 0x7f 之间的数字,总共为 128 种可能的交易类型。 +- `TransactionType` - 一个介于 0 和 0x7f 之间的数字,总共有 128 种可能的交易类型。 - `TransactionPayload` - 由交易类型定义的任意字节数组。 -基于 `TransactionType` 值,交易可被分为以下几类: +根据 `TransactionType` 的值,交易可以分为: -1. **Type 0(传统)交易:**自以太坊推出以来使用的原始交易格式。 它们不包含 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 中的功能,例如动态燃料费计算或智能合约访问列表。 传统交易缺少以序列化形式表明其类型的特定前缀,在使用[递归长度前缀编码 (RLP)](/developers/docs/data-structures-and-encoding/rlp) 时以 `0xf8` 字节开头。 这些交易的 TransactionType 值为 `0x0`。 +1. \*\*类型 0(传统)交易:\*\*自以太坊推出以来使用的原始交易格式。 它们不包含 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 的功能,例如动态燃料费计算或智能合约访问列表。 传统交易在其序列化形式中缺少表示其类型的特定前缀,在使用[递归长度前缀 (RLP)](/developers/docs/data-structures-and-encoding/rlp) 编码时,以字节 `0xf8` 开头。 这些交易的 TransactionType 值为 `0x0`。 -2. **Type 1 交易:** 作为以太坊[柏林升级](/ethereum-forks/#berlin)的一部分在 [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) 中引入,这些交易包含一个 `accessList` 参数。 该列表指定了交易预期访问的地址和存储密钥,有助于降低涉及智能合约的复杂交易的潜在[燃料](/developers/docs/gas/)花费。 EIP-1559 的费用市场变化不包含在 Type 1 交易中。 Type 1 交易还包括一个 `yParity` 参数,它可以是 `0x0` 或 `0x1`,表示 secp256k1 签名的 y 值奇偶性。 它们以字节 `0x01` 开头进行标识,其交易类型 (TransactionType) 值为 `0x1`。 +2. \*\*类型 1 交易:\*\*在 [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) 中作为以太坊[柏林升级](/ethereum-forks/#berlin)的一部分引入,这些交易包含 `accessList` 参数。 此列表指定交易期望访问的地址和存储密钥,有助于减少涉及智能合约的复杂交易的[燃料](/developers/docs/gas/)成本。 EIP-1559 的费用市场变化不包含在 Type 1 交易中。 类型 1 交易还包含 `yParity` 参数,该参数可以是 `0x0` 或 `0x1`,表示 secp256k1 签名的 y 值的奇偶性。 它们以字节 `0x01` 开头进行标识,其交易类型 (TransactionType) 值为 `0x1`。 -3. **Type 2 交易**通常称为 EIP-1559 交易,是在以太坊[伦敦升级](/ethereum-forks/#london)的 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 中引入的。 它们已成为以太坊网络上的标准交易类型。 这些交易引入了一种新的费用市场机制,通过将交易费分为基础费用和优先费用来提高可预测性。 它们以字节 `0x02` 开头,并包括 `maxPriorityFeePerGas` 和 `maxFeePerGas` 的字段。 Type 2 交易因其灵活性和效率,现已成为默认选择,特别是在网络严重拥堵期间,由于它能够帮助用户提高管理交易费用的可预测性,因此特别受到青睐。 这些交易的 TransactionType 值为 `0x2`。 +3. **类型 2 交易**,通常称为 EIP-1559 交易,是在以太坊[伦敦升级](/ethereum-forks/#london)中通过 [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) 引入的交易。 它们已成为以太坊网络上的标准交易类型。 这些交易引入了一种新的费用市场机制,通过将交易费分为基础费用和优先费用来提高可预测性。 它们以字节 `0x02` 开头,并包括 `maxPriorityFeePerGas` 和 `maxFeePerGas` 等字段。 Type 2 交易因其灵活性和效率,现已成为默认选择,特别是在网络严重拥堵期间,由于它能够帮助用户提高管理交易费用的可预测性,因此特别受到青睐。 这些交易的 TransactionType 值为 `0x2`。 +4. **类型 3 (Blob) 交易**是在以太坊[坎昆-Deneb (Dencun) 升级](/ethereum-forks/#dencun)中通过 [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) 引入的。 这些交易旨在更高效地处理 "blob" 数据 (二进制大对象),它们提供了一种以更低成本将数据发布到以太坊网络的方法,尤其有利于二层网络卷叠。 Blob 交易包含额外的字段,例如 `blobVersionedHashes`、`maxFeePerBlobGas` 和 `blobGasPrice`。 它们以字节 `0x03` 开头,其 TransactionType 值为 `0x3`。 Blob 交易代表了以太坊在数据可用性和可扩展性方面的重大改进。 +5. **类型 4 交易**是在以太坊[Pectra 升级](/roadmap/pectra/)中通过 [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) 引入的。 这些交易被设计为与账户抽象向前兼容。 它们允许 EOA 临时表现得像智能合约账户,而不会影响其原有功能。 它们包含一个 `authorization_list` 参数,该参数指定了 EOA 将其权限委托给哪个智能合约。 交易之后,EOA 的代码字段将包含被委托的智能合约的地址。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} -- [EIP-2718:Typed Transaction Envelope](https://eips.ethereum.org/EIPS/eip-2718) +- [EIP-2718:类型化交易信封](https://eips.ethereum.org/EIPS/eip-2718) -_你知道有什么社区资源帮助过你吗? 编辑并添加本页面!_ +_你还知道哪些对你有帮助的社区资源? 请编辑本页面并添加进来!_ -## 相关主题 {#related-topics} +## 相关话题 {#related-topics} - [帐户](/developers/docs/accounts/) - [以太坊虚拟机 (EVM)](/developers/docs/evm/) diff --git a/public/content/translations/zh/developers/docs/web2-vs-web3/index.md b/public/content/translations/zh/developers/docs/web2-vs-web3/index.md index bf6c1dc77b2..994079fee47 100644 --- a/public/content/translations/zh/developers/docs/web2-vs-web3/index.md +++ b/public/content/translations/zh/developers/docs/web2-vs-web3/index.md @@ -1,6 +1,6 @@ --- -title: Web2 与 Web3 的对比 -description: +title: "Web2 与 Web3 的对比" +description: "对比中心化 Web2 服务与基于以太坊区块链技术的去中心化 Web3 应用。" lang: zh --- @@ -17,7 +17,7 @@ Web2 指的是如今我们众所周知的互联网版本。 互联网由互联 - 付款是通过原生代币以太币 (ETH) 构建的。 - 以太坊是图灵完备的,这意味着你几乎可以进行任何编程。 -## 具体比较 {#practical-comparisons} +## 实际比较 {#practical-comparisons} | Web2 | Web3 | | --------------------------- | --------------------------------------------- | @@ -32,31 +32,31 @@ Web2 指的是如今我们众所周知的互联网版本。 互联网由互联 当前,Web3 存在一些局限性: - 可扩展性——交易在 web3 上进度较慢,因为它们是去中心化的。 状态变化(例如支付)需要由节点处理并在整个网络中传播。 -- UX – 与 Web3 应用程序交互可能需要额外的步骤、软件和培训。 这可能是应用的一个障碍。 +- UX — 与 web3 应用程序互动可能需要额外的步骤、软件和学习。 这可能是妨碍其应用的一块绊脚石。 - 可访问性 – 由于在现代 Web 浏览器中的集成不够,致使大多数用户无法访问 Web3。 -- 成本 – 因为成本高昂,大多数成功的去中心化应用程序仅将其代码的很小一部分放到区块链上。 +- 成本 – 因为成本高昂,大多数成功的去中心化应用程序程序仅将其代码的很小一部分放到区块链上。 ## 中心化与去中心化 {#centralization-vs-decentralization} 在下表中,我们大致列举了中心化和去中心化数字网络的一些优缺点。 -| 中心化系统 | 去中心化系统 | -| ------------------------------------------------------ | --------------------------------------------------------------------- | -| 网络半径短(所有参与者都与中心化组织连接); 信息传递快,因为是由一个拥有大量计算资源的中心化组织处理的。 | 网络上最远的参与者可能彼此相距甚远。 网络中一方的信息广播可能需要很长时间才能传达给另一方。 | -| 性能通常较高(吞吐量较高、总计算资源消耗较少)以及构建较为容易。 | 性能通常较低(吞吐量较低,总计算资源消耗较高),构建起来更为复杂。 | -| 在出现相互冲突的数据时,解决办法明确且简单:最终信任的数据来源是中心化组织。 | 解决争端需要一项协议(通常是复杂的协议)。 如果其他参与者对参与者打算同步的数据状态提出相互冲突的主张。 | -| 单点故障:恶意行为者可能能够以中心化组织为目标来破坏网络。 | 无单点故障:即使有很大比例的参与者受到攻击或下线,网络仍然可以运作。 | -| 参与者之间的协调要容易得多,由中心化组织负责。 中心化组织可以迫使网络参与者接受升级、更新协议等,阻力较小。 | 协调往往很困难,因为没有任何单一角色在网络级的决策、协议升级等方面拥有最终发言权。 在最糟糕的情况下,当对协议更改有分歧时,网络容易破裂。 | -| 中心化组织可以审查数据,可能会切断网络的某些部分与网络其他部分的交互。 | 审查制度要困难得多,因为信息有多种途径在网络上传播。 | -| 网络准入由中心化组织控制。 | 任何人都可以加入网络;没有“守门人”。 理想的情况是,参与费用非常低。 | +| 中心化系统 | 去中心化系统 | +| --------------------------------------------------------- | ---------------------------------------------------------------------- | +| 网络直径短(所有参与者都与中心化组织连接);信息传播快,因为传播由一个拥有大量计算资源的中心化组织处理。 | 网络上最远的参与者可能彼此相距不远。 网络中一方的信息可能需要很长时间才能传播给另一方。 | +| 性能通常较高(吞吐量较高、总计算资源消耗较少)并且实现较为容易。 | 性能通常较低(吞吐量较低,总计算资源消耗较高),实现起来更为复杂。 | +| 在出现相互冲突的数据时,解决办法明确且简单:最终信任的数据来源是中心化组织。 | 如果其他参与者对参与者打算同步的数据状态提出相互冲突的主张,需要一项协议(通常是复杂的)来解决争议。 | +| 单点故障:恶意行为者或许能够以中心化组织为目标来破坏网络。 | 无单点故障:即使有很大一部分参与者受到攻击或下线,网络仍然可以运作。 | +| 网络参与者之间的协调要容易得多,由中心化组织负责。 中心化组织可以迫使网络参与者接受升级、更新协议等,阻力非常小。 | 协调往往很困难,因为没有任何单一角色在网络层面的决策、协议升级等方面拥有最终发言权。 在最糟糕的情况下,当对协议变更有分歧时,网络容易破裂。 | +| 中心化组织可以审查数据,可能会切断部分网络与网络其他部分的交互。 | 审查制度要困难得多,因为信息有多种途径在网络上传播。 | +| 网络参与由中心化组织控制。 | 任何人都可以参与网络;没有“守门人”。 理想情况是,参与费用非常低。 | 请注意,这些都是一般概况,可能不适用于每一个网络。 此外,在现实情况下,网络中心化/去中心化程度取决于一系列因素;没有一个网络完全中心化或完全去中心化。 -## 延伸阅读 {#further-reading} +## 扩展阅读{#further-reading} - [什么是 Web3?](/web3/) - _ethereum.org_ -- [Web 3.0 应用程序架构](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) - _Preethi Kasireddy_ -- [去中心化的含义](https://medium.com/@VitalikButerin/the-meaning-of-decentralization-a0c92b76a274) _2017 年 2 月 6 日 - Vitalik Buterin_ -- [去中心化缘何如此重要](https://medium.com/s/story/why-decentralization-matters-5e3f79f7638e) _2018 年 2 月 18 日 - Chris Dixon_ -- [什么是 Web 3.0 以及为何它很重要](https://medium.com/fabric-ventures/what-is-web-3-0-why-it-matters-934eb07f3d2b) _2019 年 12 月 31 日 - Max Mersch 与 Richard Muirhead_ -- [我们为什么需要 Web 3.0](https://medium.com/@gavofyork/why-we-need-web-3-0-5da4f2bf95ab)_ 2018 年 9 月 12 日 - Gavin Wood_ +- [Web 3.0 应用程序的架构](https://www.preethikasireddy.com/post/the-architecture-of-a-web-3-0-application) - _Preethi Kasireddy_ +- [去中心化的意义](https://medium.com/@VitalikButerin/the-meaning-of-decentralization-a0c92b76a274) _2017 年 2 月 6 日 - Vitalik Buterin_ +- [去中心化为何重要](https://onezero.medium.com/why-decentralization-matters-5e3f79f7638e) _2018 年 2 月 18 日 - Chris Dixon_ +- [什么是 Web 3.0 及其重要性](https://medium.com/fabric-ventures/what-is-web-3-0-why-it-matters-934eb07f3d2b) _2019 年 12 月 31 日 - Max Mersch 和 Richard Muirhead_ +- [我们为什么需要 Web 3.0](https://gavofyork.medium.com/why-we-need-web-3-0-5da4f2bf95ab) _2018 年 9 月 12 日 - Gavin Wood_ diff --git a/public/content/translations/zh/developers/tutorials/a-developers-guide-to-ethereum-part-one/index.md b/public/content/translations/zh/developers/tutorials/a-developers-guide-to-ethereum-part-one/index.md index d92aa5ede8c..d9cd93a7888 100644 --- a/public/content/translations/zh/developers/tutorials/a-developers-guide-to-ethereum-part-one/index.md +++ b/public/content/translations/zh/developers/tutorials/a-developers-guide-to-ethereum-part-one/index.md @@ -1,35 +1,32 @@ --- -title: 面向 Python 开发者的以太坊介绍,第一部分 -description: 这是一篇介绍以太坊开发的文章,对那些熟悉 Python 编程语言的人来说尤其有用。 +title: "面向 Python 开发者的以太坊介绍,第一部分" +description: "这是一篇介绍以太坊开发的文章,对那些熟悉 Python 编程语言的人来说尤其有用。" author: Marc Garreau lang: zh -tags: - - "入门指南" - - "python" - - "区块链" - - "web3.py" +tags: [ "python", "web3.py" ] skill: beginner published: 2020-09-08 source: Snake charmers sourceUrl: https://snakecharmers.ethereum.org/a-developers-guide-to-ethereum-pt-1/ --- -想必您已经听说过以太坊,那么,您准备好投身于这个领域了吗? 本篇文章将快速介绍一些区块链基础知识,然后让您与模拟的以太坊节点进行互动,比如读取区块数据、检查账户余额和发送交易。 在这个过程中,我们会着重强调用传统方式构建应用与这种新的去中心化范式之间的差异。 +想必你已经听说过以太坊,那么,你准备好深入研究这个领域了吗? 本篇文章将快速介绍一些区块链基础知识,然后让你与模拟的以太坊节点进行互动,比如读取区块数据、检查帐户余额和发送交易。 在这个过程中,我们会着重强调用传统方式构建应用与这种新的去中心化范式之间的差异。 ## (软)前提条件 {#soft-prerequisites} -本文希望面向所有开发者。 在文章里会涉及 [Python 工具](/developers/docs/programming-languages/python/),不过它们只是思想的载体,如果您不是 Python 开发者也没有问题。 不过,我将对您已经了解的知识作一些假设,以便我们能够迅速地进入以太坊部分。 +本文希望面向广大开发者。 本文会涉及 [Python 工具](/developers/docs/programming-languages/python/),不过它们只是思想的载体,如果你不是 Python 开发者也没问题。 不过,我将对你已经了解的知识作一些假设,以便我们能够迅速地进入以太坊部分。 本文假定: -- 您熟悉终端操作, -- 您写过一些 Python 代码, -- 您的机器上有安装 Python 3.6 或更高版本 (强烈推荐使用 [虚拟环境](https://realpython.com/effective-python-environment/#virtual-environments) ),并且 -- 您使用过 `pip`,Python 的软件包安装程序。 再次强调,如果您不符合其中任何一条,或者您不打算敲本文中的代码,您照着学仍然可以学得很好。 +- 你熟悉终端操作, +- 你写过一些 Python 代码, +- 你的机器上安装了 Python 3.6 或更高版本(强烈建议使用[虚拟环境](https://realpython.com/effective-python-environment/#virtual-environments)),并且 +- 你使用过 `pip` (Python 的软件包安装程序)。 + 再次强调,如果你不符合其中任何一条,或者你不打算复现本文中的代码,你很可能仍然可以顺利地跟上进度。 -## 区块链简述 {#blockchains-briefly} +## 区块链简介 {#blockchains-briefly} -描述以太坊有很多方法,但其核心还是区块链。 区块链由一系列区块组成,所以让我们从区块链开始。 用最简单的话来说,以太坊区块链上的每个区块只是一些元数据和一个交易的列表。 在 JSON 格式中,它看起来像这样: +描述以太坊有很多方法,但其核心还是区块链。 区块链由一系列区块组成,所以我们从区块开始讲起。 用最简单的话来说,以太坊区块链上的每个区块只是一些元数据和一个交易列表。 在 JSON 格式中,它看起来像这样: ```json { @@ -41,39 +38,39 @@ sourceUrl: https://snakecharmers.ethereum.org/a-developers-guide-to-ethereum-pt- } ``` -每个 [块](/developers/docs/blocks/) 会引用它前面的区块; `parentHash` 是前一个区块的哈希值。 +每个[区块](/developers/docs/blocks/)都引用它前面的区块;`parentHash` 就是前一个区块的哈希。 -注:以太坊广泛使用哈希函数来生成固定大小的值(“哈希”)。 哈希值在以太坊中发挥着重要作用,但您现在可以放心地将其视为是唯一的 ID 值。 +注:以太坊广泛使用哈希函数来生成固定大小的值(“哈希”)。 哈希在以太坊中扮演着重要角色,但暂时你可以放心地把它们看作是唯一 ID。 ![描述区块链的示意图,其中包括每个区块内的数据](./blockchain-diagram.png) _区块链本质上是一个链表;每个区块都有一个对前一个区块的引用。_ -这种数据结构并不新颖,但治理网络的规则(即点对点协议)却很新颖。 区块链没有中央机构;网络中的对等节点必需协作以维持网络,并且通过竞争决定将哪些交易纳入下一个区块。 因此,当您想给朋友转账时,您需要将这笔交易广播到网络上,然后等待它被纳入即将产生的区块。 +这种数据结构并不新颖,但治理网络的规则(即点对点协议)却很新颖。 区块链没有中央机构;网络中的对等节点必需协作以维持网络,并且通过竞争决定将哪些交易纳入下一个区块。 因此,当你想给朋友转账时,你需要将这笔交易广播到网络上,然后等待它被纳入即将产生的区块。 -区块链验证资金确实从一个用户发送给另一个用户的唯一方法是使用该区块链原生货币(即,由该区块链创建和管理的货币)。 在以太坊,这种货币被称为 ETH,以太坊区块链是账户余额的唯一正式记录。 +区块链验证资金确实从一个用户发送给另一个用户的唯一方法是使用该区块链原生货币(即,由该区块链创建和管理的货币)。 在以太坊,这种货币被称为以太币,以太坊区块链包含账户余额的唯一官方记录。 -## 一种新范式 {#a-new-paradigm} +## 新范式 {#a-new-paradigm} -这种新的去中心化技术栈催生了新的开发者工具。 许多编程语言都有这样的工具,但我们将通过 Python 的视角来观察。 重申一下:即使 Python 不是您的首选语言,跟上文章也不会有什么太大的问题。 +这种新的去中心化技术栈催生了新的开发者工具。 许多编程语言都有这样的工具,但我们将通过 Python 的视角来观察。 重申一下:即使 Python 不是你的首选语言,跟上文章也不会有什么太大的问题。 -想要与以太坊进行互动的 Python 开发人员可能会接触到 [Web3.py](https://web3py.readthedocs.io/)。 Web3.py 是一个库,可以帮助我们简化连接以太坊节点,以及发送和接收数据。 +想要与以太坊进行交互的 Python 开发者可能会用到 [Web3.py](https://web3py.readthedocs.io/)。 Web3.py 是一个程序库,可以极大简化连接以太坊节点以及收发数据的过程。 注:“以太坊节点”和“以太坊客户端”可互换使用。 这两种说法都是指以太坊网络中参与者所运行的软件。 该软件可以读取区块数据,在新区块添加到链中时接收更新,广播新交易等等。 从技术角度讲,客户端是软件,节点是运行软件的计算机。 -[以太坊客户端](/developers/docs/nodes-and-clients/)可以配置为通过[进程间通信 (IPC)](https://wikipedia.org/wiki/Inter-process_communication)、超文本传输协议 (HTTP) 或网络套接字 (Websockets) 进行访问,因此 Web3.py 也需要完成这个配置。 Web3.py 将这些连接选项称为**提供者**。 您需要从三个提供者中选择一个来连接 Web3.py 实例和您的节点。 +[以太坊客户端](/developers/docs/nodes-and-clients/)可配置为通过 [IPC](https://wikipedia.org/wiki/Inter-process_communication)、HTTP 或 Websockets 访问,因此 Web3.py 也需要进行相应配置。 Web3.py 将这些连接选项称为**提供者**。 你需要从三个提供者中选择一个来连接 Web3.py 实例和你的节点。 -![描述 web3.py 如何使用 IPC 将应用程序连接到以太坊节点的示意图](./web3py-and-nodes.png) +![描述 web3.py 如何使用 IPC 将你的应用程序连接到以太坊节点的示意图](./web3py-and-nodes.png) -_将以太坊节点和 Web3.py 配置为通过相同通信的协议(例如,本图中的 IPC)进行通信。_ +_配置以太坊节点和 Web3.py 通过相同协议(例如本图中的 IPC)进行通信。_ -正确配置了 Web3.py 之后,您就可以开始与区块链交互了。 下面是一些 Web3.py 使用示例,算是抛砖引玉: +正确配置了 Web3.py 之后,你就可以开始与区块链交互了。 下面是一些 Web3.py 使用示例,算是抛砖引玉: ```python -# read block data: +# 读取区块数据: w3.eth.get_block('latest') -# send a transaction: +# 发送一笔交易: w3.eth.send_transaction({'from': ..., 'to': ..., 'value': ...}) ``` @@ -83,112 +80,115 @@ w3.eth.send_transaction({'from': ..., 'to': ..., 'value': ...}) 注:在下面的例子中,以“$”开头的命令是要在终端中运行的。 (不要输入 `$`,它只是表示行的开始。) -首先,安装 [IPython](https://ipython.org/),以方便用户在其中进行探索。 IPython 提供了 tab 补全等功能,使得我们更容易看到 Web3.py 中有哪些可用方法。 +首先,安装 [IPython](https://ipython.org/),以获得一个便于探索的用户友好环境。 IPython 提供了 tab 补全等功能,使得我们更容易看到 Web3.py 中有哪些可用方法。 ```bash -$ pip install ipython +pip install ipython ``` Web3.py 以 `web3` 的名称发布。 安装方式如下: ```bash -$ pip install web3 +pip install web3 ``` 另外,我们后面要模拟一个区块链,这就需要更多依赖项。 可以通过下面的命令安装这些依赖项: ```bash -$ pip install 'web3[tester]' +pip install 'web3[tester]' ``` -您已经设置完毕! +你已经设置完毕! -## 开启沙盒环境 {#spin-up-a-sandbox} +请注意:`web3[tester]` 软件包最高支持 Python 3.10.xx -在终端中运行 `ipython`,打开一个新的 Python 环境。 这与运行 `python` 类似,但更友好。 +## 启动一个沙盒 {#spin-up-a-sandbox} + +在终端中运行 `ipython`,打开一个新的 Python 环境。 这与运行 `python` 类似,但功能更丰富。 ```bash -$ ipython +ipython ``` -这将打印出一些关于您正在运行的 Python 和 IPython 版本的信息,然后您应该会看到一个等待输入的提示: +这将打印出一些关于你正在运行的 Python 和 IPython 版本的信息,然后你应该会看到一个等待输入的提示: ```python In [1]: ``` -您现在看到的是一个交互式的 Python shell, 实际上,它是一个沙盒。 如果您已经做到了这一点,现在可以导入 Web3.py 了: +你现在看到的是一个交互式的 Python shell, 从根本上说,这是一个沙盒。 如果你已经走到这一步,那么现在就可以导入Web3.py了: ```python In [1]: from web3 import Web3 ``` -## Web3 模块介绍 {#introducing-the-web3-module} +## Web3 模块简介 {#introducing-the-web3-module} -除了作为以太坊的网关, [Web3](https://web3py.readthedocs.io/en/stable/overview.html#base-api) 模块还提供了一些便利的功能。 让我们来探究探究。 +除了作为以太坊的网关,[Web3](https://web3py.readthedocs.io/en/stable/overview.html#base-api) 模块还提供了一些便捷函数。 让我们来探究探究。 -在以太坊应用中,您通常需要转换货币面额。 Web3 模块为此提供几个辅助方法: [fromWei](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.fromWei) 和 [toWei](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.toWei)。 +在以太坊应用中,你通常需要转换货币面额。 Web3 模块为此提供了几个辅助方法:[from_wei](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.from_wei) 和 [to_wei](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.to_wei)。 注:计算机不擅长处理十进制数学。 为了规避这个问题,开发者通常会以美分存储美元。 例如,价格为 5.99 美元的物品在数据库中存储为 599。 -在以 ETH 处理交易时,也使用了类似的模式。 但是,ETH 不是只有两个小数位,而是有 18 位。 ether 的最小单位是 wei,所以发送交易时指定的就是这个值。 +在以 ETH 处理交易时,也使用了类似的模式。 但是,ETH 不是只有两个小数位,而是有 18 位。 以太币的最小单位是 wei,因此发送交易时指定的是该值。 -1 ETH = 1000000000000000000 wei +1 以太币 = 1000000000000000000 wei -1 wei = 0.000000000000000001 ETH +1 wei = 0.000000000000000001 以太币 -试一下将一些数值转换为 wei 或反向转换。 请注意, [ETH 和 wei 之间还有其他面额](https://web3py.readthedocs.io/en/stable/troubleshooting.html#how-do-i-convert-currency-denominations)名称。 其中比较有名的是 **gwei**,因为它通常用于表示交易费用。 +试一下将一些数值转换为 wei 或反向转换。 请注意,在以太币和 wei 之间[还有许多其他面额单位的名称](https://web3py.readthedocs.io/en/stable/troubleshooting.html#how-do-i-convert-currency-denominations)。 其中比较有名的是**gwei**,因为它通常用于表示交易费用。 ```python -In [2]: Web3.toWei(1, 'ether') +In [2]: Web3.to_wei(1, 'ether') Out[2]: 1000000000000000000 -In [3]: Web3.fromWei(500000000, 'gwei') +In [3]: Web3.from_wei(500000000, 'gwei') Out[3]: Decimal('0.5') ``` -Web3 模块上的其他实用方法包括数据格式转换器(例如 [`toHex`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.toHex)),地址助手,(例如 [`is address`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.isAddress)),以及哈希函数(例如 [`keccak`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.keccak))。 其中许多内容将在后面的系列文章中介绍。 要查看所有可用的方法和属性,可以利用 IPython 的自动补全功能,输入 `Web3`。 然后在点号后面按两次 tab 键。 +Web3 模块上的其他实用方法包括数据格式转换器(例如 [`toHex`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.toHex))、地址辅助工具(例如 [`isAddress`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.isAddress))和哈希函数(例如 [`keccak`](https://web3py.readthedocs.io/en/stable/web3.main.html#web3.Web3.keccak))。 其中许多内容将在后面的系列文章中介绍。 要查看所有可用的方法和属性,可以利用 IPython 的自动补全功能,输入 `Web3`。 然后在点号后面按两次 tab 键。 -## 与链交互 {#talk-to-the-chain} +## 与链对话 {#talk-to-the-chain} -方便的方法很受欢迎,但让我们继续来说区块链。 接下来配置 Web3.py 与以太坊节点通信。 在这里,我们可以选择使用 IPC、HTTP 或 Websocket 提供者。 +这些便捷方法很棒,但我们还是继续来了解区块链吧。 接下来配置 Web3.py 与以太坊节点通信。 在这里,我们可以选择使用 IPC、HTTP 或 Websocket 提供者。 我们不会完整地进行这个步骤,但一个使用 HTTP 提供者的完整工作流程的例子可能如下所示: - 下载一个以太坊节点,例如 [Geth](https://geth.ethereum.org/)。 -- 在一个终端窗口启动 Geth,等待它同步网络。 默认的 HTTP 端口是 `8545`,但可以配置成其它端口。 -- 告诉 Web3.py 通过 HTTP 连接到节点,使用 `localhost:8545`。 `w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))` +- 在一个终端窗口启动 Geth,等待它同步网络。 默认的 HTTP 端口是 `8545`,但可以配置。 +- 让 Web3.py 通过 HTTP 连接到 `localhost:8545` 上的节点。 + `w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))` - 使用 `w3` 实例与节点交互。 -虽然这是一种“正式”的方式,但同步过程需要几个小时,如果您只是想要一个开发环境,则没有必要同步过程。 Web3.py 为此公开了第四个提供者,即 **EthereumTesterProvider**。 这个测试器提供者连接到一个模拟的以太坊节点,它有更宽松的权限,还有虚拟以太币可供操作。 +虽然这是一种“真实”的方式,但同步过程需要几个小时,如果你只是想要一个开发环境,则没必要进行同步。 Web3.py 为此公开了第四个提供者,即 **EthereumTesterProvider**。 这个测试器提供者连接到一个模拟的以太坊节点,它有更宽松的权限,还有虚拟以太币可供操作。 -![描述将 web3.py 应用程序连接到模拟以太坊节点的 EthereumTesterProvider 的示意图](./ethereumtesterprovider.png) +![显示 EthereumTesterProvider 将你的 web3.py 应用程序链接到模拟以太坊节点的示意图](./ethereumtesterprovider.png) _EthereumTesterProvider 连接到一个模拟节点,对于快速开发环境来说非常方便。_ -这个模拟节点叫做 [eth-tester](https://github.com/ethereum/eth-tester),我们把它作为 `pip install web3[tester]` 命令的一部分进行安装。 配置 Web3.py 来使用这个测试器提供者很简单: +这个模拟节点叫做 [eth-tester](https://github.com/ethereum/eth-tester),我们已通过 `pip install web3[tester]` 命令将其安装。 配置 Web3.py 来使用这个测试器提供者很简单: ```python In [4]: w3 = Web3(Web3.EthereumTesterProvider()) ``` -现在,您已经准备好在链上冲浪了! 这不是人们常说的以太链。 我只是虚构了它。 我们来快速了解一下。 +现在,你已经准备好在链上冲浪了! 人们一般不这么说。 我刚编的。 我们来快速了解一下。 -## 快速了解 {#the-quick-tour} +## 快速概览 {#the-quick-tour} -第一件事,先进行连接检查。 +首先,我们来检查一下是否一切正常: ```python -In [5]: w3.isConnected() +In [5]: w3.is_connected() Out[5]: True ``` -由于我们使用的是测试器提供者,这不是一个非常有价值的测试,但如果它确实失败了,很可能是在实例化 `w3` 变量时发生了输入错误。 仔细检查您是否包含了内括号,即 `Web3.EthereumTesterProvider()`。 +由于我们使用的是测试器提供者,这不是一个非常有价值的测试,但如果它确实失败了,很可能是在实例化 `w3` 变量时发生了输入错误。 仔细检查你是否包含了内括号,即 `Web3.EthereumTesterProvider()`。 -## 第一站:[帐户 ](/developers/docs/accounts/) {#tour-stop-1-accounts} +## 概览第一站:[账户](/developers/docs/accounts/) {#tour-stop-1-accounts} 为了方便起见,测试器提供者创建了一些帐户,并预先分配了测试以太币。 @@ -201,27 +201,27 @@ Out[6]: ['0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', ...] ``` -如果运行这个命令,您应该会看到一个以 `0x` 开头的十个字符串的列表。 每一个字符串都是一个的**公共地址**,在某些方面,类似于支票帐户上的帐号。 如果有人要给您转 ETH,您可以把这个地址给他。 +如果运行这个命令,你应该会看到一个以 `0x` 开头的十个字符串的列表。 每个都是一个**公共地址**,在某些方面类似于银行支票账户的账号。 如果有人要给你转 ETH,你可以把这个地址给他。 -如前所述,测试提供者已经为这些账户中的每一个账户预分配了一些测试以太币。 我们来看看第一个帐户上有多少 ETH。 +如前所述,测试提供者已经为这些帐户中的每一个帐户预分配了一些测试以太币。 我们来看看第一个帐户上有多少 ETH。 ```python In [7]: w3.eth.get_balance(w3.eth.accounts[0]) Out[7]: 1000000000000000000000000 ``` -好多零啊! 在你一路笑醒之前,先回忆一下之前关于货币面额的介绍。 ETH 币值用最小的面额 wei 来表示。 将其转换为 ETH: +好多零啊! 在你偷着乐之前,先回忆一下之前关于货币面额的介绍。 以太币值用最小的面额 wei 来表示。 将其转换为 ETH: ```python -In [8]: w3.fromWei(1000000000000000000000000, 'ether') +In [8]: w3.from_wei(1000000000000000000000000, 'ether') Out[8]: Decimal('1000000') ``` 100 万测试以太币,也不算太寒酸。 -## 第二站:区块数据 {#tour-stop-2-block-data} +## 概览第二站:区块数据 {#tour-stop-2-block-data} -我们来看看这个模拟区块链的状态。 +我们来看看这个模拟区块链的状态: ```python In [9]: w3.eth.get_block('latest') @@ -236,28 +236,31 @@ Out[9]: AttributeDict({ 这里返回了大量关于区块的信息,但这里只介绍以下几点: -- 该区块编号是零  —无论您在多久以前配置了测试器提供者。 与每 12 秒添加一个新区块的真实以太坊网络不同,此模拟区块链则需要你给它一些工作去做才添加区块。 +- 该区块编号是零 —无论你在多久以前配置了测试器提供者。 与每 12 秒添加一个新区块的真实以太坊网络不同,此模拟区块链则需要你给它一些工作去做才添加区块。 - `transactions` 是一个空列表,原因相同:我们还没有做任何事情。 第一个区块是一个**空区块**,只是为了开个头。 - 注意,`parentHash` 只是一堆空的字节。 这标志着它是链条上的第一个区块,也就是所谓的**创世区块**。 -## 第三站:[ 交易 ](/developers/docs/transactions/) {#tour-stop-3-transactions} +## 概览第三站:[交易](/developers/docs/transactions/) {#tour-stop-3-transactions} -在没有待处理交易之前,我们停留在零区块处,所以我们给它一个交易。 从一个账户向另一个账户发送一些测试 ETH: +在没有待处理交易之前,我们停留在零区块处,所以我们给它一个交易。 从一个帐户向另一个帐户发送一些测试 ETH: ```python In [10]: tx_hash = w3.eth.send_transaction({ 'from': w3.eth.accounts[0], 'to': w3.eth.accounts[1], - 'value': w3.toWei(3, 'ether'), + 'value': w3.to_wei(3, 'ether'), 'gas': 21000 }) ``` 这时你通常会等上几秒钟,等待交易添加到新区块中。 完整的流程是这样的: -1. 提交交易并持有交易哈希。 在包含交易的区块被创建并广播之前,交易一直处于“待处理”状态。 `tx_hash = w3.eth.send_transaction({ … })` -2. 等待交易添加到区块中: `w3.eth.wait_for_transaction_receipt(tx_hash)` -3. 继续应用逻辑。 查看成功的交易:`w3.eth.get_transaction(tx_hash)` +1. 提交交易并持有交易哈希。 在包含交易的区块被创建并广播之前,交易一直处于“待处理”状态。 + `tx_hash = w3.eth.send_transaction({ … })` +2. 等待交易被纳入区块: + `w3.eth.wait_for_transaction_receipt(tx_hash)` +3. 继续应用逻辑。 要查看成功交易: + `w3.eth.get_transaction(tx_hash)` 我们的模拟环境会在一个新的区块中即时添加交易,所以我们可以立即查看交易: @@ -274,22 +277,24 @@ Out[11]: AttributeDict({ }) ``` -您将在这里看到一些熟悉的细节:`from`、`to `和 `value `字段应该与 `send_transaction `调用的输入相匹配。 另一个令人欣慰的是,这项交易被列为 1 号区块内的第一笔交易(`'transactionIndex': 0`)。 +你将在这里看到一些熟悉的细节:`from`、`to` 和 `value` 字段应该与我们 `send_transaction` 调用的输入相匹配。 另一个令人欣慰的是,这项交易被列为 1 号区块内的第一笔交易(`'transactionIndex': 0`)。 我们也可以通过检查两个相关帐户的余额,轻松验证此次交易是否成功。 三个 ETH 应从一个帐户转移到另一个帐户。 ```python In [12]: w3.eth.get_balance(w3.eth.accounts[0]) -Out[12]: 999996999999999999969000 +Out[12]: 999996999979000000000000 In [13]: w3.eth.get_balance(w3.eth.accounts[1]) Out[13]: 1000003000000000000000000 ``` -后者看起来不错! 余额从 1000000 增加到 1000003 个 ETH。 但第一个账户发生了什么情况? 它减少的数量看起来略大于三个 ETH? 是的,没有免费的午餐,使用以太坊公网需要支付矿工手续费, 一笔小额交易费从进行交易的帐户中扣除,金额为 31000 wei。 +后者看起来不错! 余额从 1,000,000 增加到 1,000,003 个 ETH。 但第一个帐户发生了什么情况? 它减少的数量看起来略大于三个 ETH? 是的,没有免费的午餐,使用以太坊公网需要向为你提供支持的对等节点支付报酬。 从提交交易的帐户中扣除一小笔交易费用——这笔费用是燃料消耗量(ETH 转账需消耗 21000 单位燃料)乘以根据网络活动而变化的基本费用,再加上给将交易打包到区块中的验证者的小费。 + +更多关于[燃料](/developers/docs/gas/#post-london)的信息 -注:在公共网络上,交易费用根据网络需求和您希望交易处理的速度而变化。 如果您对费用的计算方式感兴趣,请查看我之前关于如何将交易包含在一个区块中的文章。 +注:在公共网络上,交易费用根据网络需求和你希望交易处理的速度而变化。 如果你对费用的计算方式感兴趣,请查看我之前关于如何将交易包含在一个区块中的文章。 -## 结尾 {#and-breathe} +## 喘口气 {#and-breathe} -我们已经学习一段时间,现在可以休息一下。 要学习的内容还有很多,我们将在本系列的第二部分继续进行探索。 探索这些概念:连接真实节点、智能合约和代币, 仍有后续问题? 请告诉我! 您的反馈对我们今后的学习至关重要! 欢迎通过 [Twitter](https://twitter.com/wolovim) 与我联系。 +我们已经学习一段时间,现在可以休息一下。 要学习的内容还有很多,我们将在本系列的第二部分继续进行探索。 即将介绍的概念:连接真实节点、智能合约和代币。 仍有后续问题? 请告诉我! 你的反馈对我们今后的学习至关重要! 欢迎通过 [Twitter](https://twitter.com/wolovim) 提出请求。 diff --git a/public/content/translations/zh/developers/tutorials/all-you-can-cache/index.md b/public/content/translations/zh/developers/tutorials/all-you-can-cache/index.md index 0b52fe029ed..627d4d72026 100644 --- a/public/content/translations/zh/developers/tutorials/all-you-can-cache/index.md +++ b/public/content/translations/zh/developers/tutorials/all-you-can-cache/index.md @@ -1,34 +1,31 @@ --- title: "一切皆可缓存" -description: 学习如何创建和使用缓存合约,以便进行更实惠的卷叠交易 +description: "学习如何创建和使用缓存合约,以便进行更实惠的卷叠交易" author: Ori Pomerantz -tags: - - "二层网络" - - "缓存" - - "storage" +tags: [ "二层网络", "缓存", "存储" ] skill: intermediate published: 2022-09-15 lang: zh --- -当使用卷叠时,交易中一个字节的成本比一个存储插槽的成本要高得多。 因此,在链上缓存尽可能多的信息是有意义的。 +使用卷叠时,交易中一个字节的成本比一个存储插槽的成本高得多。 因此,在链上缓存尽可能多的信息是有意义的。 在本文中,你将学习如何创建和使用缓存合约,使得任何可能被多次使用的参数值都会被缓存,并且(在第一次使用之后)可通过更少的字节数来使用,并学习如何编写使用此缓存的链下代码。 -如果你想跳过这篇文章,直接查看源代码,[参见此处](https://github.com/qbzzt/20220915-all-you-can-cache)。 开发堆栈是 [Foundry](https://book.getfoundry.sh/getting-started/installation)。 +如果你想跳过本文,直接查看源代码,请点击[此处](https://github.com/qbzzt/20220915-all-you-can-cache)。 开发堆栈为 [Foundry](https://getfoundry.sh/introduction/installation/)。 ## 总体设计 {#overall-design} -为了简单起见,我们将假定所有交易参数是 `uint256`,长度为 32 个字节。 当我们收到交易时,将对每个参数进行解析,如下所示: +为简单起见,我们假设所有交易参数均为 `uint256` 类型,长度为 32 字节。 收到交易时,我们将按如下方式解析每个参数: -1. 如果第一个字节是 `0xFF`,则将接下来的 32 个字节作为参数值并将其写入缓存。 +1. 如果第一个字节是 `0xFF`,则取接下来的 32 个字节作为参数值并将其写入缓存。 -2. 如果第一个字节是 `0xFE`,则将接下来的 32 个字节作为参数值,但_不_将其写入缓存。 +2. 如果第一个字节是 `0xFE`,则取接下来的 32 个字节作为参数值,但_不_将其写入缓存。 -3. 对于任何其他值,将前四位作为额外字节的数量,将后四位作为缓存键的最高有效位。 以下是一些示例: +3. 对于任何其他值,取高四位作为附加字节数,低四位作为缓存键的最高有效位。 以下是一些示例: | calldata 中的字节 | 缓存键 | - |:--------------- | --------:| + | :-------------- | -------: | | 0x0F | 0x0F | | 0x10,0x10 | 0x10 | | 0x12,0xAC | 0x02AC | @@ -36,7 +33,7 @@ lang: zh ## 缓存操作 {#cache-manipulation} -缓存是在 [`Cache.sol`](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/Cache.sol) 中实现的。 我们逐行学习它。 +缓存在 [`Cache.sol`](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/Cache.sol) 中实现。 我们逐行来过一遍。 ```solidity // SPDX-License-Identifier: UNLICENSED @@ -49,26 +46,26 @@ contract Cache { bytes1 public constant DONT_CACHE = 0xFE; ``` -这些常量用于解释特殊情况,其中我们提供了所有信息,但是是否希望将其写入缓存是可选的。 写入缓存需要对之前未使用的存储插槽执行两次 [`SSTORE`](https://www.evm.codes/#55) 操作,每次操作花费 22100 燃料,这样我们将此操作变为可选操作。 +这些常量用于解释我们提供所有信息,并选择是否将其写入缓存的特殊情况。 写入缓存需要对之前未使用的存储插槽执行两次 [`SSTORE`](https://www.evm.codes/#55) 操作,每次操作花费 22100 燃料,因此我们将其设为可选。 ```solidity mapping(uint => uint) public val2key; ``` -一个在值和其键之间的[映射](https://www.geeksforgeeks.org/solidity-mappings/)。 在发送交易之前,对值进行编码时需要这些信息。 +值与其键之间的[映射](https://www.geeksforgeeks.org/solidity/solidity-mappings/)。 在发送交易之前,对值进行编码时需要这些信息。 ```solidity - // Location n has the value for key n+1, because we need to preserve - // zero as "not in the cache". + // 位置 n 存储键 n+1 的值,因为我们需要保留 + // 零值来表示“不在缓存中”。 uint[] public key2val; ``` -我们可以使用数组来进行从键到值的映射,出于简单起见,我们按顺序分配键。 +我们可以使用数组来进行从键到值的映射,因为我们分配键,为简单起见,我们按顺序分配。 ```solidity function cacheRead(uint _key) public view returns (uint) { - require(_key <= key2val.length, "Reading uninitialize cache entry"); + require(_key <= key2val.length, "正在读取未初始化的缓存条目"); return key2val[_key-1]; } // cacheRead ``` @@ -76,30 +73,30 @@ contract Cache { 从缓存中读取一个值。 ```solidity - // Write a value to the cache if it's not there already - // Only public to enable the test to work + // 如果值尚不存在,则将其写入缓存 + // 仅设为 public 以便测试能够正常工作 function cacheWrite(uint _value) public returns (uint) { - // If the value is already in the cache, return the current key + // 如果值已在缓存中,则返回当前键 if (val2key[_value] != 0) { return val2key[_value]; } ``` -在缓存中多次存储相同的值是没有意义的。 如果值已经存在,只需返回现有的键。 +在缓存中多次存储相同的值是没有意义的。 如果该值已存在,则只返回现有键。 ```solidity - // Since 0xFE is a special case, the largest key the cache can - // hold is 0x0D followed by 15 0xFF's. If the cache length is already that - // large, fail. + // 由于 0xFE 是一个特殊情况,缓存可容纳的最大键 + // 是 0x0D 后跟 15 个 0xFF。如果缓存长度已达 + // 该值,则失败。 // 1 2 3 4 5 6 7 8 9 A B C D E F require(key2val.length+1 < 0x0DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, - "cache overflow"); + "缓存溢出"); ``` -我认为我们永远无法获得如此庞大的缓存(大约 1.8\*1037 个条目,需要大约 1027 TB 的存储空间)。 然而,我知道[“640kB 始终足够了”](https://quoteinvestigator.com/2011/09/08/640k-enough/)。 这一测试非常实惠。 +我认为我们永远不会有这么大的缓存(大约 1.8\*1037 个条目,需要大约 1027 TB 的存储空间)。 然而,我年纪大了,还记得 [“640kB 永远够用”](https://quoteinvestigator.com/2011/09/08/640k-enough/) 这句话。 这个测试的成本非常低。 ```solidity - // Write the value using the next key + // 使用下一个键写入值 val2key[_value] = key2val.length+1; ``` @@ -109,33 +106,33 @@ contract Cache { key2val.push(_value); ``` -添加正向查找(从键到值)。 因为我们按顺序分配值,所以我们可以将其添加在最后一个数组值之后。 +添加正向查找(从键到值)。 因为我们按顺序分配值,所以只需将其添加到最后一个数组值之后即可。 ```solidity return key2val.length; } // cacheWrite ``` -返回 `key2val` 的新长度,该长度表示存储新值的单元格位置。 +返回 `key2val` 的新长度,即存储新值的单元格。 ```solidity function _calldataVal(uint startByte, uint length) private pure returns (uint) ``` -这个函数从任意长度的 calldata(最多 32 个字节,即一个字的大小)中读取一个值。 +该函数从任意长度(最多 32 字节,即一个字的大小)的 calldata 中读取一个值。 ```solidity { uint _retVal; require(length < 0x21, - "_calldataVal length limit is 32 bytes"); + "_calldataVal 长度限制为 32 字节"); require(length + startByte <= msg.data.length, - "_calldataVal trying to read beyond calldatasize"); + "_calldataVal 尝试读取超出 calldatasize 的内容"); ``` -这个函数是内部函数,因此如果其余的代码编写正确,则不需要这些测试。 然而,它们的成本不高,所以不妨拥有它们。 +此函数是内部函数,因此如果其余代码编写正确,则不需要这些测试。 不过,它们的成本不高,所以我们不妨保留它们。 ```solidity assembly { @@ -143,56 +140,56 @@ contract Cache { } ``` -此代码采用 [Yul](https://docs.soliditylang.org/en/v0.8.16/yul.html) 语言。 它从 calldata 中读取一个 32 字节的值。 即使该 calldata 在 `startByte+32` 之前停止,这种方法仍然有效,因为在以太坊虚拟机中,未初始化的空间被视为零。 +此代码使用 [Yul](https://docs.soliditylang.org/en/v0.8.16/yul.html) 编写。 它从 calldata 中读取一个 32 字节的值。 即使该 calldata 在 `startByte+32` 之前停止,这种方法仍然有效,因为在以太坊虚拟机中,未初始化的空间被视为零。 ```solidity _retVal = _retVal >> (256-length*8); ``` -我们并不一定需要一个 32 字节的值。 这将消除多余的字节。 +我们不一定需要一个 32 字节的值。 这将消除多余的字节。 ```solidity return _retVal; } // _calldataVal - // Read a single parameter from the calldata, starting at _fromByte + // 从 calldata 读取单个参数,从 _fromByte 开始 function _readParam(uint _fromByte) internal returns (uint _nextByte, uint _parameterValue) { ``` -从 calldata 中读取单个参数。 请注意,我们需要返回的不仅仅是我们读取的值,还包括下一个字节的位置,因为参数的长度可以从 1 个字节到 33 个字节不等。 +从 calldata 中读取单个参数。 请注意,我们不仅需要返回我们读取的值,还需要返回下一个字节的位置,因为参数的长度可以从 1 字节到 33 字节不等。 ```solidity - // The first byte tells us how to interpret the rest + // 第一个字节告诉我们如何解释其余部分 uint8 _firstByte; _firstByte = uint8(_calldataVal(_fromByte, 1)); ``` -Solidity 试图通过禁止可能危险的[隐式类型转换](https://docs.soliditylang.org/en/v0.8.16/types.html#implicit-conversions)来减少错误的数量。 降级操作,例如从 256 位降级为 8 位,需要为显式。 +Solidity 试图通过禁止有潜在危险的[隐式类型转换](https://docs.soliditylang.org/en/v0.8.16/types.html#implicit-conversions)来减少漏洞数量。 降级操作,例如从 256 位降级为 8 位,需要为显式。 ```solidity - // Read the value, but do not write it to the cache + // 读取值,但不将其写入缓存 if (_firstByte == uint8(DONT_CACHE)) return(_fromByte+33, _calldataVal(_fromByte+1, 32)); - // Read the value, and write it to the cache + // 读取值并将其写入缓存 if (_firstByte == uint8(INTO_CACHE)) { uint _param = _calldataVal(_fromByte+1, 32); cacheWrite(_param); return(_fromByte+33, _param); } - // If we got here it means that we need to read from the cache + // 如果到了这里,意味着我们需要从缓存中读取 - // Number of extra bytes to read + // 要读取的额外字节数 uint8 _extraBytes = _firstByte / 16; ``` -取出低位四位([半字节](https://en.wikipedia.org/wiki/Nibble)),并将其与其他字节组合以从缓存中读取值。 +取低位[半字节](https://en.wikipedia.org/wiki/Nibble)并将其与其他字节组合以从缓存中读取值。 ```solidity uint _key = (uint256(_firstByte & 0x0F) << (8*_extraBytes)) + @@ -203,17 +200,17 @@ Solidity 试图通过禁止可能危险的[隐式类型转换](https://docs.soli } // _readParam - // Read n parameters (functions know how many parameters they expect) + // 读取 n 个参数(函数知道它们需要多少个参数) function _readParams(uint _paramNum) internal returns (uint[] memory) { ``` -我们可以从 calldata 中获取我们拥有的参数数量,但是调用我们的函数知道它们期望的参数数量。 让这些函数告诉我们会更容易一些。 +我们可以从 calldata 本身获取参数数量,但是调用我们的函数知道它们需要多少个参数。 让这些函数告诉我们会更容易一些。 ```solidity - // The parameters we read + // 我们读取的参数 uint[] memory params = new uint[](_paramNum); - // Parameters start at byte 4, before that it's the function signature + // 参数从第 4 个字节开始,在此之前是函数签名 uint _atByte = 4; for(uint i=0; i<_paramNum; i++) { @@ -228,7 +225,7 @@ Solidity 试图通过禁止可能危险的[隐式类型转换](https://docs.soli return(params); } // readParams - // For testing _readParams, test reading four parameters + // 用于测试 _readParams,测试读取四个参数 function fourParam() public returns (uint256,uint256,uint256,uint256) { @@ -238,10 +235,10 @@ Solidity 试图通过禁止可能危险的[隐式类型转换](https://docs.soli } // fourParam ``` -Foundry 的一个重大优势是允许用 Solidity 编写测试([见下文的“测试缓存”](#testing-the-cache))。 这使得单元测试变得更加容易。 这个函数读取四个参数并返回这些参数,以便测试可以验证它们是否正确。 +Foundry 的一个重大优势是允许用 Solidity 编写测试(见下文的[测试缓存](#testing-the-cache))。 这使得单元测试变得更加容易。 这个函数读取四个参数并返回这些参数,以便测试可以验证它们是否正确。 ```solidity - // Get a value, return bytes that will encode it (using the cache if possible) + // 获取一个值,返回将对其进行编码的字节(如有可能,使用缓存) function encodeVal(uint _val) public view returns(bytes memory) { ``` @@ -250,33 +247,33 @@ Foundry 的一个重大优势是允许用 Solidity 编写测试([见下文的 ```solidity uint _key = val2key[_val]; - // The value isn't in the cache yet, add it + // 该值尚不在缓存中,将其添加 if (_key == 0) return bytes.concat(INTO_CACHE, bytes32(_val)); ``` -在[以太坊虚拟机](/developers/docs/evm/)中,所有未初始化的存储被假定为零。 因此,如果我们在查找一个不存在的值的键时,会得到一个零。 在这种情况下,对其进行编码的字节为 `INTO_CACHE`(这样下次将被缓存),接着是实际的值。 +在[以太坊虚拟机](/developers/docs/evm/)中,所有未初始化的存储都被假定为零。 因此,如果我们在查找一个不存在的值的键时,会得到一个零。 在这种情况下,对其进行编码的字节为 `INTO_CACHE`(这样下次将被缓存),接着是实际的值。 ```solidity - // If the key is <0x10, return it as a single byte + // 如果键 <0x10,将其作为单个字节返回 if (_key < 0x10) return bytes.concat(bytes1(uint8(_key))); ``` -单字节是最简单的。 我们使用 [`bytes.concat`](https://docs.soliditylang.org/en/v0.8.16/types.html#the-functions-bytes-concat-and-string-concat) 函数将 `bytes` 类型转换为可以是任意长度的字节数组。 尽管名称如此,但当只提供一个参数时,它仍能正常工作。 +单字节是最简单的。 我们只使用 [`bytes.concat`](https://docs.soliditylang.org/en/v0.8.16/types.html#the-functions-bytes-concat-and-string-concat) 将 `bytes` 类型转换为任意长度的字节数组。 尽管名称如此,但当只提供一个参数时,它仍能正常工作。 ```solidity - // Two byte value, encoded as 0x1vvv + // 两个字节的值,编码为 0x1vvv if (_key < 0x1000) return bytes.concat(bytes2(uint16(_key) | 0x1000)); ``` -当我们有一个小于 163 的键时,我们可以用两个字节来表示它。 我们首先将一个 256 位的值 ` _key` 转换为一个 16 位的值,并使用逻辑“或”将额外字节数添加到第一个字节。 然后我们将其转换为 `bytes2` 值,继而可以转换为 `bytes`。 +当我们有一个小于 163 的键时,我们可以用两个字节来表示它。 我们首先将一个 256 位的值 `_key` 转换为一个 16 位的值,并使用逻辑“或”将额外字节数添加到第一个字节。 然后我们将其转换为 `bytes2` 值,继而可以转换为 `bytes`。 ```solidity - // There is probably a clever way to do the following lines as a loop, - // but it's a view function so I'm optimizing for programmer time and - // simplicity. + // 也许有更巧妙的方法以循环方式实现以下代码行, + // 但这是一个 view 函数,因此我以节省程序员时间和 + // 追求简洁为优化目标。 if (_key < 16*256**2) return bytes.concat(bytes3(uint24(_key) | (0x2 * 16 * 256**2))); @@ -291,14 +288,14 @@ Foundry 的一个重大优势是允许用 Solidity 编写测试([见下文的 return bytes.concat(bytes16(uint128(_key) | (0xF * 16 * 256**15))); ``` -其他的值(例如 3 字节、4 字节等)的处理方式相同,只是字段大小不同。 +其他值(3 字节、4 字节等) 处理方式相同,只是字段大小不同。 ```solidity - // If we get here, something is wrong. - revert("Error in encodeVal, should not happen"); + // 如果到了这一步,说明出错了。 + revert("encodeVal 中出错,不应发生"); ``` -如果到了这一步,意味着我们得到了一个键,其值不小于 16*25615。 但是 `cacheWrite` 对键进行了限制,因此我们甚至无法达到 14\*25616(其首字节为 0xFE,因此看起来像 `DONT_CACHE`)。 添加一个测试来防止未来的开发者引入错误,并不需要太多成本。 +如果到了这一步,意味着我们得到了一个键,其值不小于 16\*25615。 但是 `cacheWrite` 对键进行了限制,因此我们甚至无法达到 14\*25616(其首字节为 0xFE,因此看起来像 `DONT_CACHE`)。 添加一个测试来防止未来的开发者引入错误,并不需要太多成本。 ```solidity } // encodeVal @@ -308,7 +305,7 @@ Foundry 的一个重大优势是允许用 Solidity 编写测试([见下文的 ### 测试缓存 {#testing-the-cache} -Foundry 的一个优势是[允许你使用 Solidity 编写测试](https://book.getfoundry.sh/forge/tests),这使得编写单元测试更加容易。 `Cache` 类的测试可以在[此处](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/test/Cache.t.sol)找到。 由于测试代码通常会有很多重复的部分,本文仅说明有趣的部分。 +Foundry 的一个优点是[它允许你用 Solidity 编写测试](https://getfoundry.sh/forge/tests/overview/),这让单元测试的编写变得更容易。 `Cache` 类的测试[在此处](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/test/Cache.t.sol)。 由于测试代码通常会有很多重复的部分,本文仅说明有趣的部分。 ```solidity // SPDX-License-Identifier: UNLICENSED @@ -317,7 +314,7 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; -// Need to run `forge test -vv` for the console. +// 需要运行 `forge test -vv` 以便使用控制台。 import "forge-std/console.sol"; ``` @@ -344,7 +341,7 @@ contract CacheTest is Test { function testCaching() public { ``` -测试是以 `test` 开头的函数。 该函数检查基本的缓存功能,写入值并再次读取这些值。 +测试是名称以 `test` 开头的函数。 该函数检查基本的缓存功能,写入值并再次读取这些值。 ```solidity for(uint i=1; i<5000; i++) { @@ -355,15 +352,15 @@ contract CacheTest is Test { assertEq(cache.cacheRead(i), i*i); ``` -这是你进行实际测试时使用的方法,使用 [`assert...` 函数](https://book.getfoundry.sh/reference/forge-std/std-assertions)。 在这种情况下,我们检查我们写入的值是否是我们读取的值。 我们可以忽略 `cache.cacheWrite` 的结果,因为我们知道缓存键是按线性分配的。 +这是你使用 [`assert...` 函数](https://getfoundry.sh/reference/forge-std/std-assertions/)进行实际测试的方式。 在这种情况下,我们检查我们写入的值是否是我们读取的值。 我们可以忽略 `cache.cacheWrite` 的结果,因为我们知道缓存键是按线性分配的。 ```solidity } } // testCaching - // Cache the same value multiple times, ensure that the key stays - // the same + // 多次缓存相同的值,确保键保持 + // 相同 function testRepeatCaching() public { for(uint i=1; i<100; i++) { uint _key1 = cache.cacheWrite(i); @@ -385,8 +382,8 @@ contract CacheTest is Test { 理论上,这是一种不会影响连续缓存写入的错误。 所以在这里,我们进行一些非连续的写入操作,并看到值仍然没有被重新写入。 ```solidity - // Read a uint from a memory buffer (to make sure we get back the parameters - // we sent out) + // 从内存缓冲区中读取一个 uint(以确保我们得到 + // 我们发出的参数) function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) ``` @@ -403,18 +400,18 @@ contract CacheTest is Test { } ``` -Yul 不支持超出 `uint256` 的数据结构,因此当你引用更复杂的数据结构,例如内存缓冲区 `_bytes` 时,你会得到该结构的地址。 Solidity 将 `bytes memory` 类型的值存储为一个 32 字节的字,其中包含长度信息,后跟实际的字节。因此,要获取字节数量 `_start`,我们需要计算 `_bytes+32+_start`。 +Yul 不支持 `uint256` 以外的数据结构,因此当你引用更复杂的数据结构(例如内存缓冲区 `_bytes`)时,你会得到该结构的地址。 Solidity 将 `bytes memory` 类型的值存储为一个 32 字节的字,其中包含长度信息,后跟实际的字节。因此,要获取字节数量 `_start`,我们需要计算 `_bytes+32+_start`。 ```solidity return tempUint; } // toUint256 - // Function signature for fourParams(), courtesy of - // https://www.4byte.directory/signatures/?bytes4_signature=0x3edc1e6d + // fourParams() 的函数签名,由 + // https://www.4byte.directory/signatures/?bytes4_signature=0x3edc1e6d 提供 bytes4 constant FOUR_PARAMS = 0x3edc1e6d; - // Just some constant values to see we're getting the correct values back + // 仅是一些常量值,用于查看我们是否收到了正确的值 uint256 constant VAL_A = 0xDEAD60A7; uint256 constant VAL_B = 0xBEEF; uint256 constant VAL_C = 0x600D; @@ -439,15 +436,15 @@ Yul 不支持超出 `uint256` 的数据结构,因此当你引用更复杂的 我们无法使用普通的应用程序二进制接口机制来调用使用缓存的函数,因此我们需要使用低级别的 [`
.call()`](https://docs.soliditylang.org/en/v0.8.16/types.html#members-of-addresses) 机制。 该机制接受一个 `bytes memory` 类型的输入,并将其作为输出返回(同时返回一个布尔值)。 ```solidity - // First call, the cache is empty + // 第一次调用,缓存为空 _callInput = bytes.concat( FOUR_PARAMS, ``` -对于同一个合约来说,支持缓存函数(用于从交易直接调用)和非缓存函数(用于从其他智能合约调用)是很有用的。 为了做到这一点,我们需要继续依赖 Solidity 机制来调用正确的函数,而不是将所有内容放在一个 [`feedback` 函数](https://docs.soliditylang.org/en/v0.8.16/contracts.html#fallback-function)中。 这样做可以大大简化可组合性的实现。 在大多数情况下,一个字节就足够标识函数了,所以我们浪费了三个字节(16\*3= 48 单位燃料)。 然而,就我撰写此文时而言,这 48 单位燃料的成本为 0.07 美分,对于更简单、错误更少的代码而言,这是合理的成本。 +对于同一个合约来说,支持缓存函数(用于从交易直接调用)和非缓存函数(用于从其他智能合约调用)是很有用的。 为了做到这一点,我们需要继续依赖 Solidity 机制来调用正确的函数,而不是将所有内容放在一个[“回退”函数](https://docs.soliditylang.org/en/v0.8.16/contracts.html#fallback-function)中。 这样做可以大大简化可组合性的实现。 在大多数情况下,一个字节就足够标识函数了,所以我们浪费了三个字节(16\*3= 48 单位燃料)。 然而,就我撰写此文时而言,这 48 单位燃料的成本为 0.07 美分,对于更简单、错误更少的代码而言,这是合理的成本。 ```solidity - // First value, add it to the cache + // 第一个值,将其添加到缓存 cache.INTO_CACHE(), bytes32(VAL_A), ``` @@ -487,22 +484,22 @@ Yul 不支持超出 `uint256` 的数据结构,因此当你引用更复杂的 输出为四个参数。 在这里,我们验证其是否正确。 ```solidity - // Second call, we can use the cache + // 第二次调用,我们可以使用缓存 _callInput = bytes.concat( FOUR_PARAMS, - // First value in the Cache + // 缓存中的第一个值 bytes1(0x01), ``` 小于 16 的缓存键只占用一个字节。 ```solidity - // Second value, don't add it to the cache + // 第二个值,不将其添加到缓存 cache.DONT_CACHE(), bytes32(VAL_B), - // Third and fourth values, same value + // 第三和第四个值,值相同 bytes1(0x02), bytes1(0x02) ); @@ -541,18 +538,18 @@ Yul 不支持超出 `uint256` 的数据结构,因此当你引用更复杂的 `testEncodeVal()` 中唯一的附加测试是验证 `_callInput` 的长度是否正确。 对于第一次调用,长度为 4+33\*4。 对于第二次调用,其中每个值已经存在于缓存中,长度为 4+1\*4。 ```solidity - // Test encodeVal when the key is more than a single byte - // Maximum three bytes because filling the cache to four bytes takes - // too long. + // 当键超过一个字节时测试 encodeVal + // 最多三个字节,因为填满缓存到四个字节需要 + // 太长时间。 function testEncodeValBig() public { - // Put a number of values in the cache. - // To keep things simple, use key n for value n. + // 在缓存中放入一些值。 + // 为简单起见,对值 n 使用键 n。 for(uint i=1; i<0x1FFF; i++) { cache.cacheWrite(i); } ``` -上述 `testEncodeVal` 函数只将四个值写入缓存中,因此并未检查[处理多字节值的函数部分](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/Cache.sol#L144-L171)。 但是那段代码很复杂且容易出错。 +上述 `testEncodeVal` 函数只将四个值写入缓存中,因此[处理多字节值的函数部分](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/Cache.sol#L144-L171)并未得到检查。 但是那段代码很复杂且容易出错。 该函数的第一部分是一个循环,这个循环将从 1 到 0x1FFF 的所有值按顺序写入缓存,因此我们将能够对这些值进行编码并知道这些值的去向。 @@ -563,10 +560,10 @@ Yul 不支持超出 `uint256` 的数据结构,因此当你引用更复杂的 _callInput = bytes.concat( FOUR_PARAMS, - cache.encodeVal(0x000F), // One byte 0x0F - cache.encodeVal(0x0010), // Two bytes 0x1010 - cache.encodeVal(0x0100), // Two bytes 0x1100 - cache.encodeVal(0x1000) // Three bytes 0x201000 + cache.encodeVal(0x000F), // 一字节 0x0F + cache.encodeVal(0x0010), // 两字节 0x1010 + cache.encodeVal(0x0100), // 两字节 0x1100 + cache.encodeVal(0x1000) // 三字节 0x201000 ); ``` @@ -580,7 +577,7 @@ Yul 不支持超出 `uint256` 的数据结构,因此当你引用更复杂的 } // testEncodeValBig - // Test what with an excessively small buffer we get a revert + // 测试使用过小的缓冲区时,我们会得到一个回滚 function testShortCalldata() public { ``` @@ -598,7 +595,7 @@ Yul 不支持超出 `uint256` 的数据结构,因此当你引用更复杂的 由于发生了回滚,我们应该得到的结果是 `false`。 ``` - // Call with cache keys that aren't there + // 使用不存在的缓存键调用 function testNoCacheKey() public { . . @@ -606,11 +603,11 @@ Yul 不支持超出 `uint256` 的数据结构,因此当你引用更复杂的 _callInput = bytes.concat( FOUR_PARAMS, - // First value, add it to the cache + // 第一个值,将其添加到缓存 cache.INTO_CACHE(), bytes32(VAL_A), - // Second value + // 第二个值 bytes1(0x0F), bytes2(0x1234), bytes11(0xA10102030405060708090A) @@ -623,30 +620,30 @@ Yul 不支持超出 `uint256` 的数据结构,因此当你引用更复杂的 . . . - // Test what with an excessively long buffer everything works file + // 测试缓冲区过长时,所有操作都能正常工作 function testLongCalldata() public { address _cacheAddr = address(cache); bool _success; bytes memory _callInput; bytes memory _callOutput; - // First call, the cache is empty + // 第一次调用,缓存为空 _callInput = bytes.concat( FOUR_PARAMS, - // First value, add it to the cache + // 第一个值,将其添加到缓存 cache.INTO_CACHE(), bytes32(VAL_A), - // Second value, add it to the cache + // 第二个值,将其添加到缓存 cache.INTO_CACHE(), bytes32(VAL_B), - // Third value, add it to the cache + // 第三个值,将其添加到缓存 cache.INTO_CACHE(), bytes32(VAL_C), - // Fourth value, add it to the cache + // 第四个值,将其添加到缓存 cache.INTO_CACHE(), bytes32(VAL_D), - // And another value for "good luck" + // 另外一个值用于“祝你好运” bytes4(0x31112233) ); ``` @@ -665,13 +662,13 @@ Yul 不支持超出 `uint256` 的数据结构,因此当你引用更复杂的 ``` -## 一个应用示例 {#a-sample-app} +## 示例应用程序 {#a-sample-app} -使用 Solidity 语言来编写测试非常重要,但最终,一个去中心化应用程序需要能够处理来自链外的请求才能发挥其实用性。 本文演示了如何在去中心化应用程序中使用缓存,其中使用了 `WORM`(Write Once, Read Many,写入一次,读取多次)的概念。 如果一个键尚未被写入,你可以向其写入一个值。 如果该键已被写入,你可以进行回滚。 +用 Solidity 编写测试固然很好,但归根结底,一个去中心化应用程序需要能够处理来自链外的请求才算有用。 本文演示了如何在去中心化应用程序中使用缓存,其中使用了 WORM(Write Once, Read Many,写入一次,读取多次)的概念。 如果一个键尚未被写入,你可以向其写入一个值。 如果该键已被写入,你可以进行回滚。 ### 合约 {#the-contract} -[这就是合约](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/WORM.sol)。 这主要重复了我们已经完成的 `Cache` 和 `CacheTest` 部分内容,因此我们只涵盖有趣的部分。 +[这是合约](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/src/WORM.sol)。 这主要重复了我们已经完成的 `Cache` 和 `CacheTest` 部分内容,因此我们只涵盖有趣的部分。 ```solidity import "./Cache.sol"; @@ -688,12 +685,12 @@ contract WORM is Cache { } // writeEntryCached ``` -此函数与上面的 `CacheTest` 中的 `fourParam` 函数类似。 由于我们并未遵循 ABI 规范,最好不要在函数中声明任何参数。 +此函数与上面的 `CacheTest` 中的 `fourParam` 函数类似。 由于我们并未遵循应用程序二进制接口规范,最好不要在函数中声明任何参数。 ```solidity - // Make it easier to call us - // Function signature for writeEntryCached(), courtesy of - // https://www.4byte.directory/signatures/?bytes4_signature=0xe4e4f2d3 + // 使我们更易于调用 + // writeEntryCached() 的函数签名,由 + // https://www.4byte.directory/signatures/?bytes4_signature=0xe4e4f2d3 提供 bytes4 constant public WRITE_ENTRY_CACHED = 0xe4e4f2d3; ``` @@ -720,7 +717,7 @@ Read 函数是一个 `view` 函数,因此它不需要进行交易,并且不 worm.writeEntry(0xDEAD, 0xBEEF); ``` -[此 (`vm.expectRevert`)](https://book.getfoundry.sh/cheatcodes/expect-revert#expectrevert) 是我们如何在 Foundry 测试中指定下一次调用应该失败,以及报告的失败原因。 这适用于我们使用语法 `.()` 而不是构建 calldata 并使用低级别接口来调用合约(`.call()` 等)的情况。 +在 Foundry 测试中,我们通过[此 (`vm.expectRevert`)](https://book.getfoundry.sh/cheatcodes/expect-revert#expectrevert) 来指定下一次调用应该失败,以及报告的失败原因。 这适用于我们使用语法 `.()` 而不是构建 calldata 并使用低级别接口来调用合约(`.call()` 等)的情况。 ```solidity function testReadWriteCached() public { @@ -756,13 +753,13 @@ Read 函数是一个 `view` 函数,因此它不需要进行交易,并且不 (_success,) = address(worm).call(_callInput); ``` -这是我们在 Foundry 中验证代码[正确触发事件](https://book.getfoundry.sh/cheatcodes/expect-emit)的方式。 +在 Foundry 中,我们以这种方式来验证代码是否[正确触发了事件](https://getfoundry.sh/reference/cheatcodes/expect-emit/)。 ### 客户端 {#the-client} -在 Solidity 测试中,你无法得到可以复制粘贴到你自己应用程序中的 JavaScript 代码。 为了编写那段代码,我将 WORM 部署到 [Optimism Goerli](https://community.optimism.io/docs/useful-tools/networks/#optimism-goerli),这是 [Optimism](https://www.optimism.io/) 的新测试网络。 地址为 [`0xd34335b1d818cee54e3323d3246bd31d94e6a78a`](https://goerli-optimism.etherscan.io/address/0xd34335b1d818cee54e3323d3246bd31d94e6a78a)。 +在 Solidity 测试中,你无法得到可以复制粘贴到你自己应用程序中的 JavaScript 代码。 为了编写该代码,我将 WORM 部署到 [Optimism Goerli](https://community.optimism.io/docs/useful-tools/networks/#optimism-goerli)([Optimism](https://www.optimism.io/) 的新测试网)。 其地址为 [`0xd34335b1d818cee54e3323d3246bd31d94e6a78a`](https://goerli-optimism.etherscan.io/address/0xd34335b1d818cee54e3323d3246bd31d94e6a78a)。 -[你可以在这里看到客户端的 JavaScript 代码](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/javascript/index.js)。 要使用该代码: +[你可在此处查看客户端的 JavaScript 代码](https://github.com/qbzzt/20220915-all-you-can-cache/blob/main/javascript/index.js)。 要使用该代码: 1. 克隆 git 存储库: @@ -785,10 +782,10 @@ Read 函数是一个 `view` 函数,因此它不需要进行交易,并且不 4. 编辑 `.env` 文件以进行配置: - | 参数 | 值 | - | --------------------- | ---------------------------------------------------------------------------------------- | - | MNEMONIC | 持有足够以太币来支付交易费用的帐户的助记词。 [你可以在此处免费获取 Optimism Goerli 网络的以太币](https://optimismfaucet.xyz/)。 | - | OPTIMISM_GOERLI_URL | Optimism Goerli 的 URL。 公共端点 `https://goerli.optimism.io` 存在速率限制,但能够满足我们此处的需求 | + | 参数 | Value | + | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | + | MNEMONIC | 拥有足够 ETH 支付交易费用的帐户的助记词。 [你可以在此处免费获取 Optimism Goerli 网络的 ETH](https://optimismfaucet.xyz/)。 | + | OPTIMISM_GOERLI_URL | Optimism Goerli 的 URL。 公共端点 `https://goerli.optimism.io` 存在速率限制,但能够满足我们此处的需求 | 5. 运行 `index.js`。 @@ -807,7 +804,7 @@ Read 函数是一个 `view` 函数,因此它不需要进行交易,并且不 const main = async () => { const func = await worm.WRITE_ENTRY_CACHED() - // Need a new key every time + // 每次都需要一个新键 const key = await worm.encodeVal(Number(new Date())) ``` @@ -816,11 +813,11 @@ const main = async () => { ```javascript const val = await worm.encodeVal("0x600D") -// Write an entry +// 写入一个条目 const calldata = func + key.slice(2) + val.slice(2) ``` -Ethers 期望调用数据是一个十六进制字符串,即以 `0x` 开头,后跟偶数个十六进制数字。 由于 `key` 和 `val` 都以 `0x` 开头,我们需要去除这些头部信息。 +Ethers 期望调用数据是一个十六进制字符串,即 `0x` 后跟偶数个十六进制数字。 由于 `key` 和 `val` 都以 `0x` 开头,我们需要去除这些头部信息。 ```javascript const tx = await worm.populateTransaction.writeEntryCached() @@ -835,8 +832,8 @@ sentTx = await wallet.sendTransaction(tx) . . . - // Read the entry just written - const realKey = '0x' + key.slice(4) // remove the FF flag + // 读取刚写入的条目 + const realKey = '0x' + key.slice(4) // 移除 FF 标志 const entryRead = await worm.readEntry(realKey) . . @@ -856,12 +853,15 @@ sentTx = await wallet.sendTransaction(tx) 然而,这是一个潜在的危险操作。 设想以下事件序列: - 1. Noam Naive 调用 `encodeVal` 函数来对他想要向其中发送代币的地址进行编码。 该地址是应用程序中使用的最早一批地址之一,因此编码值为 0x06。 这是一个 `view` 函数,而不是一个交易,发生于 Noam 和他使用的节点之间,而其他人则对此毫不知情。 + 1. Noam Naive 调用 `encodeVal` 来对他想发送代币的目标地址进行编码。 该地址是应用程序中使用的最早一批地址之一,因此编码值为 0x06。 这是一个 `view` 函数,而不是一个交易,发生于 Noam 和他使用的节点之间,而其他人则对此毫不知情。 2. Owen Owner 运行缓存重排序操作。 实际上,很少有人会使用那个地址,所以现在它被编码为 0x201122。 另一个数值,1018,被赋值为 0x06。 - 3. Noam Naive 将他的代币发送到了 0x06 地址。 它们被发送到地址 `0x0000000000000000000000000de0b6b3a7640000`,由于没有人知道该地址的私钥,这些代币将永远留在那里。 Noam _不开心_。 + 3. Noam Naive 将他的代币发送到了 0x06。 代币被发送到地址 `0x0000000000000000000000000de0b6b3a7640000`,由于没人知道该地址的私钥,这些代币就被困在那里了。 Noam _很不开心_。 - 虽然有多种方法可以解决此问题,以及解决与缓存重新排序期间内存池中的交易相关的问题,但你必须对此有所了解。 + 有办法可以解决这个问题,以及在缓存重新排序期间交易位于内存池中的相关问题,但你必须意识到这一点。 由于我是 Optimism 的员工,这是我最熟悉的卷叠,所以这里我展示了使用 Optimism 进行缓存。 但是,对于任何内部处理费用较低的卷叠方案,这个方法应该是有效的,因为相比之下,将交易数据写入一层网络是主要费用。 + +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 + diff --git a/public/content/translations/zh/developers/tutorials/app-plasma/index.md b/public/content/translations/zh/developers/tutorials/app-plasma/index.md new file mode 100644 index 00000000000..1b07e2fa457 --- /dev/null +++ b/public/content/translations/zh/developers/tutorials/app-plasma/index.md @@ -0,0 +1,1255 @@ +--- +title: "编写一个保护隐私的应用程序专用 Plasma" +description: "在本教程中,我们将构建一个用于存款的半保密银行。 该银行是一个中心化组件,它知道每个用户的余额。 但是,此信息不会存储在链上。 银行会发布状态的哈希值。 每当发生交易时,银行都会发布新的哈希值,以及一个零知识证明,证明其拥有一个已签名的交易,可将哈希状态更改为新状态。 阅读本教程后,您不仅会了解如何使用零知识证明,还会了解为什么要使用它们以及如何安全地使用。" +author: Ori Pomerantz +tags: [ "零知识", "服务器", "链下", "隐私" ] +skill: advanced +lang: zh +published: 2025-10-15 +--- + +## 简介 {#introduction} + +与 [Rollup](/developers/docs/scaling/zk-rollups/) 相反,[Plasma](/developers/docs/scaling/plasma) 使用以太坊主网保证完整性,但不保证可用性。 在本文中,我们编写了一个行为类似于 Plasma 的应用程序,其中以太坊保证完整性(未经授权的更改),但不保证可用性(中心化组件可能宕机并禁用整个系统)。 + +我们在此编写的应用程序是一个保护隐私的银行。 不同的地址拥有带余额的帐户,它们可以向其他帐户发送资金 (ETH)。 银行会发布状态(帐户及其余额)和交易的哈希值,但会将实际余额保留在链下,以保持隐私。 + +## 设计 {#design} + +这不是一个生产就绪的系统,而是一个教学工具。 因此,它是基于几个简化的假设编写的。 + +- 固定帐户池。 帐户数量是特定的,每个帐户都属于一个预定地址。 这使得系统更加简单,因为在零知识证明中处理可变大小的数据结构很困难。 对于生产就绪系统,我们可以使用 [Merkle 根](/developers/tutorials/merkle-proofs-for-offline-data-integrity/)作为状态哈希,并为所需余额提供 Merkle 证明。 + +- 内存存储。 在生产系统中,我们需要将所有帐户余额写入磁盘,以在重启时保留它们。 在这里,如果信息丢失了也没关系。 + +- 仅限转账。 生产系统需要一种将资产存入银行和取款的方式。 但这里的目的只是为了说明概念,所以这家银行仅限于转账。 + +### 零知识证明 {#zero-knowledge-proofs} + +在基本层面上,零知识证明表明证明者知道一些数据 _Dataprivate_,使得一些公共数据 _Datapublic_ 和 _Dataprivate_ 之间存在关系 _Relationship_。 验证者知道 _Relationship_ 和 _Datapublic_。 + +为了保护隐私,我们需要将状态和交易设为私有。 但为了确保完整性,我们需要将状态的[加密哈希](https://en.wikipedia.org/wiki/Cryptographic_hash_function)设为公开。 为了向提交交易的人证明这些交易确实发生过,我们还需要发布交易哈希。 + +在大多数情况下,_Dataprivate_ 是零知识证明程序的输入,而 _Datapublic_ 是输出。 + +_Dataprivate_ 中的这些字段: + +- _Staten_,旧状态 +- _Staten+1_,新状态 +- _Transaction_,一个将旧状态更改为新状态的交易。 此交易需要包含以下字段: + - _目标地址_,接收转账的地址 + - _金额_,正在转账的金额 + - _Nonce_,用于确保每笔交易只能处理一次。 + 源地址不需要在交易中,因为可以从签名中恢复。 +- _签名_,一个被授权执行交易的签名。 在我们的案例中,唯一被授权执行交易的地址是源地址。 因为我们的零知识系统的工作方式,除了以太坊签名之外,我们还需要帐户的公钥。 + +_Datapublic_ 中的字段如下: + +- _Hash(Staten)_,旧状态的哈希 +- _Hash(Staten+1)_,新状态的哈希 +- _Hash(Transaction)_,将状态从 _Staten_ 更改为 _Staten+1_ 的交易哈希。 + +该关系检查了几个条件: + +- 公共哈希确实是私有字段的正确哈希。 +- 当交易应用于旧状态时,会产生新状态。 +- 签名来自交易的源地址。 + +由于加密哈希函数的特性,证明这些条件足以确保完整性。 + +### 数据结构 {#data-structures} + +主要的数据结构是服务器持有的状态。 对于每个帐户,服务器会跟踪帐户余额和一个 [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce),用于防止[重放攻击](https://en.wikipedia.org/wiki/Replay_attack)。 + +### 组件 {#components} + +该系统需要两个组件: + +- 接收交易、处理交易并将哈希与零知识证明一起发布到链上的_服务器_。 +- 一个存储哈希并验证零知识证明以确保状态转换合法的_智能合约_。 + +### 数据和控制流 {#flows} + +这些是各种组件之间进行通信以实现从一个帐户到另一个帐户的转账的方式。 + +1. Web 浏览器提交一个已签名的交易,请求从签名者的帐户向另一个帐户转账。 + +2. 服务器验证交易是否有效: + + - 签名者在银行中拥有一个有足够余额的帐户。 + - 收款人在银行中拥有一个帐户。 + +3. 服务器通过从签名者的余额中减去转账金额并将其加到收款人的余额中来计算新状态。 + +4. 服务器计算一个零知识证明,证明状态变更是有效的。 + +5. 服务器向以太坊提交一笔交易,其中包括: + + - 新状态哈希 + - 交易哈希(以便交易发送者知道它已被处理) + - 证明向新状态的转换有效的零知识证明 + +6. 智能合约验证零知识证明。 + +7. 如果零知识证明通过验证,智能合约将执行以下操作: + - 将当前状态哈希更新为新状态哈希 + - 发出一个包含新状态哈希和交易哈希的日志条目 + +### 工具 {#tools} + +对于客户端代码,我们将使用 [Vite](https://vite.dev/)、[React](https://react.dev/)、[Viem](https://viem.sh/) 和 [Wagmi](https://wagmi.sh/)。 这些是行业标准工具;如果你不熟悉它们,可以使用[本教程](/developers/tutorials/creating-a-wagmi-ui-for-your-contract/)。 + +服务器的大部分是使用 [Node](https://nodejs.org/en) 以 JavaScript 编写的。 零知识部分是用 [Noir](https://noir-lang.org/) 编写的。 我们需要 `1.0.0-beta.10` 版本,所以在您[按照指示安装 Noir](https://noir-lang.org/docs/getting_started/quick_start) 后,运行: + +``` +noirup -v 1.0.0-beta.10 +``` + +我们使用的区块链是 `anvil`,这是一个本地测试区块链,属于 [Foundry](https://getfoundry.sh/introduction/installation) 的一部分。 + +## 实现 {#implementation} + +因为这是一个复杂的系统,我们将分阶段实现它。 + +### 第 1 阶段 - 手动零知识 {#stage-1} + +在第一阶段,我们将在浏览器中签署一笔交易,然后手动将信息提供给零知识证明。 零知识代码期望在 `server/noir/Prover.toml` 中获取该信息(文档在[此处](https://noir-lang.org/docs/getting_started/project_breakdown#provertoml-1))。 + +要查看实际操作: + +1. 确保您已安装 [Node](https://nodejs.org/en/download) 和 [Noir](https://noir-lang.org/install)。 最好将它们安装在 UNIX 系统上,例如 macOS、Linux 或 [WSL](https://learn.microsoft.com/en-us/windows/wsl/install)。 + +2. 下载阶段 1 的代码并启动 Web 服务器以提供客户端代码。 + + ```sh + git clone https://github.com/qbzzt/250911-zk-bank.git -b 01-manual-zk + cd 250911-zk-bank + cd client + npm install + npm run dev + ``` + + 这里需要一个 Web 服务器的原因是,为了防止某些类型的欺诈,许多钱包(例如 MetaMask)不接受直接从磁盘提供的文件 + +3. 用钱包打开浏览器。 + +4. 在钱包中,输入一个新的密码短语。 请注意,这将删除您现有的密码短语,因此_请确保您有备份_。 + + 密码短语是 `test test test test test test test test test test test junk`,这是 anvil 的默认测试密码短语。 + +5. 浏览到[客户端代码](http://localhost:5173/)。 + +6. 连接到钱包并选择您的目标帐户和金额。 + +7. 点击 **Sign** 并签署交易。 + +8. 在 **Prover.toml** 标题下,您会找到文本。 用该文本替换 `server/noir/Prover.toml`。 + +9. 执行零知识证明。 + + ```sh + cd ../server/noir + nargo execute + ``` + + 输出应类似于 + + ``` + ori@CryptoDocGuy:~/noir/250911-zk-bank/server/noir$ nargo execute + + [zkBank] Circuit witness successfully solved + [zkBank] Witness saved to target/zkBank.gz + [zkBank] Circuit output: (0x199aa62af8c1d562a6ec96e66347bf3240ab2afb5d022c895e6bf6a5e617167b, 0x0cfc0a67cb7308e4e9b254026b54204e34f6c8b041be207e64c5db77d95dd82d, 0x450cf9da6e180d6159290554ae3d8787, 0x6d8bc5a15b9037e52fb59b6b98722a85) + ``` + +10. 将最后两个值与您在 Web 浏览器上看到的哈希进行比较,以查看消息是否已正确哈希。 + +#### `server/noir/Prover.toml` {#server-noir-prover-toml} + +[此文件](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/server/noir/Prover.toml) 显示了 Noir 期望的信息格式。 + +```toml +message="send 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 500 finney (milliEth) 0 " +``` + +消息采用文本格式,这使得用户易于理解(在签名时是必要的),也便于 Noir 代码解析。 金额以 finney 为单位,一方面可以实现小数额转账,另一方面也易于阅读。 最后一个数字是 [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce)。 + +字符串长度为 100 个字符。 零知识证明不能很好地处理可变大小的数据,因此通常需要填充数据。 + +```toml +pubKeyX=["0x83",...,"0x75"] +pubKeyY=["0x35",...,"0xa5"] +signature=["0xb1",...,"0x0d"] +``` + +这三个参数是固定大小的字节数组。 + +```toml +[[accounts]] +address="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +balance=100_000 +nonce=0 + +[[accounts]] +address="0x70997970C51812dc3A010C7d01b50e0d17dc79C8" +balance=100_000 +nonce=0 +``` + +这是指定结构数组的方式。 对于每个条目,我们指定地址、余额(以 milliETH 为单位,又称 [finney](https://cryptovalleyjournal.com/glossary/finney/)) 和下一个 nonce 值。 + +#### `client/src/Transfer.tsx` {#client-src-transfer-tsx} + +[此文件](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/client/src/Transfer.tsx) 实现了客户端处理,并生成 `server/noir/Prover.toml` 文件(包含零知识参数的文件)。 + +以下是更有趣部分的解释。 + +```tsx +export default attrs => { +``` + +此函数创建 `Transfer` React 组件,其他文件可以导入该组件。 + +```tsx + const accounts = [ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "0x90F79bf6EB2c4f870365E785982E1f101E93b906", + "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65", + ] +``` + +这些是帐户地址,由 `test ...` test junk` 密码短语创建的地址。 如果您想使用自己的地址,只需修改此定义即可。 + +```tsx + const account = useAccount() + const wallet = createWalletClient({ + transport: custom(window.ethereum!) + }) +``` + +这些 [Wagmi 钩子](https://wagmi.sh/react/api/hooks) 让我们能够访问 [viem](https://viem.sh/) 库和钱包。 + +```tsx + const message = `send ${toAccount} ${ethAmount*1000} finney (milliEth) ${nonce}`.padEnd(100, " ") +``` + +这是用空格填充的消息。 每次 [`useState`](https://react.dev/reference/react/useState) 变量之一发生变化时,组件都会重新绘制,`message` 也会更新。 + +```tsx + const sign = async () => { +``` + +当用户点击 **Sign** 按钮时,此函数将被调用。 消息会自动更新,但签名需要用户在钱包中批准,除非必要,否则我们不想请求它。 + +```tsx + const signature = await wallet.signMessage({ + account: fromAccount, + message, + }) +``` + +要求钱包[签署消息](https://viem.sh/docs/accounts/local/signMessage)。 + +```tsx + const hash = hashMessage(message) +``` + +获取消息哈希。 将其提供给用户以进行调试(Noir 代码的调试)会很有帮助。 + +```tsx + const pubKey = await recoverPublicKey({ + hash, + signature + }) +``` + +[获取公钥](https://viem.sh/docs/utilities/recoverPublicKey)。 这是 [Noir `ecrecover`](https://github.com/colinnielsen/ecrecover-noir) 函数所必需的。 + +```tsx + setSignature(signature) + setHash(hash) + setPubKey(pubKey) +``` + +设置状态变量。 这样做会重新绘制组件(在 `sign` 函数退出后)并向用户显示更新后的值。 + +```tsx + let proverToml = ` +``` + +`Prover.toml` 的文本。 + +```tsx +message="${message}" + +pubKeyX=${hexToArray(pubKey.slice(4,4+2*32))} +pubKeyY=${hexToArray(pubKey.slice(4+2*32))} +``` + +Viem 以 65 字节十六进制字符串的形式为我们提供公钥。 第一个字节是 `0x04`,一个版本标记。 后面是公钥的 `x` 的 32 个字节,然后是公钥的 `y` 的 32 个字节。 + +然而,Noir 期望以两个字节数组的形式获取此信息,一个用于 `x`,一个用于 `y`。 在客户端解析它比在零知识证明中解析它更容易。 + +请注意,这通常是零知识中的良好实践。 零知识证明内部的代码是昂贵的,因此任何可以在零知识证明外部完成的处理_都应该_在零知识证明外部完成。 + +```tsx +signature=${hexToArray(signature.slice(2,-2))} +``` + +签名也以 65 字节的十六进制字符串形式提供。 但是,最后一个字节仅用于恢复公钥。 由于公钥已经提供给 Noir 代码,我们不需要它来验证签名,Noir 代码也不需要它。 + +```tsx +${accounts.map(accountInProverToml).reduce((a,b) => a+b, "")} +` +``` + +提供帐户。 + +```tsx + setProverToml(proverToml) + } + + return ( + <> +

转账

+``` + +这是组件的 HTML(更准确地说,是 [JSX](https://react.dev/learn/writing-markup-with-jsx))格式。 + +#### `server/noir/src/main.nr` {#server-noir-src-main-nr} + +[此文件](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/server/noir/src/main.nr)是实际的零知识代码。 + +``` +use std::hash::pedersen_hash; +``` + +[Pedersen 哈希](https://rya-sge.github.io/access-denied/2024/05/07/pedersen-hash-function/)由 [Noir 标准库](https://noir-lang.org/docs/noir/standard_library/cryptographic_primitives/hashes#pedersen_hash)提供。 零知识证明通常使用此哈希函数。 与标准哈希函数相比,在[算术电路](https://rareskills.io/post/arithmetic-circuit)中计算要容易得多。 + +``` +use keccak256::keccak256; +use dep::ecrecover; +``` + +这两个函数是外部库,在 [`Nargo.toml`](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/server/noir/Nargo.toml) 中定义。 它们的功能正如其名,一个函数用于计算 [keccak256 哈希](https://emn178.github.io/online-tools/keccak_256.html),另一个函数用于验证以太坊签名并恢复签名者的以太坊地址。 + +``` +global ACCOUNT_NUMBER : u32 = 5; +``` + +Noir 受到了 [Rust](https://www.rust-lang.org/) 的启发。 默认情况下,变量是常量。 这就是我们定义全局配置常量的方式。 具体来说,`ACCOUNT_NUMBER` 是我们存储的帐户数量。 + +`u` 命名的数据类型是该位数的无符号整数。 唯一支持的类型是 `u8`、`u16`、`u32`、`u64` 和 `u128`。 + +``` +global FLAT_ACCOUNT_FIELDS : u32 = 2; +``` + +如下文所述,此变量用于帐户的 Pedersen 哈希。 + +``` +global MESSAGE_LENGTH : u32 = 100; +``` + +如上所述,消息长度是固定的。 在此处指定。 + +``` +global ASCII_MESSAGE_LENGTH : [u8; 3] = [0x31, 0x30, 0x30]; +global HASH_BUFFER_SIZE : u32 = 26+3+MESSAGE_LENGTH; +``` + +[EIP-191 签名](https://eips.ethereum.org/EIPS/eip-191) 需要一个带有 26 字节前缀的缓冲区,后跟 ASCII 格式的消息长度,最后是消息本身。 + +``` +struct Account { + balance: u128, + address: Field, + nonce: u32, +} +``` + +我们存储的关于一个帐户的信息。 [`Field`](https://noir-lang.org/docs/noir/concepts/data_types/fields) 是一个数字,通常最多 253 位,可以直接用于实现零知识证明的[算术电路](https://rareskills.io/post/arithmetic-circuit)。 这里我们使用 `Field` 来存储一个 160 位的以太坊地址。 + +``` +struct TransferTxn { + from: Field, + to: Field, + amount: u128, + nonce: u32 +} +``` + +我们为一笔转账交易存储的信息。 + +``` +fn flatten_account(account: Account) -> [Field; FLAT_ACCOUNT_FIELDS] { +``` + +一个函数定义。 参数是 `Account` 信息。 结果是一个 `Field` 变量数组,其长度为 `FLAT_ACCOUNT_FIELDS` + +``` + let flat = [ + account.address, + ((account.balance << 32) + account.nonce.into()).into(), + ]; +``` + +数组中的第一个值是帐户地址。 第二个值包括余额和 nonce。 `.into()` 调用将数字更改为所需的数据类型。 `account.nonce` 是一个 `u32` 值,但要将其加到 `account.balance « 32`(一个 `u128` 值)上,它需要是一个 `u128`。 这是第一个 `.into()`。 第二个将 `u128` 结果转换为一个 `Field`,以便它能放入数组中。 + +``` + flat +} +``` + +在 Noir 中,函数只能在末尾返回值(没有提前返回)。 要指定返回值,您需要在函数的右括号之前对其进行求值。 + +``` +fn flatten_accounts(accounts: [Account; ACCOUNT_NUMBER]) -> [Field; FLAT_ACCOUNT_FIELDS*ACCOUNT_NUMBER] { +``` + +此函数将帐户数组转换为 `Field` 数组,可用作 Petersen 哈希的输入。 + +``` + let mut flat: [Field; FLAT_ACCOUNT_FIELDS*ACCOUNT_NUMBER] = [0; FLAT_ACCOUNT_FIELDS*ACCOUNT_NUMBER]; +``` + +这就是你指定一个可变变量的方式,也就是说,_不是_一个常量。 Noir 中的变量必须总有一个值,所以我们将这个变量初始化为全零。 + +``` + for i in 0..ACCOUNT_NUMBER { +``` + +这是一个 `for` 循环。 请注意,边界是常量。 Noir 循环必须在编译时知道其边界。 原因是算术电路不支持流控制。 在处理 `for` 循环时,编译器只是将循环内的代码多次放置,每次迭代一次。 + +``` + let fields = flatten_account(accounts[i]); + for j in 0..FLAT_ACCOUNT_FIELDS { + flat[i*FLAT_ACCOUNT_FIELDS + j] = fields[j]; + } + } + + flat +} + +fn hash_accounts(accounts: [Account; ACCOUNT_NUMBER]) -> Field { + pedersen_hash(flatten_accounts(accounts)) +} +``` + +最后,我们来到了哈希帐户数组的函数。 + +``` +fn find_account(accounts: [Account; ACCOUNT_NUMBER], address: Field) -> u32 { + let mut account : u32 = ACCOUNT_NUMBER; + + for i in 0..ACCOUNT_NUMBER { + if accounts[i].address == address { + account = i; + } + } +``` + +此函数查找具有特定地址的帐户。 在标准代码中,此函数会非常低效,因为它会遍历所有帐户,即使在找到地址之后也是如此。 + +然而,在零知识证明中,没有流控制。 如果我们需要检查一个条件,我们必须每次都检查它。 + +`if` 语句也会发生类似的情况。 上面循环中的 `if` 语句被翻译成这些数学语句。 + +_conditionresult = accounts[i].address == address_ // 如果相等则为 1,否则为 0 + +_accountnew = conditionresult\*i + (1-conditionresult)\*accountold_ + +```rust + assert (account < ACCOUNT_NUMBER, f"{address} does not have an account"); + + account +} +``` + +如果断言为假,[`assert`](https://noir-lang.org/docs/dev/noir/concepts/assert) 函数会导致零知识证明崩溃。 在这种情况下,如果我们找不到具有相关地址的帐户。 要报告地址,我们使用[格式化字符串](https://noir-lang.org/docs/noir/concepts/data_types/strings#format-strings)。 + +```rust +fn apply_transfer_txn(accounts: [Account; ACCOUNT_NUMBER], txn: TransferTxn) -> [Account; ACCOUNT_NUMBER] { +``` + +此函数应用转账交易并返回新的帐户数组。 + +```rust + let from = find_account(accounts, txn.from); + let to = find_account(accounts, txn.to); + + let (txnFrom, txnAmount, txnNonce, accountNonce) = + (txn.from, txn.amount, txn.nonce, accounts[from].nonce); +``` + +在 Noir 中,我们无法在格式字符串内访问结构元素,因此我们创建了一个可用的副本。 + +```rust + assert (accounts[from].balance >= txn.amount, + f"{txnFrom} does not have {txnAmount} finney"); + + assert (accounts[from].nonce == txn.nonce, + f"Transaction has nonce {txnNonce}, but the account is expected to use {accountNonce}"); +``` + +这是两个可能使交易无效的条件。 + +```rust + let mut newAccounts = accounts; + + newAccounts[from].balance -= txn.amount; + newAccounts[from].nonce += 1; + newAccounts[to].balance += txn.amount; + + newAccounts +} +``` + +创建新的帐户数组,然后返回它。 + +```rust +fn readAddress(messageBytes: [u8; MESSAGE_LENGTH]) -> Field +``` + +该函数从消息中读取地址。 + +```rust +{ + let mut result : Field = 0; + + for i in 7..47 { +``` + +地址总是 20 字节(又名 40 个十六进制数字)长,从第 7 个字符开始。 + +```rust + result *= 0x10; + if messageBytes[i] >= 48 & messageBytes[i] <= 57 { // 0-9 + result += (messageBytes[i]-48).into(); + } + if messageBytes[i] >= 65 & messageBytes[i] <= 70 { // A-F + result += (messageBytes[i]-65+10).into() + } + if messageBytes[i] >= 97 & messageBytes[i] <= 102 { // a-f + result += (messageBytes[i]-97+10).into() + } + } + + result +} + +fn readAmountAndNonce(messageBytes: [u8; MESSAGE_LENGTH]) -> (u128, u32) +``` + +从消息中读取金额和 nonce。 + +```rust +{ + let mut amount : u128 = 0; + let mut nonce: u32 = 0; + let mut stillReadingAmount: bool = true; + let mut lookingForNonce: bool = false; + let mut stillReadingNonce: bool = false; +``` + +在消息中,地址之后的第一个数字是 finney(又称 千分之一 ETH)的转账金额。 第二个数字是 nonce。 它们之间的任何文本都将被忽略。 + +```rust + for i in 48..MESSAGE_LENGTH { + if messageBytes[i] >= 48 & messageBytes[i] <= 57 { // 0-9 + let digit = (messageBytes[i]-48); + + if stillReadingAmount { + amount = amount*10 + digit.into(); + } + + if lookingForNonce { // 我们刚找到它 + stillReadingNonce = true; + lookingForNonce = false; + } + + if stillReadingNonce { + nonce = nonce*10 + digit.into(); + } + } else { + if stillReadingAmount { + stillReadingAmount = false; + lookingForNonce = true; + } + if stillReadingNonce { + stillReadingNonce = false; + } + } + } + + (amount, nonce) +} +``` + +返回一个[元组](https://noir-lang.org/docs/noir/concepts/data_types/tuples)是从函数返回多个值的 Noir 方式。 + +```rust +fn readTransferTxn(message: str) -> TransferTxn +{ + let mut txn: TransferTxn = TransferTxn { from: 0, to: 0, amount:0, nonce:0 }; + let messageBytes = message.as_bytes(); + + txn.to = readAddress(messageBytes); + let (amount, nonce) = readAmountAndNonce(messageBytes); + txn.amount = amount; + txn.nonce = nonce; + + txn +} +``` + +此函数将消息转换为字节,然后将金额转换为 `TransferTxn`。 + +```rust +// 相当于 Viem 的 hashMessage +// https://viem.sh/docs/utilities/hashMessage#hashmessage +fn hashMessage(message: str) -> [u8;32] { +``` + +我们能够对帐户使用 Pedersen 哈希,因为它们只在零知识证明内部进行哈希。 然而,在此代码中,我们需要检查由浏览器生成的消息签名。 为此,我们需要遵循 [EIP 191](https://eips.ethereum.org/EIPS/eip-191) 中的以太坊签名格式。 这意味着我们需要创建一个组合缓冲区,其中包含标准前缀、ASCII 格式的消息长度和消息本身,并使用以太坊标准 keccak256 对其进行哈希。 + +```rust + // ASCII 前缀 + let prefix_bytes = [ + 0x19, // \x19 + 0x45, // 'E' + 0x74, // 't' + 0x68, // 'h' + 0x65, // 'e' + 0x72, // 'r' + 0x65, // 'e' + 0x75, // 'u' + 0x6D, // 'm' + 0x20, // ' ' + 0x53, // 'S' + 0x69, // 'i' + 0x67, // 'g' + 0x6E, // 'n' + 0x65, // 'e' + 0x64, // 'd' + 0x20, // ' ' + 0x4D, // 'M' + 0x65, // 'e' + 0x73, // 's' + 0x73, // 's' + 0x61, // 'a' + 0x67, // 'g' + 0x65, // 'e' + 0x3A, // ':' + 0x0A // '\n' + ]; +``` + +为避免应用程序要求用户签署可用作交易或其他用途的消息的情况,EIP 191 规定所有已签名的消息都以字符 0x19(不是有效的 ASCII 字符)开头,后跟 `Ethereum Signed Message:` 和一个换行符。 + +```rust + let mut buffer: [u8; HASH_BUFFER_SIZE] = [0u8; HASH_BUFFER_SIZE]; + for i in 0..26 { + buffer[i] = prefix_bytes[i]; + } + + let messageBytes : [u8; MESSAGE_LENGTH] = message.as_bytes(); + + if MESSAGE_LENGTH <= 9 { + for i in 0..1 { + buffer[i+26] = ASCII_MESSAGE_LENGTH[i]; + } + + for i in 0..MESSAGE_LENGTH { + buffer[i+26+1] = messageBytes[i]; + } + } + + if MESSAGE_LENGTH >= 10 & MESSAGE_LENGTH <= 99 { + for i in 0..2 { + buffer[i+26] = ASCII_MESSAGE_LENGTH[i]; + } + + for i in 0..MESSAGE_LENGTH { + buffer[i+26+2] = messageBytes[i]; + } + } + + if MESSAGE_LENGTH >= 100 { + for i in 0..3 { + buffer[i+26] = ASCII_MESSAGE_LENGTH[i]; + } + + for i in 0..MESSAGE_LENGTH { + buffer[i+26+3] = messageBytes[i]; + } + } + + assert(MESSAGE_LENGTH < 1000, "Messages whose length is over three digits are not supported"); +``` + +处理长度最多为 999 的消息,如果大于此长度则失败。 我添加了此代码,尽管消息长度是常量,但这样做可以更容易地更改它。 在生产系统上,为了更好的性能,您可能会假设 `MESSAGE_LENGTH` 不会改变。 + +```rust + keccak256::keccak256(buffer, HASH_BUFFER_SIZE) +} +``` + +使用以太坊标准 `keccak256` 函数。 + +```rust +fn signatureToAddressAndHash( + message: str, + pubKeyX: [u8; 32], + pubKeyY: [u8; 32], + signature: [u8; 64] + ) -> (Field, Field, Field) // 地址、哈希的前 16 个字节、哈希的后 16 个字节 +{ +``` + +此函数验证签名,这需要消息哈希。 然后,它为我们提供签名地址和消息哈希。 消息哈希以两个 `Field` 值的形式提供,因为它们在程序的其余部分比字节数组更容易使用。 + +我们需要使用两个 `Field` 值,因为字段计算是对一个大数进行[模](https://en.wikipedia.org/wiki/Modulo)运算,但该数字通常小于 256 位(否则很难在 EVM 中执行这些计算)。 + +```rust + let hash = hashMessage(message); + + let mut (hash1, hash2) = (0,0); + + for i in 0..16 { + hash1 = hash1*256 + hash[31-i].into(); + hash2 = hash2*256 + hash[15-i].into(); + } +``` + +将 `hash1` 和 `hash2` 指定为可变变量,并逐字节将哈希写入其中。 + +```rust + ( + ecrecover::ecrecover(pubKeyX, pubKeyY, signature, hash), +``` + +这类似于 [Solidity 的 `ecrecover`](https://docs.soliditylang.org/en/v0.8.30/cheatsheet.html#mathematical-and-cryptographic-functions),但有两个重要区别: + +- 如果签名无效,调用会失败一个 `assert` 并中止程序。 +- 虽然可以从签名和哈希中恢复公钥,但这是可以在外部完成的处理,因此不值得在零知识证明中进行。 如果有人在这里试图欺骗我们,签名验证将会失败。 + +```rust + hash1, + hash2 + ) +} + +fn main( + accounts: [Account; ACCOUNT_NUMBER], + message: str, + pubKeyX: [u8; 32], + pubKeyY: [u8; 32], + signature: [u8; 64], + ) -> pub ( + Field, // 旧帐户数组的哈希 + Field, // 新帐户数组的哈希 + Field, // 消息哈希的前 16 个字节 + Field, // 消息哈希的后 16 个字节 + ) +``` + +最后,我们到达 `main` 函数。 我们需要证明我们有一笔交易,可以有效地将帐户哈希从旧值更改为新值。 我们还需要证明它具有此特定的交易哈希,以便发送者知道他们的交易已处理。 + +```rust +{ + let mut txn = readTransferTxn(message); +``` + +我们需要 `txn` 是可变的,因为我们不是从消息中读取“from”地址,而是从签名中读取。 + +```rust + let (fromAddress, txnHash1, txnHash2) = signatureToAddressAndHash( + message, + pubKeyX, + pubKeyY, + signature); + + txn.from = fromAddress; + + let newAccounts = apply_transfer_txn(accounts, txn); + + ( + hash_accounts(accounts), + hash_accounts(newAccounts), + txnHash1, + txnHash2 + ) +} +``` + +### 阶段 2 - 添加服务器 {#stage-2} + +在第二阶段,我们添加一个服务器,用于接收和实现来自浏览器的转账交易。 + +要查看实际操作: + +1. 如果 Vite 正在运行,请停止它。 + +2. 下载包含服务器的分支,并确保您拥有所有必需的模块。 + + ```sh + git checkout 02-add-server + cd client + npm install + cd ../server + npm install + ``` + + 无需编译 Noir 代码,它与您在阶段 1 中使用的代码相同。 + +3. 启动服务器。 + + ```sh + npm run start + ``` + +4. 在单独的命令行窗口中,运行 Vite 以提供浏览器代码。 + + ```sh + cd client + npm run dev + ``` + +5. 浏览到客户端代码 [http://localhost:5173](http://localhost:5173) + +6. 在您发出交易之前,您需要知道 nonce 以及您可以发送的金额。 要获取此信息,请单击 **Update account data** 并签署消息。 + + 我们在这里遇到了一个两难的境地。 一方面,我们不希望签署可以重复使用的消息([重放攻击](https://en.wikipedia.org/wiki/Replay_attack)),这就是我们首先需要 nonce 的原因。 但是,我们还没有 nonce。 解决方案是选择一个只能使用一次且双方都已有的 nonce,例如当前时间。 + + 这个解决方案的问题在于时间可能不完全同步。 因此,我们改为签署一个每分钟都会变化的值。 这意味着我们受到重放攻击的漏洞窗口最多为一分钟。 考虑到在生产环境中,已签名的请求将受到 TLS 的保护,并且隧道的另一端——服务器——已经可以泄露余额和 nonce(它必须知道这些才能工作),这是一个可以接受的风险。 + +7. 一旦浏览器取回余额和 nonce,它就会显示转账表单。 选择目标地址和金额,然后单击 **Transfer**。 签署此请求。 + +8. 要查看转账,请**更新帐户数据**或查看运行服务器的窗口。 服务器每次状态更改时都会记录日志。 + + ``` + ori@CryptoDocGuy:~/x/250911-zk-bank/server$ npm run start + + > server@1.0.0 start + > node --experimental-json-modules index.mjs + + Listening on port 3000 + Txn send 0x90F79bf6EB2c4f870365E785982E1f101E93b906 36000 finney (milliEth) 0 processed + New state: + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 has 64000 (1) + 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 has 100000 (0) + 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC has 100000 (0) + 0x90F79bf6EB2c4f870365E785982E1f101E93b906 has 136000 (0) + 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 has 100000 (0) + Txn send 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 7200 finney (milliEth) 1 processed + New state: + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 has 56800 (2) + 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 has 107200 (0) + 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC has 100000 (0) + 0x90F79bf6EB2c4f870365E785982E1f101E93b906 has 136000 (0) + 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 has 100000 (0) + Txn send 0x90F79bf6EB2c4f870365E785982E1f101E93b906 3000 finney (milliEth) 2 processed + New state: + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 has 53800 (3) + 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 has 107200 (0) + 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC has 100000 (0) + 0x90F79bf6EB2c4f870365E785982E1f101E93b906 has 139000 (0) + 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 has 100000 (0) + ``` + +#### `server/index.mjs` {#server-index-mjs-1} + +[此文件](https://github.com/qbzzt/250911-zk-bank/blob/02-add-server/server/index.mjs) 包含服务器进程,并与 [`main.nr`](https://github.com/qbzzt/250911-zk-bank/blob/02-add-server/server/noir/src/main.nr) 中的 Noir 代码进行交互。 以下是一些有趣部分的解释。 + +```js +import { Noir } from '@noir-lang/noir_js' +``` + +[noir.js](https://www.npmjs.com/package/@noir-lang/noir_js) 库是 JavaScript 代码和 Noir 代码之间的接口。 + +```js +const circuit = JSON.parse(await fs.readFile("./noir/target/zkBank.json")) +const noir = new Noir(circuit) +``` + +加载算术电路——我们在前一阶段创建的已编译 Noir 程序——并准备执行它。 + +```js +// 我们只在收到已签名请求时提供帐户信息 +const accountInformation = async signature => { + const fromAddress = await recoverAddress({ + hash: hashMessage("Get account data " + Math.floor((new Date().getTime())/60000)), + signature + }) +``` + +要提供帐户信息,我们只需要签名。 原因是,我们已经知道消息会是什么,因此也知道了消息哈希。 + +```js +const processMessage = async (message, signature) => { +``` + +处理一条消息并执行它编码的交易。 + +```js + // 获取公钥 + const pubKey = await recoverPublicKey({ + hash, + signature + }) +``` + +现在我们在服务器上运行 JavaScript,我们可以在服务器上而不是在客户端上检索公钥。 + +```js + let noirResult + try { + noirResult = await noir.execute({ + message, + signature: signature.slice(2,-2).match(/.{2}/g).map(x => `0x${x}`), + pubKeyX, + pubKeyY, + accounts: Accounts + }) +``` + +`noir.execute` 运行 Noir 程序。 这些参数等同于 [`Prover.toml`](https://github.com/qbzzt/250911-zk-bank/blob/01-manual-zk/server/noir/Prover.toml) 中提供的参数。 请注意,长值以十六进制字符串数组(`["0x60", "0xA7"]`)的形式提供,而不是像 Viem 那样以单个十六进制值(`0x60A7`)的形式提供。 + +```js + } catch (err) { + console.log(`Noir error: ${err}`) + throw Error("Invalid transaction, not processed") + } +``` + +如果出现错误,捕获它,然后将简化版本中继到客户端。 + +```js + Accounts[fromAccountNumber].nonce++ + Accounts[fromAccountNumber].balance -= amount + Accounts[toAccountNumber].balance += amount +``` + +应用交易。 我们已经在 Noir 代码中做过了,但在这里再做一次比从那里提取结果更容易。 + +```js +let Accounts = [ + { + address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + balance: 5000, + nonce: 0, + }, +``` + +初始的 `Accounts` 结构。 + +### 阶段 3 - 以太坊智能合约 {#stage-3} + +1. 停止服务器和客户端进程。 + +2. 下载包含智能合约的分支,并确保您拥有所有必需的模块。 + + ```sh + git checkout 03-smart-contracts + cd client + npm install + cd ../server + npm install + ``` + +3. 在单独的命令行窗口中运行 `anvil`。 + +4. 生成验证密钥和 solidity 验证器,然后将验证器代码复制到 Solidity 项目。 + + ```sh + cd noir + bb write_vk -b ./target/zkBank.json -o ./target --oracle_hash keccak + bb write_solidity_verifier -k ./target/vk -o ./target/Verifier.sol + cp target/Verifier.sol ../../smart-contracts/src + ``` + +5. 转到智能合约并设置环境变量以使用 `anvil` 区块链。 + + ```sh + cd ../../smart-contracts + export ETH_RPC_URL=http://localhost:8545 + ETH_PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 + ``` + +6. 部署 `Verifier.sol` 并将地址存储在环境变量中。 + + ```sh + VERIFIER_ADDRESS=`forge create src/Verifier.sol:HonkVerifier --private-key $ETH_PRIVATE_KEY --optimize --broadcast | awk '/Deployed to:/ {print $3}'` + echo $VERIFIER_ADDRESS + ``` + +7. 部署 `ZkBank` 合约。 + + ```sh + ZKBANK_ADDRESS=`forge create ZkBank --private-key $ETH_PRIVATE_KEY --broadcast --constructor-args $VERIFIER_ADDRESS 0x199aa62af8c1d562a6ec96e66347bf3240ab2afb5d022c895e6bf6a5e617167b | awk '/Deployed to:/ {print $3}'` + echo $ZKBANK_ADDRESS + ``` + + `0x199..67b` 值是 `Accounts` 初始状态的 Pederson 哈希。 如果您在 `server/index.mjs` 中修改此初始状态,您可以运行一个交易来查看零知识证明报告的初始哈希。 + +8. 运行服务器。 + + ```sh + cd ../server + npm run start + ``` + +9. 在不同的命令行窗口中运行客户端。 + + ```sh + cd client + npm run dev + ``` + +10. 运行一些交易。 + +11. 要验证链上状态是否已更改,请重新启动服务器进程。 可以看到 `ZkBank` 不再接受交易,因为交易中的原始哈希值与链上存储的哈希值不同。 + + 这是预期的错误类型。 + + ``` + ori@CryptoDocGuy:~/x/250911-zk-bank/server$ npm run start + + > server@1.0.0 start + > node --experimental-json-modules index.mjs + + Listening on port 3000 + Verification error: ContractFunctionExecutionError: The contract function "processTransaction" reverted with the following reason: + Wrong old state hash + + Contract Call: + address: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 + function: processTransaction(bytes _proof, bytes32[] _publicInputs) + args: (0x0000000000000000000000000000000000000000000000042ab5d6d1986846cf00000000000000000000000000000000000000000000000b75c020998797da7800000000000000000000000000000000000000000000000 + ``` + +#### `server/index.mjs` {#server-index-mjs-2} + +此文件中的更改主要与创建实际证明并将其提交到链上有关。 + +```js +import { exec } from 'child_process' +import util from 'util' + +const execPromise = util.promisify(exec) +``` + +我们需要使用 [Barretenberg 包](https://github.com/AztecProtocol/aztec-packages/tree/next/barretenberg)来创建要发送到链上的实际证明。 我们可以通过运行命令行界面 (`bb`) 或使用 [JavaScript 库 `bb.js`](https://www.npmjs.com/package/@aztec/bb.js) 来使用此包。 JavaScript 库比本地运行代码慢得多,所以我们在这里使用 [`exec`](https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback) 来使用命令行。 + +请注意,如果您决定使用 `bb.js`,您需要使用与您正在使用的 Noir 版本兼容的版本。 在撰写本文时,当前的 Noir 版本 (1.0.0-beta.11) 使用 `bb.js` 版本 0.87。 + +```js +const zkBankAddress = process.env.ZKBANK_ADDRESS || "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" +``` + +这里的地址是您在从干净的 `anvil` 开始并按照上述说明操作时获得的地址。 + +```js +const walletClient = createWalletClient({ + chain: anvil, + transport: http(), + account: privateKeyToAccount("0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6") +}) +``` + +此私钥是 `anvil` 中的默认预资助帐户之一。 + +```js +const generateProof = async (witness, fileID) => { +``` + +使用 `bb` 可执行文件生成证明。 + +```js + const fname = `witness-${fileID}.gz` + await fs.writeFile(fname, witness) +``` + +将见证写入文件。 + +```js + await execPromise(`bb prove -b ./noir/target/zkBank.json -w ${fname} -o ${fileID} --oracle_hash keccak --output_format fields`) +``` + +实际创建证明。 此步骤还会创建一个包含公共变量的文件,但我们不需要它。 我们已经从 `noir.execute` 获得了这些变量。 + +```js + const proof = "0x" + JSON.parse(await fs.readFile(`./${fileID}/proof_fields.json`)).reduce((a,b) => a+b, "").replace(/0x/g, "") +``` + +证明是 `Field` 值的 JSON 数组,每个值都表示为十六进制值。 然而,我们需要在交易中以单个 `bytes` 值的形式发送它,Viem 将其表示为一个大的十六进制字符串。 在这里,我们通过连接所有值、删除所有 `0x`,然后在末尾添加一个来更改格式。 + +```js + await execPromise(`rm -r ${fname} ${fileID}`) + + return proof +} +``` + +清理并返回证明。 + +```js +const processMessage = async (message, signature) => { + . + . + . + + const publicFields = noirResult.returnValue.map(x=>'0x' + x.slice(2).padStart(64, "0")) +``` + +公共字段需要是 32 字节值的数组。 然而,由于我们需要在两个 `Field` 值之间划分交易哈希,它显示为一个 16 字节的值。 在这里,我们添加零,以便 Viem 将其理解为实际的 32 字节。 + +```js + const proof = await generateProof(noirResult.witness, `${fromAddress}-${nonce}`) +``` + +每个地址只使用一次每个 nonce,这样我们就可以使用 `fromAddress` 和 `nonce` 的组合作为见证文件和输出目录的唯一标识符。 + +```js + try { + await zkBank.write.processTransaction([ + proof, publicFields]) + } catch (err) { + console.log(`Verification error: ${err}`) + throw Error("Can't verify the transaction onchain") + } + . + . + . +} +``` + +将交易发送到链上。 + +#### `smart-contracts/src/ZkBank.sol` {#smart-contracts-src-zkbank-sol} + +这是接收交易的链上代码。 + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.21; + +import {HonkVerifier} from "./Verifier.sol"; + +contract ZkBank { + HonkVerifier immutable myVerifier; + bytes32 currentStateHash; + + constructor(address _verifierAddress, bytes32 _initialStateHash) { + currentStateHash = _initialStateHash; + myVerifier = HonkVerifier(_verifierAddress); + } +``` + +链上代码需要跟踪两个变量:验证器(由 `nargo` 创建的独立合约)和当前状态哈希。 + +```solidity + event TransactionProcessed( + bytes32 indexed transactionHash, + bytes32 oldStateHash, + bytes32 newStateHash + ); +``` + +每次状态更改时,我们都会发出一个 `TransactionProcessed` 事件。 + +```solidity + function processTransaction( + bytes calldata _proof, + bytes32[] calldata _publicFields + ) public { +``` + +此函数处理交易。 它以验证器要求的格式获取证明(作为 `bytes`)和公共输入(作为 `bytes32` 数组),以最小化链上处理并因此降低燃料成本。 + +```solidity + require(_publicInputs[0] == currentStateHash, + "Wrong old state hash"); +``` + +零知识证明需要证明交易将我们当前的哈希更改为一个新的哈希。 + +```solidity + myVerifier.verify(_proof, _publicFields); +``` + +调用验证器合约以验证零知识证明。 如果零知识证明错误,此步骤将回滚交易。 + +```solidity + currentStateHash = _publicFields[1]; + + emit TransactionProcessed( + _publicFields[2]<<128 | _publicFields[3], + _publicFields[0], + _publicFields[1] + ); + } +} +``` + +如果一切检查无误,则将状态哈希更新为新值,并发出一个 `TransactionProcessed` 事件。 + +## 中心化组件的滥用 {#abuses} + +信息安全包括三个属性: + +- _机密性_,用户不能读取他们无权读取的信息。 +- _完整性_,信息不能被未经授权的用户以未经授权的方式更改。 +- _可用性_,授权用户可以使用系统。 + +在此系统中,完整性通过零知识证明提供。 可用性更难保证,而机密性则不可能,因为银行必须知道每个帐户的余额和所有交易。 无法阻止拥有信息的实体共享该信息。 + +使用[隐身地址](https://vitalik.eth.limo/general/2023/01/20/stealth.html)可能可以创建一个真正机密的银行,但这超出了本文的范围。 + +### 虚假信息 {#false-info} + +服务器违反完整性的一种方式是在[请求数据](https://github.com/qbzzt/250911-zk-bank/blob/03-smart-contracts/server/index.mjs#L278-L291)时提供虚假信息。 + +为了解决这个问题,我们可以编写第二个 Noir 程序,该程序接收帐户作为私有输入,并接收请求信息的地址作为公共输入。 输出是该地址的余额和 nonce,以及帐户的哈希。 + +当然,此证明无法在链上验证,因为我们不希望在链上发布 nonce 和余额。 但是,它可以通过在浏览器中运行的客户端代码进行验证。 + +### 强制交易 {#forced-txns} + +在 L2 上确保可用性和防止审查的通常机制是[强制交易](https://docs.optimism.io/stack/transactions/forced-transaction)。 但强制交易无法与零知识证明相结合。 服务器是唯一可以验证交易的实体。 + +我们可以修改 `smart-contracts/src/ZkBank.sol` 以接受强制交易,并防止服务器在处理它们之前更改状态。 然而,这使我们面临简单的拒绝服务攻击。 如果强制交易无效,因此无法处理怎么办? + +解决方案是提供一个零知识证明,证明强制交易无效。 这为服务器提供了三个选项: + +- 处理强制交易,提供零知识证明,证明其已处理并且生成了新的状态哈希。 +- 拒绝强制交易,并向合约提供零知识证明,证明交易无效(未知地址、错误的 nonce 或余额不足)。 +- 忽略强制交易。 无法强制服务器实际处理交易,但这意味着整个系统都不可用。 + +#### 可用性保证金 {#avail-bonds} + +在实际实现中,维持服务器运行可能存在某种利润动机。 我们可以通过让服务器发布可用性保证金来加强这种激励,如果在一定时期内未处理强制交易,任何人都可以销毁该保证金。 + +### 错误的 Noir 代码 {#bad-noir-code} + +通常,为了让人们信任智能合约,我们会将源代码上传到[区块浏览器](https://eth.blockscout.com/address/0x7D16d2c4e96BCFC8f815E15b771aC847EcbDB48b?tab=contract)。 然而,在零知识证明的情况下,这是不够的。 + +`Verifier.sol` 包含验证密钥,它是 Noir 程序的一个函数。 然而,该密钥并不能告诉我们 Noir 程序是什么。 要真正拥有一个可信的解决方案,您需要上传 Noir 程序(以及创建它的版本)。 否则,零知识证明可能反映了不同的程序,一个带有后门的程序。 + +在区块浏览器开始允许我们上传和验证 Noir 程序之前,您应该自己动手(最好上传到 [IPFS](/developers/tutorials/ipfs-decentralized-ui/))。 然后,高级用户将能够下载源代码,自己编译,创建 `Verifier.sol`,并验证它与链上的版本完全相同。 + +## 结论 {#conclusion} + +Plasma 类型的应用程序需要一个中心化组件作为信息存储。 这带来了潜在的漏洞,但作为回报,它允许我们以区块链本身无法实现的方式保护隐私。 通过零知识证明,我们可以确保完整性,并可能使运行中心化组件的任何人在经济上更有利于维护可用性。 + +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 + +## 致谢 {#acknowledgements} + +- Josh Crites 阅读了本文的草稿,并帮助我解决了一个棘手的 Noir 问题。 + +任何剩余的错误都由我负责。 diff --git a/public/content/translations/zh/developers/tutorials/calling-a-smart-contract-from-javascript/index.md b/public/content/translations/zh/developers/tutorials/calling-a-smart-contract-from-javascript/index.md index d314fff16c9..9cb3c1db9f8 100644 --- a/public/content/translations/zh/developers/tutorials/calling-a-smart-contract-from-javascript/index.md +++ b/public/content/translations/zh/developers/tutorials/calling-a-smart-contract-from-javascript/index.md @@ -1,12 +1,8 @@ --- -title: 通过JavaScript调用智能合约 -description: 以DAI代币为例展示如何通过JavaScript调用智能合约函数 +title: "通过 JavaScript 调用智能合约" +description: "以 DAI 代币为例,介绍如何通过 JavaScript 调用智能合约函数" author: jdourlens -tags: - - "交易" - - "前端" - - "JavaScript" - - "web3.js" +tags: [ "交易", "前端", "JavaScript", "web3.js" ] skill: beginner lang: zh published: 2020-04-19 @@ -15,15 +11,15 @@ sourceUrl: https://ethereumdev.io/calling-a-smart-contract-from-javascript/ address: "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" --- -在本教程中,我们将会看到如何通过JavaScript调用[智能合约](/developers/docs/smart-contracts/)。 首先读取智能合约的状态(例如:ERC20持有者的余额),然后通过代币转账修改区块链的状态。 你首先需要了解[设置JS环境与区块链交互](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/)。 +在本教程中,我们将了解如何通过 JavaScript 调用[智能合约](/developers/docs/smart-contracts/)函数。 首先是读取智能合约的状态(例如,ERC20 持有者的余额),然后我们将通过代币转账来修改区块链的状态。 你应该已经熟悉[如何设置 JS 环境来与区块链交互](/developers/tutorials/set-up-web3js-to-use-ethereum-in-javascript/)。 -在本例中,我们将使用DAI代币,基于测试目的,我们将使用ganache-cli分叉区块链并解锁一个已经拥有很多DAI的地址。 +在本例中,我们将使用 DAI 代币。为了进行测试,我们将使用 ganache-cli 分叉区块链,并解锁一个已有很多 DAI 的地址: ```bash ganache-cli -f https://mainnet.infura.io/v3/[YOUR INFURA KEY] -d -i 66 1 --unlock 0x4d10ae710Bd8D1C31bd7465c8CBC3add6F279E81 ``` -要与智能合约交互,我们需要它的地址和ABI: +要与智能合约交互,我们需要它的地址和 ABI: ```js const ERC20TransferABI = [ @@ -74,9 +70,9 @@ const ERC20TransferABI = [ const DAI_ADDRESS = "0x6b175474e89094c44da98b954eedeac495271d0f" ``` -对于此项目,我们剥离完整的ERC20 ABI ,仅保留`balanceOf`和`transfer`函数,不过你可以在这里获取完整的[ERC20 ABI](https://ethereumdev.io/abi-for-erc20-contract-on-ethereum/)。 +在这个项目中,我们删除了完整的 ERC20 ABI,只保留了 `balanceOf` 和 `transfer` 函数,但你可以[在这里找到完整的 ERC20 ABI](https://ethereumdev.io/abi-for-erc20-contract-on-ethereum/)。 -然后我们需要实例化我们的智能合约: +然后我们需要实例化智能合约: ```js const web3 = new Web3("http://localhost:8545") @@ -84,23 +80,23 @@ const web3 = new Web3("http://localhost:8545") const daiToken = new web3.eth.Contract(ERC20TransferABI, DAI_ADDRESS) ``` -我们还会设置两个地址: +我们还将设置两个地址: -- 一个接受转账 -- 一个已经解锁并将发送 +- 接收转账的一方,以及 +- 我们已解锁的、将发送转账的一方: ```js const senderAddress = "0x4d10ae710Bd8D1C31bd7465c8CBC3add6F279E81" const receiverAddress = "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" ``` -在下一部分中,我们会调用 `balance Of` 函数来检索当前的代币数量,此时这两个地址的代币数量都被冻结。 +在下一部分中,我们将调用 `balanceOf` 函数来检索这两个地址当前持有的代币数量。 ## 调用:从智能合约读取值 {#call-reading-value-from-a-smart-contract} -第一个例子,将调用“常量(constant)”方法并且在EVM中执行这个智能合约方法,并不发送任何交易。 为此我们将读取一个地址的ECR20余额。 [阅读关于 ECR20 代币的文章](/developers/tutorials/understand-the-erc-20-token-smart-contract/)。 +第一个示例将调用一个“常量”方法,并在 EVM 中执行其智能合约方法,而无需发送任何交易。 为此,我们将读取一个地址的 ERC20 余额。 [阅读我们关于 ERC20 代币的文章](/developers/tutorials/understand-the-erc-20-token-smart-contract/)。 -你可以访问为其提供 ABI 的实例化智能合约方法,如下所示:`yourContract.methods.methodname`。 通过使用`call`函数,你可以接收执行函数的结果。 +你可以按如下方式访问你为其提供了 ABI 的实例化智能合约的方法:`yourContract.methods.methodname`。 通过使用 `call` 函数,你将收到执行该函数的结果。 ```js daiToken.methods.balanceOf(senderAddress).call(function (err, res) { @@ -112,11 +108,11 @@ daiToken.methods.balanceOf(senderAddress).call(function (err, res) { }) ``` -请记住,DAI ERC20有18位小数,这意味着你需要移除18个零才能获得正确的数额。 uint256 将以字符串形式返回,因为 Javascript 不处理大数值。 如果不确定,请了解我们关于bignumber.js的教程[如何在JS中处理大数](https://ethereumdev.io/how-to-deal-with-big-numbers-in-javascript/)。 +请记住,DAI ERC20 有 18 位小数,这意味着你需要去掉 18 个零才能得到正确的金额。 由于 JavaScript 不处理大数值,`uint256` 会作为字符串返回。 如果你不确定[如何在 JS 中处理大数,请查看我们关于 bignumber.js 的教程](https://ethereumdev.io/how-to-deal-with-big-numbers-in-javascript/)。 -## 发送:将交易发送给智能合约函数 {#send-sending-a-transaction-to-a-smart-contract-function} +## 发送:向智能合约函数发送交易 {#send-sending-a-transaction-to-a-smart-contract-function} -对于第二个示例,我们将调用DAI智能合约的transfer函数,发送10个DAI到第二个地址。 transfer函数接受两个参数:收件人地址和转账代币的数量: +在第二个示例中,我们将调用 DAI 智能合约的 `transfer` 函数,向我们的第二个地址发送 10 个 DAI。 `transfer` 函数接受两个参数:接收方地址和要转账的代币数量: ```js daiToken.methods @@ -130,6 +126,6 @@ daiToken.methods }) ``` -调用函数返回将被在区块链中挖矿(mine) 的交易的哈希。 在以太坊中,交易哈希是可以预测的 - 这里是我们在执行前获得交易哈希值的方法([了解如何计算哈希](https://ethereum.stackexchange.com/questions/45648/how-to-calculate-the-assigned-txhash-of-a-transaction))。 +该函数调用返回交易的哈希,该交易将被挖矿并加入区块链。 在以太坊上,交易哈希是可预测的——因此我们可以在交易执行前就得到其哈希([在此处了解如何计算哈希](https://ethereum.stackexchange.com/questions/45648/how-to-calculate-the-assigned-txhash-of-a-transaction))。 -因为该函数只向区块链提交交易,除非通过挖矿并包含在区块链中,否则我们无法看到结果。 在下一个教程中,我们将学习[如何通过了解其哈希值来等待一个交易在区块链上的执行](https://ethereumdev.io/waiting-for-a-transaction-to-be-mined-on-ethereum-with-js/)。 +由于该函数只是将交易提交到区块链,因此只有当它被挖出并打包到区块链中时,我们才能看到结果。 在下一篇教程中,我们将学习[如何根据交易哈希等待其在区块链上执行](https://ethereumdev.io/waiting-for-a-transaction-to-be-mined-on-ethereum-with-js/)。 diff --git a/public/content/translations/zh/developers/tutorials/creating-a-wagmi-ui-for-your-contract/index.md b/public/content/translations/zh/developers/tutorials/creating-a-wagmi-ui-for-your-contract/index.md new file mode 100644 index 00000000000..13a78d5fcf2 --- /dev/null +++ b/public/content/translations/zh/developers/tutorials/creating-a-wagmi-ui-for-your-contract/index.md @@ -0,0 +1,585 @@ +--- +title: "为您的合约构建用户界面" +description: "我们将使用 TypeScript、React、Vite 和 Wagmi 等现代组件来构建一个现代但简约的用户界面,并学习如何将钱包连接到用户界面、调用智能合约来读取信息、向智能合约发送交易以及监控来自智能合约的事件以识别更改。" +author: Ori Pomerantz +tags: [ "typescript", "react", "vite", "wagmi", "前端" ] +skill: beginner +published: 2023-11-01 +lang: zh +sidebarDepth: 3 +--- + +您在以太坊生态系统中找到了我们需要的功能。 您编写了智能合约来实现它,甚至可能编写了一些在链下运行的相关代码。 太好了! 遗憾的是,如果没有用户界面,您就不会有任何用户,而且您上一次编写网站时,人们还在使用拨号调制解调器,JavaScript 还是个新事物。 + +本文就是为您准备的。 我假设您了解编程,或许还了解一些 JavaScript 和 HTML,但您的用户界面技能已经生疏和过时了。 我们将一起学习一个简单的现代应用,这样您就会知道现在是如何做的了。 + +## 为何这很重要 {#why-important} + +理论上,您可以让人们使用 [Etherscan](https://holesky.etherscan.io/address/0x432d810484add7454ddb3b5311f0ac2e95cecea8#writeContract) 或 [Blockscout](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=write_contract) 与您的合约进行交互。 对于经验丰富的以太坊用户来说,这很好。 但我们正努力为[另外十亿人](https://blog.ethereum.org/2021/05/07/ethereum-for-the-next-billion)服务。 如果没有出色的用户体验,这是不可能实现的,而友好的用户界面是其中的重要组成部分。 + +## Greeter 应用 {#greeter-app} + +现代 UI 的工作原理背后有很多理论,也有[很多不错的网站](https://react.dev/learn/thinking-in-react)[对此进行了解释](https://wagmi.sh/core/getting-started)。 我不会重复那些网站已经做得很好的工作,而是假设您更喜欢通过实践来学习,并从一个您可以上手的应用开始。 您仍然需要理论来完成工作,我们稍后会讲到这一点——我们将逐个源文件进行讲解,并在讲到时进行讨论。 + +### 安装 {#installation} + +1. 如有必要,请将 [Holesky 区块链](https://chainlist.org/?search=holesky&testnets=true) 添加到您的钱包并[获取测试 ETH](https://www.holeskyfaucet.io/)。 + +2. 克隆 github 仓库。 + + ```sh + git clone https://github.com/qbzzt/20230801-modern-ui.git + ``` + +3. 安装必要的软件包。 + + ```sh + cd 20230801-modern-ui + pnpm install + ``` + +4. 启动应用。 + + ```sh + pnpm dev + ``` + +5. 浏览到应用显示的 URL。 在大多数情况下,该 URL 为 [http://localhost:5173/](http://localhost:5173/)。 + +6. 您可以在[区块链浏览器](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=contract)上看到合约源代码,它是 Hardhat Greeter 的略微修改版本。 + +### 文件演练 {#file-walk-through} + +#### `index.html` {#index-html} + +该文件是标准的 HTML 样板文件,但导入脚本文件的这一行除外。 + +```html + +``` + +#### `src/main.tsx` {#main-tsx} + +文件扩展名告诉我们,这是一个用 [TypeScript](https://www.typescriptlang.org/) 编写的 [React 组件](https://www.w3schools.com/react/react_components.asp),TypeScript 是 JavaScript 的一个扩展,支持[类型检查](https://en.wikipedia.org/wiki/Type_system#Type_checking)。 TypeScript 被编译成 JavaScript,因此我们可以用它来进行客户端执行。 + +```tsx +import '@rainbow-me/rainbowkit/styles.css' +import { RainbowKitProvider } from '@rainbow-me/rainbowkit' +import * as React from 'react' +import * as ReactDOM from 'react-dom/client' +import { WagmiConfig } from 'wagmi' +import { chains, config } from './wagmi' +``` + +导入我们需要的库代码。 + +```tsx +import { App } from './App' +``` + +导入实现该应用的 React 组件(见下文)。 + +```tsx +ReactDOM.createRoot(document.getElementById('root')!).render( +``` + +创建根 React 组件。 `render` 的参数是 [JSX](https://www.w3schools.com/react/react_jsx.asp),这是一种同时使用 HTML 和 JavaScript/TypeScript 的扩展语言。 这里的感叹号告诉 TypeScript 组件:“你不知道 `document.getElementById('root')` 是否会是 `ReactDOM.createRoot` 的有效参数,但别担心——我是开发者,我告诉你它会是”。 + +```tsx + +``` + +该应用将放在 [一个 `React.StrictMode` 组件](https://react.dev/reference/react/StrictMode)中。 该组件告诉 React 库插入额外的调试检查,这在开发过程中很有用。 + +```tsx + +``` + +该应用也位于 [一个 `WagmiConfig` 组件](https://wagmi.sh/react/api/WagmiProvider)中。 [Wagmi (we are going to make it) 库](https://wagmi.sh/) 将 React UI 定义与 [viem 库](https://viem.sh/)连接起来,用于编写以太坊去中心化应用程序。 + +```tsx + +``` + +最后,还有[一个 `RainbowKitProvider` 组件](https://www.rainbowkit.com/)。 此组件处理登录以及钱包和应用之间的通信。 + +```tsx + +``` + +现在我们可以为应用提供组件,该组件实际实现了 UI。 组件末尾的 `/>` 告诉 React,根据 XML 标准,该组件内部没有任何定义。 + +```tsx + + + , +) +``` + +当然,我们必须关闭其他组件。 + +#### `src/App.tsx` {#app-tsx} + +```tsx +import { ConnectButton } from '@rainbow-me/rainbowkit' +import { useAccount } from 'wagmi' +import { Greeter } from './components/Greeter' + +export function App() { +``` + +这是创建 React 组件的标准方法——定义一个函数,每次需要渲染时都会调用该函数。 这个函数通常在顶部有一些 TypeScript 或 JavaScript 代码,然后是一个返回 JSX 代码的 `return` 语句。 + +```tsx + const { isConnected } = useAccount() +``` + +这里我们使用 [`useAccount`](https://wagmi.sh/react/api/hooks/useAccount) 来检查我们是否通过钱包连接到区块链。 + +按照惯例,在 React 中,名为 `use...` 的函数是返回某种数据的 [hooks](https://www.w3schools.com/react/react_hooks.asp)。 当您使用此类挂钩时,您的组件不仅会获取数据,而且当该数据更改时,组件会使用更新后的信息重新渲染。 + +```tsx + return ( + <> +``` + +React 组件的 JSX _必须_返回一个组件。 当我们有多个组件并且没有任何东西可以"自然地"包装它们时,我们使用一个空组件 (`<> ... `) 将它们变成单个组件。 + +```tsx +

Greeter

+ +``` + +我们从 RainbowKit 中获取 [`ConnectButton` 组件](https://www.rainbowkit.com/docs/connect-button)。 当我们未连接时,它会给我们一个“连接钱包”按钮,该按钮会打开一个模式窗口,解释什么是钱包,并让您选择使用哪一个。 当我们连接时,它会显示我们使用的区块链、我们的帐户地址和我们的 ETH 余额。 我们可以使用这些显示来切换网络或断开连接。 + +```tsx + {isConnected && ( +``` + +当我们需要将实际的 JavaScript(或将被编译成 JavaScript 的 TypeScript)插入到 JSX 中时,我们使用括号(`{}`)。 + +语法 `a && b` 是 [`a ?` 的缩写 b : a`](https://www.w3schools.com/react/react_es6_ternary.asp)。 也就是说,如果 `a`为真,则其值为`b`,否则其值为 `a`(可以是 `false`、`0` 等)。 这是一种告诉 React 组件只应在满足特定条件时才显示的简单方法。 + +在这种情况下,我们只想在用户连接到区块链时向用户显示 `Greeter`。 + +```tsx + + )} + + ) +} +``` + +#### `src/components/Greeter.tsx` {#greeter-tsx} + +该文件包含大部分 UI 功能。 它包含通常会放在多个文件中的定义,但由于这是一个教程,程序被优化为第一次易于理解,而不是为了性能或易于维护。 + +```tsx +import { useState, ChangeEventHandler } from 'react' +import { useNetwork, + useReadContract, + usePrepareContractWrite, + useContractWrite, + useContractEvent + } from 'wagmi' +``` + +我们使用这些库函数。 同样,在使用它们的地方,下面会进行解释。 + +```tsx +import { AddressType } from 'abitype' +``` + +[`abitype` 库](https://abitype.dev/)为我们提供了各种以太坊数据类型的 TypeScript 定义,例如 [`AddressType`](https://abitype.dev/config#addresstype)。 + +```tsx +let greeterABI = [ + . + . + . +] as const // greeterABI +``` + +`Greeter` 合约的 ABI。 +如果您同时开发合约和 UI,通常会将它们放在同一个仓库中,并使用 Solidity 编译器生成的 ABI 作为应用中的文件。 然而,这里没有必要这样做,因为合约已经开发完毕,不会再改变。 + +```tsx +type AddressPerBlockchainType = { + [key: number]: AddressType +} +``` + +TypeScript 是强类型的。 我们使用这个定义来指定 `Greeter` 合约在不同链上部署的地址。 键是数字(chainId),值是 `AddressType`(一个地址)。 + +```tsx +const contractAddrs: AddressPerBlockchainType = { + // Holesky + 17000: '0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8', + + // Sepolia + 11155111: '0x7143d5c190F048C8d19fe325b748b081903E3BF0' +} +``` + +合约在两个受支持网络上的地址:[Holesky](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=contact_code) 和 [Sepolia](https://eth-sepolia.blockscout.com/address/0x7143d5c190F048C8d19fe325b748b081903E3BF0?tab=contact_code)。 + +注意:实际上还有第三个定义,针对 Redstone Holesky,将在下面解释。 + +```tsx +type ShowObjectAttrsType = { + name: string, + object: any +} +``` + +此类型用作 `ShowObject` 组件的参数(稍后解释)。 它包括对象的名称及其值,用于调试目的。 + +```tsx +type ShowGreetingAttrsType = { + greeting: string | undefined +} +``` + +在任何时候,我们都可能知道问候语是什么(因为我们从区块链中读取了它),也可能不知道(因为我们还没有收到它)。 因此,拥有一个可以是字符串或空的类型是很有用的。 + +##### `Greeter` 组件 {#greeter-component} + +```tsx +const Greeter = () => { +``` + +最后,我们来定义这个组件。 + +```tsx + const { chain } = useNetwork() +``` + +我们使用的链的信息,由 [wagmi](https://wagmi.sh/react/hooks/useNetwork) 提供。 +因为这是一个钩子 (`use...`),所以每当此信息发生变化时,组件都会被重新绘制。 + +```tsx + const greeterAddr = chain && contractAddrs[chain.id] +``` + +Greeter 合约的地址,它因链而异(如果我们没有链信息或者我们在没有该合约的链上,它就是 `undefined`)。 + +```tsx + const readResults = useReadContract({ + address: greeterAddr, + abi: greeterABI, + functionName: "greet" , // No arguments + watch: true + }) +``` + +[`useReadContract` 钩子](https://wagmi.sh/react/api/hooks/useReadContract) 从合约中读取信息。 您可以在 UI 中展开 `readResults` 来确切地看到它返回了什么信息。 在这种情况下,我们希望它继续观察,以便在问候语更改时得到通知。 + +\*\*注意:\*\*我们可以监听 [`setGreeting` 事件](https://eth-holesky.blockscout.com/address/0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8?tab=logs)来了解问候语何时更改并以这种方式进行更新。 然而,虽然这样可能更高效,但它并不适用于所有情况。 当用户切换到不同的链时,问候语也会改变,但这种改变并不伴随事件。 我们可以让一部分代码监听事件,另一部分识别链的变化,但这会比仅仅设置 [`watch` 参数](https://wagmi.sh/react/api/hooks/useReadContract#watch-optional)更复杂。 + +```tsx + const [ newGreeting, setNewGreeting ] = useState("") +``` + +React 的 [`useState` 钩子](https://www.w3schools.com/react/react_usestate.asp)允许我们指定一个状态变量,其值在组件的多次渲染之间保持不变。 初始值是参数,在本例中为空字符串。 + +`useState` 钩子返回一个包含两个值的列表: + +1. 状态变量的当前值。 +2. 一个在需要时修改状态变量的函数。 由于这是一个钩子,所以每次调用它时,组件都会重新渲染。 + +在这种情况下,我们使用一个状态变量来表示用户想要设置的新问候语。 + +```tsx + const greetingChange : ChangeEventHandler = (evt) => + setNewGreeting(evt.target.value) +``` + +这是新问候语输入字段发生变化时的事件处理程序。 类型 [`ChangeEventHandler`](https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/forms_and_events/) 指定这是 HTML 输入元素值变化的处理器。 之所以使用 `` 部分,是因为这是一个[泛型类型](https://www.w3schools.com/typescript/typescript_basic_generics.php)。 + +```tsx + const preparedTx = usePrepareContractWrite({ + address: greeterAddr, + abi: greeterABI, + functionName: 'setGreeting', + args: [ newGreeting ] + }) + const workingTx = useContractWrite(preparedTx.config) +``` + +这是从客户端角度提交区块链交易的过程: + +1. 使用 [`eth_estimateGas`](https://docs.alchemy.com/reference/eth-estimategas) 将交易发送到区块链中的一个节点。 +2. 等待节点的响应。 +3. 收到响应后,请用户通过钱包签署交易。 这一步_必须_在收到节点响应后进行,因为在签名之前,用户会看到交易的 gas 成本。 +4. 等待用户批准。 +5. 再次发送交易,这次使用 [`eth_sendRawTransaction`](https://docs.alchemy.com/reference/eth-sendrawtransaction)。 + +第 2 步可能会花费一段可感知的时间,在此期间,用户会想知道他们的命令是否真的被用户界面接收到,以及为什么还没有要求他们签署交易。 这会造成糟糕的用户体验 (UX)。 + +解决方案是使用[准备钩子](https://wagmi.sh/react/prepare-hooks)。 每次参数更改时,立即向节点发送 `eth_estimateGas` 请求。 然后,当用户实际想要发送交易时(在本例中,通过按**更新问候语**),gas 成本是已知的,用户可以立即看到钱包页面。 + +```tsx + return ( +``` + +现在我们终于可以创建要返回的实际 HTML 了。 + +```tsx + <> +

Greeter

+ { + !readResults.isError && !readResults.isLoading && + + } +
+``` + +创建一个 `ShowGreeting` 组件(在下面解释),但前提是问候语已成功从区块链中读取。 + +```tsx + +``` + +这是用户可以设置新问候语的输入文本字段。 每次用户按下一个键,我们都会调用 `greetingChange`,它会调用 `setNewGreeting`。 由于 `setNewGreeting` 来自 `useState` 钩子,它会导致 `Greeter` 组件再次渲染。 这意味着: + +- 我们需要指定 `value` 来保留新问候语的值,否则它将变回默认值,即空字符串。 +- 每次 `newGreeting` 更改时都会调用 `usePrepareContractWrite`,这意味着它在准备好的交易中总是会有最新的 `newGreeting`。 + +```tsx + +``` + +如果没有 `workingTx.write`,那么我们仍在等待发送问候语更新所需的信息,因此按钮是禁用的。 如果有一个 `workingTx.write` 值,那么这就是调用以发送交易的函数。 + +```tsx +
+ + + + + ) +} +``` + +最后,为了帮助您了解我们在做什么,请显示我们使用的三个对象: + +- `readResults` +- `preparedTx` +- `workingTx` + +##### `ShowGreeting` 组件 {#showgreeting-component} + +此组件显示 + +```tsx +const ShowGreeting = (attrs : ShowGreetingAttrsType) => { +``` + +组件函数接收一个包含组件所有属性的参数。 + +```tsx + return {attrs.greeting} +} +``` + +##### `ShowObject` 组件 {#showobject-component} + +为了提供信息,我们使用 `ShowObject` 组件来显示重要的对象(`readResults` 用于读取问候语,`preparedTx` 和 `workingTx` 用于我们创建的交易)。 + +```tsx +const ShowObject = (attrs: ShowObjectAttrsType ) => { + const keys = Object.keys(attrs.object) + const funs = keys.filter(k => typeof attrs.object[k] == "function") + return <> +
+``` + +我们不希望所有信息都杂乱地显示在 UI 中,因此为了能够查看或关闭它们,我们使用 [`details`](https://www.w3schools.com/tags/tag_details.asp) 标签。 + +```tsx + {attrs.name} +
+        {JSON.stringify(attrs.object, null, 2)}
+```
+
+大多数字段都是使用 [`JSON.stringify`](https://www.w3schools.com/js/js_json_stringify.asp) 显示的。
+
+```tsx
+      
+ { funs.length > 0 && + <> + Functions: +
    +``` + +唯一的例外是函数,它不属于 [JSON 标准](https://www.json.org/json-en.html),因此必须单独显示。 + +```tsx + {funs.map((f, i) => +``` + +在 JSX 中,`{` 花括号 `}` 内的代码被解释为 JavaScript。 然后,`(` 圆括号 `)` 内的代码再次被解释为 JSX。 + +```tsx + (
  • {f}
  • ) + )} +``` + +React 要求 [DOM 树](https://www.w3schools.com/js/js_htmldom.asp)中的标签具有不同的标识符。 这意味着同一标签(在本例中为[无序列表](https://www.w3schools.com/tags/tag_ul.asp))的子标签需要不同的 `key` 属性。 + +```tsx +
+ + } +
+ +} +``` + +结束各种 HTML 标签。 + +##### 最终的 `export` {#the-final-export} + +```tsx +export { Greeter } +``` + +`Greeter` 组件是我们需要为应用导出的组件。 + +#### `src/wagmi.ts` {#wagmi-ts} + +最后,与 WAGMI 相关的各种定义都在 `src/wagmi.ts` 中。 我不会在这里解释所有内容,因为其中大部分是您不太可能需要更改的样板代码。 + +这里的代码与[在 github 上](https://github.com/qbzzt/20230801-modern-ui/blob/main/src/wagmi.ts)的代码不完全相同,因为在文章后面我们添加了另一条链([Redstone Holesky](https://redstone.xyz/docs/network-info))。 + +```ts +import { getDefaultWallets } from '@rainbow-me/rainbowkit' +import { configureChains, createConfig } from 'wagmi' +import { holesky, sepolia } from 'wagmi/chains' +``` + +导入应用支持的区块链。 您可以在 [viem github](https://github.com/wagmi-dev/viem/tree/main/src/chains/definitions) 中查看支持的链的列表。 + +```ts +import { publicProvider } from 'wagmi/providers/public' + +const walletConnectProjectId = 'c96e690bb92b6311e8e9b2a6a22df575' +``` + +要使用 [WalletConnect](https://walletconnect.com/),您需要为您的应用提供一个项目 ID。 您可以在 [cloud.walletconnect.com](https://cloud.walletconnect.com/sign-in) 上获取。 + +```ts +const { chains, publicClient, webSocketPublicClient } = configureChains( + [ holesky, sepolia ], + [ + publicProvider(), + ], +) + +const { connectors } = getDefaultWallets({ + appName: 'My wagmi + RainbowKit App', + chains, + projectId: walletConnectProjectId, +}) + +export const config = createConfig({ + autoConnect: true, + connectors, + publicClient, + webSocketPublicClient, +}) + +export { chains } +``` + +### 添加另一个区块链 {#add-blockchain} + +如今有很多 [L2 扩容解决方案](/layer-2/),您可能想支持一些 viem 尚不支持的方案。 要做到这一点,您需要修改 `src/wagmi.ts`。 这些说明解释了如何添加 [Redstone Holesky](https://redstone.xyz/docs/network-info)。 + +1. 从 viem 导入 `defineChain` 类型。 + + ```ts + import { defineChain } from 'viem' + ``` + +2. 添加网络定义。 + + ```ts + const redstoneHolesky = defineChain({ + id: 17_001, + name: 'Redstone Holesky', + network: 'redstone-holesky', + nativeCurrency: { + decimals: 18, + name: 'Ether', + symbol: 'ETH', + }, + rpcUrls: { + default: { + http: ['https://rpc.holesky.redstone.xyz'], + webSocket: ['wss://rpc.holesky.redstone.xyz/ws'], + }, + public: { + http: ['https://rpc.holesky.redstone.xyz'], + webSocket: ['wss://rpc.holesky.redstone.xyz/ws'], + }, + }, + blockExplorers: { + default: { name: 'Explorer', url: 'https://explorer.holesky.redstone.xyz' }, + }, + }) + ``` + +3. 将新链添加到 `configureChains` 调用中。 + + ```ts + const { chains, publicClient, webSocketPublicClient } = configureChains( + [ holesky, sepolia, redstoneHolesky ], + [ publicProvider(), ], + ) + ``` + +4. 确保应用知道您在新网络上的合约地址。 在这种情况下,我们修改 `src/components/Greeter.tsx`: + + ```ts + const contractAddrs : AddressPerBlockchainType = { + // Holesky + 17000: '0x432d810484AdD7454ddb3b5311f0Ac2E95CeceA8', + + // Redstone Holesky + 17001: '0x4919517f82a1B89a32392E1BF72ec827ba9986D3', + + // Sepolia + 11155111: '0x7143d5c190F048C8d19fe325b748b081903E3BF0' + } + ``` + +## 结论 {#conclusion} + +当然,您并不真正关心为 `Greeter` 提供用户界面。 您想为自己的合约创建用户界面。 要创建您自己的应用,请执行以下步骤: + +1. 指定创建 wagmi 应用。 + + ```sh copy + pnpm create wagmi + ``` + +2. 为应用命名。 + +3. 选择 **React** 框架。 + +4. 选择 **Vite** 变体。 + +5. 您可以[添加 Rainbow kit](https://www.rainbowkit.com/docs/installation#manual-setup)。 + +现在去为您的合约创造一个全世界都能使用的界面吧。 + +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 + diff --git a/public/content/translations/zh/developers/tutorials/deploying-your-first-smart-contract/index.md b/public/content/translations/zh/developers/tutorials/deploying-your-first-smart-contract/index.md index 95dffc887cf..6cd21974f77 100644 --- a/public/content/translations/zh/developers/tutorials/deploying-your-first-smart-contract/index.md +++ b/public/content/translations/zh/developers/tutorials/deploying-your-first-smart-contract/index.md @@ -1,12 +1,8 @@ --- -title: 部署第一个智能合约 -description: 介绍如何在以太坊测试网络上部署你第一个智能合约 +title: "部署你的第一个智能合约" +description: "介绍如何在以太坊测试网上部署您的第一个智能合约" author: "jdourlens" -tags: - - "智能合约" - - "remix" - - "solidity" - - "deploying" +tags: [ "智能合同", "remix", "Solidity", "部署" ] skill: beginner lang: zh published: 2020-04-03 @@ -15,17 +11,17 @@ sourceUrl: https://ethereumdev.io/deploying-your-first-smart-contract/ address: "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" --- -我猜你和我们一样会很兴奋在以太坊区块链上[部署](/developers/docs/smart-contracts/deploying/)[智能合约](/developers/docs/smart-contracts/)并与之交互。 +我们想必您和我们一样兴奋,即将在以太坊区块链上[部署](/developers/docs/smart-contracts/deploying/)并与您的第一个[智能合约](/developers/docs/smart-contracts/)交互。 -别担心,作为我们的第一个智能合约,我们会将其部署在[本地测试网络](/developers/docs/networks/)上,因此你不需要任何开销就可以随意部署和运行它。 +别担心,由于这是我们的第一个智能合约,我们会将其部署在[本地测试网](/developers/docs/networks/)上,因此您不需要任何开销就可以随意部署和运行它。 ## 编写合约 {#writing-our-contract} -第一步[访问Remix](https://remix.ethereum.org/)并创建一个新文件。 在Remix界面的左上角添加一个新文件,并输入所需的文件名。 +第一步是[访问 Remix](https://remix.ethereum.org/) 并创建一个新文件。 在 Remix 界面的左上角,添加一个新文件并输入您想要的文件名。 -![在Remix界面中添加一个新文件](./remix.png) +![在 Remix 界面中添加新文件](./remix.png) -在这个新文件中,我们将粘贴如下代码: +在新文件中,我们将粘贴以下代码。 ```solidity // SPDX-License-Identifier: MIT @@ -33,15 +29,15 @@ pragma solidity >=0.5.17; contract Counter { - // Public variable of type unsigned int to keep the number of counts + // 用于记录计数的无符号整数类型的公共变量 uint256 public count = 0; - // Function that increments our counter + // 递增计数器的函数 function increment() public { count += 1; } - // Not necessary getter to get the count value + // 用于获取计数值的非必要 getter 函数 function getCount() public view returns (uint256) { return count; } @@ -49,51 +45,51 @@ contract Counter { } ``` -如果你曾经写过程序,应该可以轻松猜到这个程序是做什么的。 下面按行解释: +如果您有编程经验,应该可以轻松猜出这个程序是做什么的。 下面是逐行解释: - 第 4 行:我们定义了一个名为 `Counter` 的合约。 -- 第 7 行:我们的合约存储了一个无符号整型 `count`,从 0 开始。 -- 第 10 行:第一个函数将修改合约的状态,并使用 `increment()` 递增我们的变量 `count`。 -- 第 15 行,第二个函数就是一个取值器,能够从智能合约外部读取 `count` 变量的值。 请注意,因为我们将 `count` 变量定义为公共变量,所以这个函数是不必要的,但它可以作为一个例子展示。 +- 第 7 行:我们的合约存储了一个名为 `count` 的无符号整数,初始值为 0。 +- 第 10 行:第一个函数会修改合约的状态,并调用 `increment()` 来递增我们的变量 `count`。 +- 第 15 行:第二个函数只是一个取值器,用于在智能合约外部读取 `count` 变量的值。 请注意,由于我们将 `count` 变量定义为 public,这个函数不是必需的,但这里用作示例。 -第一个简单的智能合约到此结束。 正如你所知,它看上去像是 Java 或 C++ 这样的面向对象编程 (OOP) 语言中的一个类。 现在可以运行我们的合约了。 +我们第一个简单的智能合约就是这样。 您可能知道,它看起来像 Java 或 C++ 等 OOP(面向对象编程)语言中的类。 现在是时候体验我们的合约了。 ## 部署合约 {#deploying-our-contract} -当我们写了第一个智能合约后,我们现在可以将它部署在区块链中并运行它。 +我们已经编写了第一个智能合约,现在要将它部署到区块链上进行体验。 -[在区块链上部署智能合约](/developers/docs/smart-contracts/deploying/)实际上只是发送了一个包含已编译智能合约代码的交易,并且没有指定任何收件人。 +在区块链上[部署智能合约](/developers/docs/smart-contracts/deploying/)实际上只是发送一笔包含已编译智能合约代码且未指定任何接收者的交易。 -我们首先点击左侧的编译图标来[编译合约](/developers/docs/smart-contracts/compiling/): +我们首先通过点击左侧的编译图标来[编译合约](/developers/docs/smart-contracts/compiling/): -![Remix工具栏中的编译图标](./remix-compile-button.png) +![Remix 工具栏中的编译图标](./remix-compile-button.png) 然后点击编译按钮: -![Remix solidity编译器的编译按钮](./remix-compile.png) +![Remix Solidity 编译器中的编译按钮](./remix-compile.png) -你可以选择“Auto compile”选项,这样在将合约内容保存到文本编辑器时合约也随之编译。 +您可以选择“Auto compile”选项,这样当您在文本编辑器中保存内容时,合约将始终被编译。 -然后切换到部署和运行交易屏幕: +然后导航至“deploy and run transactions”屏幕: -![Remix工具栏的部署图标](./remix-deploy.png) +![Remix 工具栏中的部署图标](./remix-deploy.png) -在“部署和运行交易”屏幕上,仔细检查显示的合约名称并点击“部署”。 正如你在页面顶部所见,当前环境是“JavaScript 虚拟机”,这意味着我们将在本地测试区块链上部署我们的智能合约并与之交互,以便能够更快地进行测试且无须支付任何费用。 +进入“deploy and run transactions”屏幕后,请再次确认您的合约名称已显示,然后点击 Deploy。 如您在页面顶部所见,当前环境是“JavaScript 虚拟机”,这意味着我们将在本地测试区块链上部署我们的智能合约并与之交互,以便能够更快地进行测试,且无须支付任何费用。 -![Remix solidity编译器的部署按钮](./remix-deploy-button.png) +![Remix Solidity 编译器中的部署按钮](./remix-deploy-button.png) -点击“部署”按钮后,你可以看到合约在底部显示出来。 点击左侧的箭头展开,可以看到合约的内容。 这里有我们的变量`counter`、函数`increment()`和getter `getCounter()`。 +点击“Deploy”按钮后,您会看到您的合约出现在底部。 点击左边的箭头展开,这样就能看到我们合约的内容。 这里有我们的变量 `counter`、`increment()` 函数和 getter `getCounter()`。 -如果你点击`count`或`getCount`按钮,它将实际检索合约的`count`变量的内容,并显示出来。 因为我们尚未调用`increment`函数,它应该显示0。 +如果您点击 `count` 或 `getCount` 按钮,它将实际检索并显示合约的 `count` 变量的内容。 由于我们还没有调用 `increment` 函数,它应该显示 0。 -![Remix solidity编译器的函数按钮](./remix-function-button.png) +![Remix Solidity 编译器中的函数按钮](./remix-function-button.png) -现在点击按钮来调用`increment`函数。 你可以在窗口底部看到交易产生的日志。 当按下检索数据按钮而非`increment`按钮时,你看到的日志有所不同。 这是因为读取区块链的数据不需要任何交易(写入)或费用。 因为只有修改区块链的状态需要进行交易。 +现在我们来点击按钮,调用 `increment` 函数。 您会在窗口底部看到已执行交易的日志。 您会发现,当您按下检索数据的按钮时,日志与按下 `increment` 按钮时的日志是不同的。 这是因为在区块链上读取数据不需要任何交易(写入)或费用。 因为只有修改区块链的状态才需要进行交易: ![交易日志](./transaction-log.png) -在按下increment按钮后,将产生一个交易来调用我们的`increment()`函数,如果我们点击count或getCount按钮,将读取我们的智能合约的最新状态,count变量大于0。 +按下 increment 按钮后,会生成一个调用我们 `increment()` 函数的交易。之后,如果我们再点击 count 或 getCount 按钮,就会读取到智能合约的最新状态,其中的 count 变量值将大于 0。 -![智能合约状态的最新更新](./updated-state.png) +![智能合约的最新更新状态](./updated-state.png) -在下一个教程中,我们将论述[如何在智能合约中添加事件](/developers/tutorials/logging-events-smart-contracts/)。 记录事件是调试智能合约了解调用函数时所发生情况的方便方式。 +在下一篇教程中,我们将介绍[如何向您的智能合约添加事件](/developers/tutorials/logging-events-smart-contracts/)。 记录事件是调试您的智能合约和了解调用函数时发生的情况的便捷方式。 diff --git a/public/content/translations/zh/developers/tutorials/develop-and-test-dapps-with-a-multi-client-local-eth-testnet/index.md b/public/content/translations/zh/developers/tutorials/develop-and-test-dapps-with-a-multi-client-local-eth-testnet/index.md new file mode 100644 index 00000000000..b11c95cfb86 --- /dev/null +++ b/public/content/translations/zh/developers/tutorials/develop-and-test-dapps-with-a-multi-client-local-eth-testnet/index.md @@ -0,0 +1,363 @@ +--- +title: "如何在本地多客户端测试网上开发和测试去中心化应用程序" +description: "本指南将首先引导你完成实例化和配置多客户端本地以太坊测试网,然后使用该测试网部署和测试去中心化应用程序。" +author: "Tedi Mitiku" +tags: [ "客户端", "节点", "智能合同", "可组合性", "共识层", "执行层", "测试" ] +skill: intermediate +lang: zh +published: 2023-04-11 +--- + +## 简介 {#introduction} + +本指南将引导你完成实例化可配置的本地以太坊测试网、向其部署智能合约,以及使用该测试网对你的去中心化应用程序运行测试的整个过程。 本指南专为希望在部署到实时测试网或主网之前,根据不同的网络配置在本地开发和测试其去中心化应用程序的开发者而设计。 + +在本指南中,你将: + +- 使用 [Kurtosis](https://www.kurtosis.com/) 和 [`eth-network-package`](https://github.com/kurtosis-tech/eth-network-package) 实例化本地以太坊测试网, +- 将 Hardhat 去中心化应用程序开发环境连接到本地测试网,以编译、部署和测试去中心化应用程序,以及 +- 配置本地测试网,包括节点数量和特定 EL/CL 客户端配对等参数,以便能够根据各种网络配置进行开发和测试工作。 + +### 什么是 Kurtosis? {#what-is-kurtosis} + +[Kurtosis](https://www.kurtosis.com/) 是一个可组合的构建系统,专为配置多容器测试环境而设计。 它专门帮助开发者创建需要动态设置逻辑的可复现环境,例如区块链测试网。 + +在本指南中,Kurtosis eth-network-package 启动一个本地以太坊测试网,支持 [`geth`](https://geth.ethereum.org/) 执行层 (EL) 客户端,以及 [`teku`](https://consensys.io/teku)、[`lighthouse`](https://lighthouse.sigmaprime.io/) 和 [`lodestar`](https://lodestar.chainsafe.io/) 共识层 (CL) 客户端。 此软件包可作为 Hardhat Network、Ganache 和 Anvil 等框架中网络的可配置和可组合替代方案。 Kurtosis 为开发者提供了对其使用的测试网的更强控制力和灵活性,这也是 [以太坊基金会使用 Kurtosis 测试合并](https://www.kurtosis.com/blog/testing-the-ethereum-merge) 并继续使用它来测试网络升级的一个主要原因。 + +## 设置 Kurtosis {#setting-up-kurtosis} + +在继续之前,请确保你已: + +- 在本地计算机上[安装并启动 Docker 引擎](https://docs.kurtosis.com/install/#i-install--start-docker) +- [安装 Kurtosis 命令行界面](https://docs.kurtosis.com/install#ii-install-the-cli)(如果已安装命令行界面,则将其升级到最新版本) +- 安装 [Node.js](https://nodejs.org/en)、[yarn](https://classic.yarnpkg.com/lang/en/docs/install/#mac-stable) 和 [npx](https://www.npmjs.com/package/npx)(用于你的去中心化应用程序环境) + +## 实例化本地以太坊测试网 {#instantiate-testnet} + +要启动本地以太坊测试网,请运行: + +```python +kurtosis --enclave local-eth-testnet run github.com/kurtosis-tech/eth-network-package +``` + +注意:此命令使用 `--enclave` 标志将你的网络命名为: "local-eth-testnet"。 + +Kurtosis 会在后台打印出它为解析、验证和执行指令而采取的步骤。 最后,你应该会看到类似如下的输出: + +```python +INFO[2023-04-04T18:09:44-04:00] ====================================================== +INFO[2023-04-04T18:09:44-04:00] || Created enclave: local-eth-testnet || +INFO[2023-04-04T18:09:44-04:00] ====================================================== +Name: local-eth-testnet +UUID: 39372d756ae8 +Status: RUNNING +Creation Time: Tue, 04 Apr 2023 18:09:03 EDT + +========================================= Files Artifacts ========================================= +UUID Name +d4085a064230 cl-genesis-data +1c62cb792e4c el-genesis-data +bd60489b73a7 genesis-generation-config-cl +b2e593fe5228 genesis-generation-config-el +d552a54acf78 geth-prefunded-keys +5f7e661eb838 prysm-password +054e7338bb59 validator-keystore-0 + +========================================== User Services ========================================== +UUID Name Ports Status +e20f129ee0c5 cl-client-0-beacon http: 4000/tcp -> RUNNING + metrics: 5054/tcp -> + tcp-discovery: 9000/tcp -> 127.0.0.1:54263 + udp-discovery: 9000/udp -> 127.0.0.1:60470 +a8b6c926cdb4 cl-client-0-validator http: 5042/tcp -> 127.0.0.1:54267 RUNNING + metrics: 5064/tcp -> +d7b802f623e8 el-client-0 engine-rpc: 8551/tcp -> 127.0.0.1:54253 RUNNING + rpc: 8545/tcp -> 127.0.0.1:54251 + tcp-discovery: 30303/tcp -> 127.0.0.1:54254 + udp-discovery: 30303/udp -> 127.0.0.1:53834 + ws: 8546/tcp -> 127.0.0.1:54252 +514a829c0a84 prelaunch-data-generator-1680646157905431468 STOPPED +62bd62d0aa7a prelaunch-data-generator-1680646157915424301 STOPPED +05e9619e0e90 prelaunch-data-generator-1680646157922872635 STOPPED + +``` + +恭喜! 你使用 Kurtosis 通过 Docker 实例化了一个本地以太坊测试网,其中包含一个 CL(`lighthouse`)和一个 EL 客户端(`geth`)。 + +### 回顾 {#review-instantiate-testnet} + +在本节中,你执行了一个命令,指示 Kurtosis 使用[托管在 GitHub 上的 `eth-network-package`](https://github.com/kurtosis-tech/eth-network-package) 在 Kurtosis [Enclave](https://docs.kurtosis.com/advanced-concepts/enclaves/) 中启动一个本地以太坊测试网。 在你的 enclave 中,你会找到“文件工件”和“用户服务”。 + +你的 enclave 中的[文件工件](https://docs.kurtosis.com/advanced-concepts/files-artifacts/)包含用于引导 EL 和 CL 客户端的所有生成和使用的数据。 这些数据是使用 `prelaunch-data-generator` 服务创建的,该服务基于此 [Docker 镜像](https://github.com/ethpandaops/ethereum-genesis-generator)构建。 + +用户服务显示在你的 enclave 中运行的所有容器化服务。 你会注意到,一个同时具有 EL 客户端和 CL 客户端的节点已被创建。 + +## 将你的去中心化应用程序开发环境连接到本地以太坊测试网 {#connect-your-dapp} + +### 设置去中心化应用程序开发环境 {#set-up-dapp-env} + +现在你已经有了一个正在运行的本地测试网,你可以连接你的去中心化应用程序开发环境来使用你的本地测试网。 本指南将使用 Hardhat 框架将一个二十一点 (blackjack) 去中心化应用程序部署到你的本地测试网。 + +要设置你的去中心化应用程序开发环境,克隆包含我们的示例去中心化应用程序的代码库并安装其依赖项,请运行: + +```python +git clone https://github.com/kurtosis-tech/awesome-kurtosis.git && cd awesome-kurtosis/smart-contract-example && yarn +``` + +这里使用的 [smart-contract-example](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example) 文件夹包含使用 [Hardhat](https://hardhat.org/) 框架的去中心化应用程序开发者的典型设置: + +- [`contracts/`](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example/contracts) 包含一些用于二十一点 (Blackjack) 去中心化应用程序的简单智能合约 +- [`scripts/`](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example/scripts) 包含一个脚本,用于将代币合约部署到你的本地以太坊网络 +- [`test/`](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/smart-contract-example/test) 包含一个针对你的代币合约的简单 .js 测试,用于确认我们的二十一点 (Blackjack) 去中心化应用程序中的每个玩家都已铸造了 1000 枚代币 +- [`hardhat.config.ts`](https://github.com/kurtosis-tech/awesome-kurtosis/blob/main/smart-contract-example/hardhat.config.ts) 用于配置你的 Hardhat 设置 + +### 配置 Hardhat 以使用本地测试网 {#configure-hardhat} + +设置好去中心化应用程序开发环境后,你现在将连接 Hardhat 以使用 Kurtosis 生成的本地以太坊测试网。 为此,请将你的 `hardhat.config.ts` 配置文件中 `localnet` 结构里的 `<$YOUR_PORT>` 替换为任何 `el-client-` 服务的 RPC URI 输出端口。 在本示例案例中,端口为 `64248`。 你的端口会有所不同。 + +`hardhat.config.ts` 中的示例: + +```js +localnet: { +url: 'http://127.0.0.1:<$YOUR_PORT>',// TODO:将 $YOUR_PORT 替换为以太坊网络 Kurtosis 包生成的节点 URI 的端口 + +// 这些是与 eth-network-package 创建的预置资金的测试帐户关联的私钥 +// +accounts: [ + "ef5177cd0b6b21c87db5a0bf35d4084a8a57a9d6a064f86d51ac85f2b873a4e2", + "48fcc39ae27a0e8bf0274021ae6ebd8fe4a0e12623d61464c498900b28feb567", + "7988b3a148716ff800414935b305436493e1f25237a2a03e5eebc343735e2f31", + "b3c409b6b0b3aa5e65ab2dc1930534608239a478106acf6f3d9178e9f9b00b35", + "df9bb6de5d3dc59595bcaa676397d837ff49441d211878c024eabda2cd067c9f", + "7da08f856b5956d40a72968f93396f6acff17193f013e8053f6fbb6c08c194d6", + ], +}, +``` + +保存文件后,你的 Hardhat 去中心化应用程序开发环境就已连接到你的本地以太坊测试网! 你可以通过运行以下命令来验证你的测试网是否正常工作: + +```python +npx hardhat balances --network localnet +``` + +输出应如下所示: + +```python +0x878705ba3f8Bc32FCf7F4CAa1A35E72AF65CF766 has balance 10000000000000000000000000 +0x4E9A3d9D1cd2A2b2371b8b3F489aE72259886f1A has balance 10000000000000000000000000 +0xdF8466f277964Bb7a0FFD819403302C34DCD530A has balance 10000000000000000000000000 +0x5c613e39Fc0Ad91AfDA24587e6f52192d75FBA50 has balance 10000000000000000000000000 +0x375ae6107f8cC4cF34842B71C6F746a362Ad8EAc has balance 10000000000000000000000000 +0x1F6298457C5d76270325B724Da5d1953923a6B88 has balance 10000000000000000000000000 +``` + +这证实了 Hardhat 正在使用你的本地测试网,并检测到由 `eth-network-package` 创建的预置资金的帐户。 + +### 在本地部署和测试你的去中心化应用程序 {#deploy-and-test-dapp} + +在去中心化应用程序开发环境完全连接到本地以太坊测试网后,你现在可以使用本地测试网对你的去中心化应用程序运行开发和测试工作流。 + +要编译和部署 `ChipToken.sol` 智能合约以进行本地原型设计和开发,请运行: + +```python +npx hardhat compile +npx hardhat run scripts/deploy.ts --network localnet +``` + +输出应如下所示: + +```python +ChipToken 已部署到: 0xAb2A01BC351770D09611Ac80f1DE076D56E0487d +``` + +现在尝试对你的本地去中心化应用程序运行 `simple.js` 测试,以确认我们的二十一点 (Blackjack) 去中心化应用程序中的每个玩家都铸造了 1000 枚代币: + +输出应如下所示: + +```python +npx hardhat test --network localnet +``` + +输出应如下所示: + +```python +ChipToken + mint + ✔ 应该为 PLAYER ONE 铸造 1000 个筹码 + + 1 个通过 (654ms) +``` + +### 回顾 {#review-dapp-workflows} + +至此,你已经设置好一个去中心化应用程序开发环境,将其连接到由 Kurtosis 创建的本地以太坊网络,并已对你的去中心化应用程序进行了编译、部署和简单测试。 + +现在,让我们探讨如何配置底层网络,以便在不同的网络配置下测试我们的去中心化应用程序。 + +## 配置本地以太坊测试网 {#configure-testnet} + +### 更改客户端配置和节点数量 {#configure-client-config-and-num-nodes} + +你的本地以太坊测试网可以配置为使用不同的 EL 和 CL 客户端对,以及不同数量的节点,具体取决于你想要开发或测试的场景和特定网络配置。 这意味着,一旦设置好,你就可以启动一个自定义的本地测试网,并用它来运行相同的工作流(部署、测试等)。 在各种网络配置下,以确保一切都按预期工作。 要了解有关可以修改的其他参数的更多信息,请访问此链接。 + +试试看! 你可以通过 JSON 文件将各种配置选项传递给 `eth-network-package`。 此网络参数 JSON 文件提供了 Kurtosis 将用于设置本地以太坊网络的具体配置。 + +获取默认配置文件并对其进行编辑,以启动具有不同 EL/CL 对的三个节点: + +- 节点 1:`geth`/`lighthouse` +- 节点 2:`geth`/`lodestar` +- 节点 3:`geth`/`teku` + +此配置创建了一个由以太坊节点实现组成的异构网络,用于测试你的去中心化应用程序。 你的配置文件现在应如下所示: + +```yaml +{ + "participants": + [ + { + "el_client_type": "geth", + "el_client_image": "", + "el_client_log_level": "", + "cl_client_type": "lighthouse", + "cl_client_image": "", + "cl_client_log_level": "", + "beacon_extra_params": [], + "el_extra_params": [], + "validator_extra_params": [], + "builder_network_params": null, + }, + { + "el_client_type": "geth", + "el_client_image": "", + "el_client_log_level": "", + "cl_client_type": "lodestar", + "cl_client_image": "", + "cl_client_log_level": "", + "beacon_extra_params": [], + "el_extra_params": [], + "validator_extra_params": [], + "builder_network_params": null, + }, + { + "el_client_type": "geth", + "el_client_image": "", + "el_client_log_level": "", + "cl_client_type": "teku", + "cl_client_image": "", + "cl_client_log_level": "", + "beacon_extra_params": [], + "el_extra_params": [], + "validator_extra_params": [], + "builder_network_params": null, + }, + ], + "network_params": + { + "preregistered_validator_keys_mnemonic": "giant issue aisle success illegal bike spike question tent bar rely arctic volcano long crawl hungry vocal artwork sniff fantasy very lucky have athlete", + "num_validator_keys_per_node": 64, + "network_id": "3151908", + "deposit_contract_address": "0x4242424242424242424242424242424242424242", + "seconds_per_slot": 12, + "genesis_delay": 120, + "capella_fork_epoch": 5, + }, +} +``` + +每个 `participants` 结构都映射到网络中的一个节点,因此 3 个 `participants` 结构将告诉 Kurtosis 在你的网络中启动 3 个节点。 每个 `participants` 结构都允许你指定用于该特定节点的 EL 和 CL 对。 + +`network_params` 结构配置网络设置,这些设置用于为每个节点创建创世文件,以及网络的每时隙秒数等其他设置。 + +将编辑后的参数文件保存在你希望的任何目录中(在下面的示例中,它保存在桌面上),然后通过运行以下命令来使用它运行你的 Kurtosis 包: + +```python +kurtosis clean -a && kurtosis run --enclave local-eth-testnet github.com/kurtosis-tech/eth-network-package "$(cat ~/eth-network-params.json)" +``` + +注意:此处使用 `kurtosis clean -a` 命令来指示 Kurtosis 在启动新测试网之前销毁旧测试网及其内容。 + +同样,Kurtosis 会运行一会并打印出正在执行的各个步骤。 最终,输出应如下所示: + +```python +Starlark code successfully run. No output was returned. +INFO[2023-04-07T11:43:16-04:00] ========================================================== +INFO[2023-04-07T11:43:16-04:00] || Created enclave: local-eth-testnet || +INFO[2023-04-07T11:43:16-04:00] ========================================================== +Name: local-eth-testnet +UUID: bef8c192008e +Status: RUNNING +Creation Time: Fri, 07 Apr 2023 11:41:58 EDT + +========================================= Files Artifacts ========================================= +UUID Name +cc495a8e364a cl-genesis-data +7033fcdb5471 el-genesis-data +a3aef43fc738 genesis-generation-config-cl +8e968005fc9d genesis-generation-config-el +3182cca9d3cd geth-prefunded-keys +8421166e234f prysm-password +d9e6e8d44d99 validator-keystore-0 +23f5ba517394 validator-keystore-1 +4d28dea40b5c validator-keystore-2 + +========================================== User Services ========================================== +UUID Name Ports Status +485e6fde55ae cl-client-0-beacon http: 4000/tcp -> http://127.0.0.1:65010 RUNNING + metrics: 5054/tcp -> http://127.0.0.1:65011 + tcp-discovery: 9000/tcp -> 127.0.0.1:65012 + udp-discovery: 9000/udp -> 127.0.0.1:54455 +73739bd158b2 cl-client-0-validator http: 5042/tcp -> 127.0.0.1:65016 RUNNING + metrics: 5064/tcp -> http://127.0.0.1:65017 +1b0a233cd011 cl-client-1-beacon http: 4000/tcp -> 127.0.0.1:65021 RUNNING + metrics: 8008/tcp -> 127.0.0.1:65023 + tcp-discovery: 9000/tcp -> 127.0.0.1:65024 + udp-discovery: 9000/udp -> 127.0.0.1:56031 + validator-metrics: 5064/tcp -> 127.0.0.1:65022 +949b8220cd53 cl-client-1-validator http: 4000/tcp -> 127.0.0.1:65028 RUNNING + metrics: 8008/tcp -> 127.0.0.1:65030 + tcp-discovery: 9000/tcp -> 127.0.0.1:65031 + udp-discovery: 9000/udp -> 127.0.0.1:60784 + validator-metrics: 5064/tcp -> 127.0.0.1:65029 +c34417bea5fa cl-client-2 http: 4000/tcp -> 127.0.0.1:65037 RUNNING + metrics: 8008/tcp -> 127.0.0.1:65035 + tcp-discovery: 9000/tcp -> 127.0.0.1:65036 + udp-discovery: 9000/udp -> 127.0.0.1:63581 +e19738e6329d el-client-0 engine-rpc: 8551/tcp -> 127.0.0.1:64986 RUNNING + rpc: 8545/tcp -> 127.0.0.1:64988 + tcp-discovery: 30303/tcp -> 127.0.0.1:64987 + udp-discovery: 30303/udp -> 127.0.0.1:55706 + ws: 8546/tcp -> 127.0.0.1:64989 +e904687449d9 el-client-1 engine-rpc: 8551/tcp -> 127.0.0.1:64993 RUNNING + rpc: 8545/tcp -> 127.0.0.1:64995 + tcp-discovery: 30303/tcp -> 127.0.0.1:64994 + udp-discovery: 30303/udp -> 127.0.0.1:58096 + ws: 8546/tcp -> 127.0.0.1:64996 +ad6f401126fa el-client-2 engine-rpc: 8551/tcp -> 127.0.0.1:65003 RUNNING + rpc: 8545/tcp -> 127.0.0.1:65001 + tcp-discovery: 30303/tcp -> 127.0.0.1:65000 + udp-discovery: 30303/udp -> 127.0.0.1:57269 + ws: 8546/tcp -> 127.0.0.1:65002 +12d04a9dbb69 prelaunch-data-generator-1680882122181135513 STOPPED +5b45f9c0504b prelaunch-data-generator-1680882122192182847 STOPPED +3d4aaa75e218 prelaunch-data-generator-1680882122201668972 STOPPED +``` + +恭喜! 你已成功将本地测试网配置为 3 个节点,而不是 1 个。 要对你的去中心化应用程序运行与之前相同的工作流(部署和测试),请执行与之前相同的操作,将你的 `hardhat.config.ts` 配置文件中 `localnet` 结构里的 `<$YOUR_PORT>` 替换为新的 3 节点本地测试网中任何 `el-client-` 服务的 RPC URI 输出端口。 + +## 结论 {#conclusion} + +就这些! 回顾这篇简短的指南,你: + +- 使用 Kurtosis 通过 Docker 创建了一个本地以太坊测试网 +- 将你的本地去中心化应用程序开发环境连接到本地以太坊网络 +- 在本地以太坊网络上部署了一个去中心化应用程序并对其进行了简单测试 +- 将底层以太坊网络配置为 3 个节点 + +我们很乐意听取你的意见,哪些方面做得好,哪些方面可以改进,或者回答你的任何问题。 请随时通过 [GitHub](https://github.com/kurtosis-tech/kurtosis/issues/new/choose) 或[发送电子邮件](mailto:feedback@kurtosistech.com)与我们联系! + +### 其他示例和指南 {#other-examples-guides} + +我们鼓励你查看我们的[快速入门](https://docs.kurtosis.com/quickstart)(你将在其中构建一个 Postgres 数据库和 API)以及我们 [awesome-kurtosis 代码库](https://github.com/kurtosis-tech/awesome-kurtosis)中的其他示例,你将在其中找到一些很棒的示例,包括用于以下用途的包: + +- [启动同一个本地以太坊测试网](https://github.com/kurtosis-tech/eth2-package),但连接了额外的服务,例如交易垃圾信息发送器(用于模拟交易)、分叉监控器以及连接的 Grafana 和 Prometheus 实例 +- 对同一个本地以太坊网络执行[子网络测试](https://github.com/kurtosis-tech/awesome-kurtosis/tree/main/ethereum-network-partition-test) diff --git a/public/content/translations/zh/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/index.md b/public/content/translations/zh/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/index.md index a9df421999e..8b4f1cf170d 100644 --- a/public/content/translations/zh/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/index.md +++ b/public/content/translations/zh/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/index.md @@ -1,12 +1,9 @@ --- title: "如何缩减合约以规避合约大小限制" -description: 您可以做些什么避免智能合约变得太大? +description: "你可以做些什么避免智能合约变得太大?" author: Markus Waas lang: zh -tags: - - "solidity" - - "智能合约" - - "存储" +tags: [ "Solidity", "智能合同", "存储" ] skill: intermediate published: 2020-06-26 source: soliditydeveloper.com @@ -15,46 +12,44 @@ sourceUrl: https://soliditydeveloper.com/max-contract-size ## 为什么会有限制? {#why-is-there-a-limit} -在 [2016 年 11 月 22 日](https://blog.ethereum.org/2016/11/18/hard-fork-no-4-spurious-dragon/),伪龙硬分叉引入了 [EIP-170](https://eips.ethereum.org/EIPS/eip-170),将智能合约的大小限制在 24.576 kb。 对于作为 Solidity 开发者的您来说,这意味着当您向合约中添加越来越多的功能时,在某个时候您会达到极限,并且在部署时会看到错误: +在 [2016 年 11 月 22 日](https://blog.ethereum.org/2016/11/18/hard-fork-no-4-spurious-dragon/),Spurious Dragon 硬分叉引入了 [EIP-170](https://eips.ethereum.org/EIPS/eip-170),增加了 24.576 kb 的智能合约大小限制。 对于 Solidity 开发者来说,这意味着当你向合约中添加越来越多的功能时,在某个时候你会达到限制,并且在部署时会看到错误: -`警告:合约代码大小超过 24576 字节(Spurious Dragon 分叉中引入的限制)。 该合约可能无法在主网上部署。 请考虑启用优化器(其“运行”值较低!),关闭 revert 字符串,或使用库。` +`警告:合约代码大小超过 24576 字节(Spurious Dragon 分叉中引入的限制)。 该合约可能无法在主网上部署。 请考虑启用优化器(“运行”值较低!)、关闭 revert 字符串或使用程序库。` -引入这一限制是为了防止拒绝服务 (DOS) 攻击。 任何对合约的调用从矿工费上来说都是相对便宜的。 然而,根据被调用合约代码的大小(从磁盘读取代码、预处理代码、将数据添加到 Merkle 证明),合约调用对以太坊节点的影响会不成比例地增加。 每当您出现这样的情况,攻击者只需要很少的资源就能给别人造成大量的工作,您就有可能遭受 DOS 攻击。 +引入这一限制是为了防止拒绝服务 (DOS) 攻击。 就燃料而言,对合约的任何调用都相对便宜。 然而,根据被调用合约代码的大小(从磁盘读取代码、预处理代码、将数据添加到 Merkle 证明),合约调用对以太坊节点的影响会不成比例地增加。 每当你出现这样的情况,攻击者只需要很少的资源就能给别人造成大量的工作,你就有可能遭受 DOS 攻击。 -最初,这不是什么大问题,因为一个自然合约大小限制是区块燃料限制。 显然,合约必须和其所有字节码一起部署在交易内。 如果只将单个交易添加到区块中,可能会用完所有燃料,而燃料并非无限。 [伦敦升级](/ethereum-forks/#london)后,区块燃料限制已能够根据网络需求在 15M 和 30M 单位之间变动。 +最初,这不是什么大问题,因为一个天然的合约大小限制就是区块燃料限制。 显然,合约必须和其所有字节码一起部署在交易内。 如果只将单个交易添加到区块中,可能会用完所有燃料,而燃料并非无限。 自从[伦敦升级](/ethereum-forks/#london)后,区块燃料限制便可根据网络需求在 15M 和 30M 单位之间变化。 -在下文中,我们将根据其潜在的影响顺序来研究一些方法。 从减肥的角度来谈一谈。 对于一个人来说,要达到他们的目标体重(在我们的例子中是 24 kb),最好的策略是首先关注影响较大的方法。 在大多数情况下,只要调整您的饮食就能达到目标,但有时您需要做得更多一些。 然后您可以增加一些锻炼(中等影响)或甚至补充剂(小影响)。 +在下文中,我们将根据其潜在的影响顺序来研究一些方法。 从减肥的角度来谈一谈。 对于一个人来说,要达到他们的目标体重(在我们的例子中是 24 kb),最好的策略是首先关注影响较大的方法。 在大多数情况下,只要调整你的饮食就能达到目标,但有时你需要做得更多一些。 然后你可以增加一些锻炼(中等影响)或甚至补充剂(小影响)。 -## 较大影响 {#big-impact} +## 重大影响 {#big-impact} -### 把合约分开 {#separate-your-contracts} +### 拆分合约 {#separate-your-contracts} -这应始终是您的第一个方法。 如何将合约分成多个较小的合约? 一般来说,它会迫使您为您的合约想出一个好的架构。 从代码可读性的角度来看,较小的合约总是首选。 对于拆分合同,请问您自己: +这应始终是你的首选方法。 如何将合约分成多个较小的合约? 一般来说,它会迫使你为你的合约想出一个好的架构。 从代码可读性的角度来看,较小的合约总是首选。 对于拆分合约,问问你自己: - 哪些函数属于同一类? 每一组函数最好能在自己的合约中。 - 哪些函数不需要读取合约状态或仅需要读取状态的特定子集? -- 您能把存储和功能分开吗? +- 你能把存储和功能分开吗? -### 使用库 {#libraries} +### 程序库 {#libraries} -将功能代码移出存储空间的一个简单方法是使用[库](https://solidity.readthedocs.io/en/v0.6.10/contracts.html#libraries)。 不要将库函数声明为内部函数,因为这些函数将在编译过程中直接被[添加到合约中](https://ethereum.stackexchange.com/questions/12975/are-internal-functions-in-libraries-not-covered-by-linking)。 但是,如果您使用公共函数,那么这些函数事实上将在一个单独的库合约中。 可以考虑使用命令 [using for](https://solidity.readthedocs.io/en/v0.6.10/contracts.html#using-for),使库的使用更加方便。 +将功能代码与存储分离的一个简单方法是使用[程序库](https://solidity.readthedocs.io/en/v0.6.10/contracts.html#libraries)。 不要将程序库函数声明为 internal,因为它们会在编译期间直接[添加到合约中](https://ethereum.stackexchange.com/questions/12975/are-internal-functions-in-libraries-not-covered-by-linking)。 但是,如果你使用 public 函数,那么这些函数实际上会位于一个单独的程序库合约中。 考虑[使用 using for](https://solidity.readthedocs.io/en/v0.6.10/contracts.html#using-for) 使程序库的使用更加方便。 -### 使用代理 {#proxies} +### 代理 {#proxies} -一个更先进的策略是代理系统。 库在后台使用 `DELEGATECALL`,它只是用调用合约的状态执行另一个合约的函数。 查看[这篇博客文章](https://hackernoon.com/how-to-make-smart-contracts-upgradable-2612e771d5a2)来了解更多关于代理系统的信息。 它们可以为您提供了更多的功能,例如它们能够升级,但它们也增加了很多复杂性。 我不会仅仅为了减少合约的大小而增加这些东西,除非由于某种原因这是唯一的选择。 +一个更先进的策略是代理系统。 程序库在后台使用 `DELEGATECALL`,它只是用调用合约的状态来执行另一个合约的函数。 查看[这篇博文](https://hackernoon.com/how-to-make-smart-contracts-upgradable-2612e771d5a2)以了解更多关于代理系统的信息。 它们提供了更多功能(例如,支持可升级性),但同时也增加了很多复杂性。 我不会仅仅为了减少合约大小而添加这些,除非出于某种原因这是你唯一的选择。 ## 中等影响 {#medium-impact} ### 移除函数 {#remove-functions} -这一点应该是显而易见的, 即函数在一定程度上会增加合约的大小。 +这一点应该很明显。 函数会显著增加合约的大小。 -- **外部函数**:为了方便起见,我们常常添加大量视图函数。 这完全没有问题,直到您遇到大小限制。 然后,您可能需要真正考虑,移除绝对必要以外的所有内容。 -- **内部函数**:您也可以移除内部/ 私有函数,只要函数只被调用一次,就可以简单地内联代码。 +- **外部**:我们常常为了方便而添加许多视图函数。 这完全没问题,直到你达到大小限制。 这时,你可能就要认真考虑,只保留绝对必要的函数。 +- **Internal**:只要函数只被调用一次,你也可以移除 internal/private 函数,并直接内联代码。 -### 避免额外的变量 {#avoid-additional-variables} - -像这样一个简单的更改: +### 避免使用额外的变量 {#avoid-additional-variables} ```solidity function get(uint id) returns (address,address) { @@ -69,30 +64,41 @@ function get(uint id) returns (address,address) { } ``` -大小差异为** 0.28kb**。 您有可能在合约中找到许多类似的情况,这些情况加起来可以达到很大的数额。 +这样一个简单的改动就能产生 **0.28kb** 的差异。 你有可能在合约中找到许多类似的情况,这些情况加起来可以达到很大的数额。 ### 缩短错误信息 {#shorten-error-message} -长的恢复信息,尤其是许多不同的回滚消息可能会使合约变得臃肿。 相反,使用简短的错误代码,并在合约中对其进行解码。 一条长信息可以变得很短: +过长的 revert 信息,特别是许多不同的 revert 信息,可能会使合约变得臃肿。 可以改用简短的错误代码,然后在你的客户端解码它们。 一条长信息可以变得短很多: ```solidity -require(msg.sender == owner, "Only the owner of this contract can call this function"); - +require(msg.sender == owner, "只有本合约的所有者才能调用此函数"); ``` ```solidity require(msg.sender == owner, "OW1"); ``` -### 在优化器中考虑一个低运行值 {#consider-a-low-run-value-in-the-optimizer} +### 使用自定义错误代替错误信息 + +[Solidity 0.8.4](https://blog.soliditylang.org/2021/04/21/custom-errors/) 引入了自定义错误。 它们是减小合约大小的极佳方法,因为它们和函数一样,被 ABI 编码为选择器。 + +```solidity +error Unauthorized(); + +if (msg.sender != owner) { + revert Unauthorized(); +} +``` + +### 考虑在优化器中使用较低的运行值 {#consider-a-low-run-value-in-the-optimizer} -您也可以更改优化器设置。 默认值为 200,表示它试图在一个函数被调用 200 次的情况下优化字节码。 如果您将其改为 1,相当于告诉优化器针对每个函数只运行一次的情况进行优化。 一个仅运行一次的优化函数意味着它对部署本身进行了优化。 请注意,**这将会增加运行函数的 [gas 成本](/developers/docs/gas/)**,所以,您可能不想这样做。 +你也可以更改优化器设置。 默认值为 200,表示它试图在一个函数被调用 200 次的情况下优化字节码。 如果将其更改为 1,基本上就是告诉优化器针对每个函数只运行一次的情况进行优化。 一个仅运行一次的优化函数意味着它对部署本身进行了优化。 请注意,**这会增加运行函数的[燃料成本](/developers/docs/gas/)**,所以你可能不希望这样做。 -## 轻微的影响 {#small-impact} +## 较小影响 {#small-impact} ### 避免将结构体传递给函数 {#avoid-passing-structs-to-functions} -如果您正在使用 [ABIEncoderV2](https://solidity.readthedocs.io/en/v0.6.10/layout-of-source-files.html#abiencoderv2),它可以帮助您不将结构体传递给函数。 不会将参数作为结构体传递... +如果你正在使用 [ABIEncoderV2](https://solidity.readthedocs.io/en/v0.6.10/layout-of-source-files.html#abiencoderv2),不将结构体传递给函数会有所帮助。 不要将参数作为结构体传递,而是直接传递所需的参数。 在这个例子中,我们又节省了 **0.1kb**。 ```solidity function get(uint id) returns (address,address) { @@ -114,16 +120,14 @@ function _get(address addr1, address addr2) private view returns(address,address } ``` -... 而是直接传递所需参数。 在此示例中,我们又节省了 **0.1kb**。 - -### 声明函数和变量的正确可见性 {#declare-correct-visibility-for-functions-and-variables} +### 为函数和变量声明正确的可见性 {#declare-correct-visibility-for-functions-and-variables} -- 函数或变量仅从外部调用? 那么,将他们声明为 `external` 而不是 `public`。 -- 函数或变量仅从合约内调用? 那么,将它们声明为 `private` 或 `internal` 而不是 `public`。 +- 函数或变量只从外部调用? 将它们声明为 `external` 而不是 `public`。 +- 函数或变量只从合约内部调用? 将它们声明为 `private` 或 `internal` 而不是 `public`。 -### 移除修改器 {#remove-modifiers} +### 移除修饰符 {#remove-modifiers} -修改器,尤其是在密集使用的情况下,可能会对合约大小产生重大影响。 可以考虑移除它们,而改用函数。 +修饰符,尤其是在密集使用的情况下,可能会对合约大小产生重大影响。 可以考虑移除它们,改用函数。 ```solidity modifier checkStuff() {} @@ -137,4 +141,4 @@ function checkStuff() private {} function doSomething() { checkStuff(); } ``` -这些提示应有助您大幅度减少合约的大小。 我要再次强调的是,如果可能的话,务必将重点放在拆分合约上,以获得最大的效果。 +这些技巧应该能帮助你显著减小合约的大小。 我要再次强调的是,如果可能的话,务必将重点放在拆分合约上,以获得最大的效果。 diff --git a/public/content/translations/zh/developers/tutorials/eip-1271-smart-contract-signatures/index.md b/public/content/translations/zh/developers/tutorials/eip-1271-smart-contract-signatures/index.md index 8a1eda2b413..6c5d1038884 100644 --- a/public/content/translations/zh/developers/tutorials/eip-1271-smart-contract-signatures/index.md +++ b/public/content/translations/zh/developers/tutorials/eip-1271-smart-contract-signatures/index.md @@ -1,13 +1,9 @@ --- title: "EIP-1271:签署和验证智能合约签名" -description: 基于 EIP-1271 的智能合约签名生成与验证概述。 我们还介绍了 Safe(原 Gnosis Safe)中使用的 EIP-1271 实现,以此为智能合约开发者提供一个可参考的具体例子。 +description: "基于 EIP-1271 的智能合约签名生成与验证概述。 我们还介绍了 Safe(原 Gnosis Safe)中使用的 EIP-1271 实现,以此为智能合约开发者提供一个可参考的具体例子。" author: Nathan H. Leung lang: zh -tags: - - "eip-1271" - - "智能合约" - - "验证" - - "签名" +tags: [ "eip-1271", "智能合同", "验证", "签署" ] skill: intermediate published: 2023-01-12 --- @@ -24,7 +20,7 @@ published: 2023-01-12 1. 信息:“我想用我的以太坊钱包登录这个网站” 2. 签名者:我的地址是 `0x000…` -3. 证明:这里有一些证明,证明我,`0x000…`,确实创建了这整条信息(通常会加密)。 +3. 证明:这里有一些证据,证明我 `0x000…` 确实创建了这整条信息(这通常是加密的)。 值得注意的是,数字签名包括“信息”和“签名”两部分。 @@ -36,11 +32,11 @@ published: 2023-01-12 要在基于以太坊的区块链上创建数字签名,通常需要一个别人不知道的秘密私钥。 这样,你的签名才是你的(如果其他人不知道密钥,则无法创建相同的签名)。 -你的以太坊帐户(即你的外部帐户/EOA)有一个与之关联的私钥,这是通常在网站或去中心化应用程序要求你签名时使用的私钥(例如“使用以太坊登录”)。 +你的以太坊帐户(即你的外部持有帐户/EOA)有一个与之关联的私钥,当网站或去中心化应用程序要求你签名时(例如,用于“通过以太坊登录”),通常会使用此私钥。 -应用程序可以在[不知道你的私钥](https://en.wikipedia.org/wiki/Public-key_cryptography)的情况下[验证你使用 ethers.js 等第三方库创建的签名](https://docs.alchemy.com/docs/how-to-verify-a-message-signature-on-ethereum),并且确认_你_是那个创建签名的人。 +应用程序可以使用 ethers.js 等第三方库来[验证你创建的签名](https://www.alchemy.com/docs/how-to-verify-a-message-signature-on-ethereum),同时[无需知道你的私钥](https://en.wikipedia.org/wiki/Public-key_cryptography),并确信签名是由_你_创建的。 -> 事实上,由于外部帐户数字签名使用公钥加密,可以在**链下**生成和验证! 这就是无燃料去中心化自治组织投票的工作原理—并非在链上提交投票,而是使用加密库在链下创建和验证数字签名。 +> 事实上,由于 EOA 数字签名使用公钥密码学,它们可以在**链下**生成和验证! 这就是免 Gas 的 DAO 投票的运作方式 — 无需在链上提交投票,而是使用加密库在链下创建和验证数字签名。 虽然外部帐户帐户有私钥,但智能合约帐户没有任何类型的私钥或密钥(因此“使用以太坊登录”等自然不适用于智能合约帐户)。 @@ -50,13 +46,13 @@ EIP-1271 旨在解决:如果智能合约没有可以合并到签名中的密 智能合约没有可用于签署信息的私钥。 那么,我们如何辨别签名的真伪呢? -有一种想法是,我们可以直接_询问_智能合约签名是否真实! +嗯,有一个想法是,我们可以直接_询问_智能合约签名是否真实! EIP-1271 所做的就是将“询问”智能合约给定签名是否有效这一想法标准化。 实现 EIP-1271 的合约必须有一个名为 `isValidSignature` 的函数,该函数接收信息和签名。 然后,合约可以运行一些验证逻辑(规范并没有在此强制执行任何特定内容),然后返回一个表示签名是否有效的值。 -如果 `isValidSignature` 返回表示签名有效的结果,这就相当于合约在说“是的,我承认这个签名和信息!” +如果 `isValidSignature` 返回有效的结果,那基本上就是合约在说“是的,我批准这个签名 + 信息!” ### 接口 @@ -71,13 +67,13 @@ contract ERC1271 { bytes4 constant internal MAGICVALUE = 0x1626ba7e; /** - * @dev Should return whether the signature provided is valid for the provided hash - * @param _hash Hash of the data to be signed - * @param _signature Signature byte array associated with _hash + * @dev 应返回所提供的签名对于所提供的哈希是否有效 + * @param _hash 待签名数据的哈希值 + * @param _signature 与 _hash 关联的签名字节数组 * - * MUST return the bytes4 magic value 0x1626ba7e when function passes. - * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5) - * MUST allow external calls + * 函数通过时必须返回 bytes4 魔术值 0x1626ba7e。 + * 不得修改状态(solc < 0.5 使用 STATICCALL,solc > 0.5 使用 view 修饰符) + * 必须允许外部调用 */ function isValidSignature( bytes32 _hash, @@ -90,28 +86,28 @@ contract ERC1271 { ## EIP-1271 实现示例:安全 -合约可通过多种方式实现 `isValidSignature`—规范本身对具体实现没有做出太多要求。 +合约可通过多种方式实现 `isValidSignature` — 规范本身对具体实现没有做出太多要求。 实现 EIP-1271 的一个代表性合约是 Safe(原 Gnosis Safe)。 -在 Safe 的代码中,[实现了 ](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol) `isValidSignature`,从而使签名可通过以下[两种方式](https://ethereum.stackexchange.com/questions/122635/signing-messages-as-a-gnosis-safe-eip1271-support)创建和验证: +在 Safe 的代码中,`isValidSignature` 的[实现方式](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol)使得签名可以通过[两种方式](https://ethereum.stackexchange.com/questions/122635/signing-messages-as-a-gnosis-safe-eip1271-support)创建和验证: -1. 链上消息 +1. 链上信息 1. 创建:一个安全的所有者创建一个新的安全交易来“签名”一则消息,并将消息作为数据传入交易中。 一旦足够的所有者对交易进行签名,使签名数量达到多签名阈值后,交易就会被广播并运行。 在交易中,会调用一个安全函数,将消息添加到“已批准”消息列表中。 - 2. 验证:调用 Safe 合约的 `isValidSignature` 函数,并传入待验证的消息作为消息参数,传入[一个空值作为签名参数](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol#L32)(即 `0x`)。 Safe 合约会看到签名参数为空,将不会对签名进行密码验证,而是直接检查消息是否在“已批准”消息列表中。 + 2. 验证:在 Safe 合约上调用 `isValidSignature`,将被验证的信息作为信息参数传入,并为[签名参数传入一个空值](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol#L32)(即 `0x`)。 Safe 合约会看到签名参数为空,将不会对签名进行密码验证,而是直接检查消息是否在“已批准”消息列表中。 2. 链下信息: - 1. 创建:安全的所有者在链下创建一条消息,然后让其他安全的所有者分别对消息进行签名,直到有足够的签名来达到多签名批准阈值。 - 2. 验证:调用 `isValidSignature`。 在消息参数中,传入要验证的消息。 在签名参数中,传入每个安全所有者的签名,所有签名都是背靠背连接在一起的。 Safe 合约会检查是否有足够签名以达到阈值,**并**检查每个签名的有效性。 如果是,它将返回一个表示签名验证成功的值。 + 1. 创建:Safe 所有者在链下创建一条信息,然后让其他 Safe 所有者分别对该信息进行签名,直到有足够的签名来满足多重签名批准阈值。 + 2. 验证:调用 `isValidSignature`。 在消息参数中,传入要验证的消息。 在签名参数中,传入每个安全所有者的签名,所有签名都是背靠背连接在一起的。 Safe 将检查签名数量是否足以达到阈值,**并且**每个签名都有效。 如果是,它将返回一个表示签名验证成功的值。 ## `_hash` 参数到底是什么? 为什么不传递整条消息? -你可能已经发现,[EIP-1271 接口](https://eips.ethereum.org/EIPS/eip-1271)中的 `isValidSignature` 函数并不接收消息本身,而是使用 `_hash` 参数。 这意味着我们只需将消息的 32 个字节长的哈希值(一般通过 keccak256)传入 `isValidSignature`,而不是传入任意长度的完整消息。 +你可能已经注意到,[EIP-1271 接口](https://eips.ethereum.org/EIPS/eip-1271)中的 `isValidSignature` 函数并不接收信息本身,而是接收一个 `_hash` 参数。 这意味着我们不是将完整的任意长度信息传递给 `isValidSignature`,而是传递该信息的 32 字节哈希值(通常是 keccak256)。 -calldata 的每一个字节(即传入智能合约函数的函数参数数据)都会[花费 16 个单位燃料(若为空字节,则会花费 4 上单位燃料)](https://eips.ethereum.org/EIPS/eip-2028),因此在消息较长时,这可以节省很多的燃料费。 +calldata 的每个字节——即传递给智能合约函数的函数参数数据——[会花费 16 Gas(如果为零字节,则花费 4 Gas)](https://eips.ethereum.org/EIPS/eip-2028),因此如果信息很长,可以节省大量 Gas。 ### 先前的 EIP-1271 规范 -现有 EIP-1271 规范中的 `isValidSignature` 函数,其第一个参数为 `bytes` 类型(任意长度,而不是固定长度的 `bytes32`),并且参数名为 `message`。 这是 EIP-1271 标准的一个[旧版本](https://github.com/safe-global/safe-contracts/issues/391#issuecomment-1075427206)。 +在实际中存在一些 EIP-1271 规范,它们的 `isValidSignature` 函数第一个参数的类型为 `bytes`(任意长度,而不是固定长度的 `bytes32`),参数名为 `message`。 这是 EIP-1271 标准的[一个旧版本](https://github.com/safe-global/safe-contracts/issues/391#issuecomment-1075427206)。 ## 如何在我的合约中实现 EIP-1271? @@ -122,6 +118,6 @@ calldata 的每一个字节(即传入智能合约函数的函数参数数据 最终,都将由作为合约开发者的你来决定! -## 结论 +## 总结 [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) 是一个允许智能合约验证签名的通用标准。 它为智能合约打开了一扇门,使其行为更像外部帐户(例如,为“使用以太坊登录”提供一种与智能合约协同工作的方式),而且它可通过多种方式实现(例如 Safe 有一个有用且有趣的实现方式值得考虑)。 diff --git a/public/content/translations/zh/developers/tutorials/erc-721-vyper-annotated-code/index.md b/public/content/translations/zh/developers/tutorials/erc-721-vyper-annotated-code/index.md index b22617d525b..486aff8a6ce 100644 --- a/public/content/translations/zh/developers/tutorials/erc-721-vyper-annotated-code/index.md +++ b/public/content/translations/zh/developers/tutorials/erc-721-vyper-annotated-code/index.md @@ -1,31 +1,34 @@ --- -title: "Vyper ERC-721 合约概览" -description: Ryuya Nakamura 编写的 ERC-721 合约及其原理 +title: "Vyper ERC-721 合约详解" +description: "Ryuya Nakamura 的 ERC-721 合约及其工作原理" author: Ori Pomerantz lang: zh -tags: - - "vyper" - - "erc-721" - - "python" +tags: [ "vyper", "erc-721", "python" ] skill: beginner published: 2021-04-01 --- ## 简介 {#introduction} -[ERC-721](/developers/docs/standards/tokens/erc-721/) 标准的作用是持有非同质化代币 (NFT) 的所有权。 [ERC-20](/developers/docs/standards/tokens/erc-20/) 代币如同商品一样,因为每个代币之间没有任何区别。 相比之下,ERC-721 代币专门用来代表类似但又不同的资产,例如表示不同的[卡通猫咪](https://www.cryptokitties.co/) 或各种房地产的所有权。 +[ERC-721](/developers/docs/standards/tokens/erc-721/) 标准用于持有非同质化代币 (NFT) 的所有权。 +[ERC-20](/developers/docs/standards/tokens/erc-20/) 代币的行为像商品,因为单个代币之间没有区别。 +与此相反,ERC-721 代币是为相似但不相同的资产设计的,例如不同的猫咪 +卡通或不同房地产的所有权凭证。 -在本文中,我们将分析 [Ryuya Nakamura 编写的 ERC-721 合约](https://github.com/vyperlang/vyper/blob/master/examples/tokens/ERC721.vy)。 该合约是用 [Vyper](https://vyper.readthedocs.io/en/latest/index.html) 语言编写的,Vyper 是一种类似 Python 的合约语言,与使用 Solidity 相比,编写不安全的代码变得更加困难。 +在本文中,我们将分析 [Ryuya Nakamura 的 ERC-721 合约](https://github.com/vyperlang/vyper/blob/master/examples/tokens/ERC721.vy)。 +该合约使用 [Vyper](https://vyper.readthedocs.io/en/latest/index.html) 编写,这是一种类似 Python 的合约语言,其设计使得编写不安全的代码比使用 Solidity 更难。 ## 合约 {#contract} ```python -# @dev Implementation of ERC-721 non-fungible token standard. +# @dev ERC-721 非同质化代币标准的实现。 # @author Ryuya Nakamura (@nrryuya) -# Modified from: https://github.com/vyperlang/vyper/blob/de74722bf2d8718cca46902be165f9fe0e3641dd/examples/tokens/ERC721.vy +# 修改自:https://github.com/vyperlang/vyper/blob/de74722bf2d8718cca46902be165f9fe0e3641dd/examples/tokens/ERC721.vy ``` -Vyper 中的注释与 Python 中一样,以哈希 (`#`) 开头并且持续一整行。 [NatSpec](https://vyper.readthedocs.io/en/latest/natspec.html) 使用包含 `@` 的注释生成方便人阅读的文档。 +在 Vyper 中,注释与 Python 一样,以哈希符号 (`#`) 开头,并持续到行尾。 包含 +`@` 的注释被 [NatSpec](https://vyper.readthedocs.io/en/latest/natspec.html) 用于生成人类可读的 +文档。 ```python from vyper.interfaces import ERC721 @@ -33,159 +36,194 @@ from vyper.interfaces import ERC721 implements: ERC721 ``` -ERC-721 接口内置在 Vyper 语言中。 [你可以点击此处查看代码定义。](https://github.com/vyperlang/vyper/blob/master/vyper/builtin_interfaces/ERC721.py) 接口定义是用 Python 而不是 Vyper 编写的,因为接口不仅在区块链内使用, 而且在外部客户端向区块链发送交易时也使用,而客户端可能 是用 Python 编写的。 +ERC-721 接口内置于 Vyper 语言中。 +[你可以在这里查看代码定义](https://github.com/vyperlang/vyper/blob/master/vyper/builtin_interfaces/ERC721.py)。 +接口定义是用 Python 而不是 Vyper 编写的,因为接口不仅在 +区块链内部使用,而且在外部客户端向区块链发送交易时也会使用,而客户端可能 +是用 Python 编写的。 -第一行导入接口,第二行指定我们在这里执行它。 +第一行导入接口,第二行指定我们在此处实现它。 -### ERC721 接收者接口 {#receiver-interface} +### ERC721Receiver 接口 {#receiver-interface} ```python -# Interface for the contract called by safeTransferFrom() +# safeTransferFrom() 调用的合约接口 interface ERC721Receiver: def onERC721Received( ``` -ERC-721 支持两类转账: +ERC-721 支持两种类型的转账: -- `transferFrom`,让发送者指定任何目的地地址并让发送者 承担转账责任。 这意味着你可以转账到一个无效的地址,在这种情况下,NFT 将永远丢失。 -- `safeTransferFrom`,检查目的地址是否是合约。 如果是,ERC-721 合约 将会询问接收合约是否要接收这笔 NFT 转账。 +- `transferFrom`,它允许发送者指定任何目标地址,并将转账的责任 + 放在发送者身上。 这意味着你可以转账到无效地址,在这种情况下, + NFT 将永久丢失。 +- `safeTransferFrom`,它会检查目标地址是否为合约。 如果是,ERC-721 合约 + 会询问接收合约是否愿意接收该 NFT。 -接收合约必须执行 `ERC721Receiver` 才能回应 `safeTransferFrom` 请求。 +要响应 `safeTransferFrom` 请求,接收合约必须实现 `ERC721Receiver`。 ```python _operator: address, _from: address, ``` -`_from` 地址是代币的当前所有者。 `_operator` 地址是请求转账的 地址(由于限额,这两个地址可能不同)。 +`_from` 地址是代币的当前所有者。 `_operator` 地址是请求 +转账的地址(由于授权额度的存在,这两个地址可能不同)。 ```python _tokenId: uint256, ``` -ERC-721 代币 ID 是 256 位的。 通常,这些 ID 是通过对代币所代表的 任何东西进行哈希运算创建的。 +ERC-721 代币 ID 是 256 位的。 通常,它们是通过对代币所代表的任何 +事物的描述进行哈希运算来创建的。 ```python _data: Bytes[1024] ``` -请求最多可以有 1024 字节的用户数据。 +请求最多可以包含 1024 字节的用户数据。 ```python ) -> bytes32: view ``` -为了防止发生合约意外接受转账的情况,返回值不是布尔值, 而是一个具有特定值的 256 位数字串。 +为防止合约意外接受转账,返回值不是布尔值, +而是具有特定值的 256 位数据。 -此函数是 `view`,这意味着它可以读取区块链的状态,但不能修改。 +此函数是 `view` 函数,这意味着它可以读取区块链的状态,但不能修改它。 ### 事件 {#events} -[事件](https://media.consensys.net/technical-introduction-to-events-and-logs-in-ethereum-a074d65dd61e) 的触发是为了向区块链外部的用户和服务器通知事件。 请注意,事件 的内容不向区块链上的合约提供。 +发出[事件](https://media.consensys.net/technical-introduction-to-events-and-logs-in-ethereum-a074d65dd61e)是为了将事件通知给区块链外部的用户和服务器。 请注意,区块链上的合约无法访问事件的 +内容。 ```python -# @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are -# created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any -# number of NFTs may be created and assigned without emitting Transfer. At the time of any -# transfer, the approved address for that NFT (if any) is reset to none. -# @param _from Sender of NFT (if address is zero address it indicates token creation). -# @param _to Receiver of NFT (if address is zero address it indicates token destruction). -# @param _tokenId The NFT that got transferred. +# @dev 当任何 NFT 的所有权因任何机制发生变化时发出。当 NFT 被 +# 创建(`from` == 0)和销毁(`to` == 0)时,会发出此事件。例外:在合约创建期间,可以 +# 创建和分配任意数量的 NFT 而不发出 Transfer 事件。在任何 +# 转账时,该 NFT 的批准地址(如有)将被重置为无。 +# @param _from NFT 的发送者(如果地址是零地址,则表示代币创建)。 +# @param _to NFT 的接收者(如果地址是零地址,则表示代币销毁)。 +# @param _tokenId 被转移的 NFT。 event Transfer: sender: indexed(address) receiver: indexed(address) tokenId: indexed(uint256) ``` -这类似于 ERC-20 转账事件,不同之处在于我们报告的是 `tokenId` 而不是金额。 没有人拥有零地址,所以根据惯例我们用它来报告代币的创建和销毁。 +这类似于 ERC-20 的 Transfer 事件,区别在于我们报告的是 `tokenId` 而不是数量。 +没有人拥有零地址,因此按照惯例,我们用它来报告代币的创建和销毁。 ```python -# @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero -# address indicates there is no approved address. When a Transfer event emits, this also -# indicates that the approved address for that NFT (if any) is reset to none. -# @param _owner Owner of NFT. -# @param _approved Address that we are approving. -# @param _tokenId NFT which we are approving. +# @dev 当 NFT 的批准地址被更改或重新确认时发出此事件。零 +# 地址表示没有批准地址。当 Transfer 事件发出时,这也 +# 表示该 NFT 的批准地址(如有)被重置为无。 +# @param _owner NFT 的所有者。 +# @param _approved 我们正在批准的地址。 +# @param _tokenId 我们正在批准的 NFT。 event Approval: owner: indexed(address) approved: indexed(address) tokenId: indexed(uint256) ``` -ERC-721 批准与 ERC-20 限额类似。 特定地址只允许转移特定 代币。 这就形成了一种合约在接受代币时作出回应的机制。 合约不能侦听 事件,所以如果你只是把代币转移给合约,它们不会“知道”这笔转账。 因此,代币所有者 首先提交批准,然后向合约发送请求:“我批准你转移 代币 X,请执行......”。 +ERC-721 的批准类似于 ERC-20 的授权额度。 一个特定地址被允许转移一个特定的 +代币。 这为合约在接受代币时提供了一种响应机制。 合约无法 +监听事件,所以如果你只是将代币转移给它们,它们不会“知道”这件事。 这样, +所有者首先提交批准,然后向合约发送请求:“我已批准你转移代币 +X,请执行...” -这是一种设计选择,使 ERC-721 标准与 ERC-20 标准类似。 由于 ERC-721 代币 为非同质化代币,合约还可以通过查看代币的所有权来确定 它得到了一个特定代币。 +这是一种设计选择,旨在使 ERC-721 标准与 ERC-20 标准相似。 因为 +ERC-721 代币不是同质化的,合约也可以通过 +查看代币的所有权来识别它收到了一个特定的代币。 ```python -# @dev This emits when an operator is enabled or disabled for an owner. The operator can manage -# all NFTs of the owner. -# @param _owner Owner of NFT. -# @param _operator Address to which we are setting operator rights. -# @param _approved Status of operator rights(true if operator rights are given and false if -# revoked). +# @dev 当为所有者启用或禁用操作员时发出此事件。操作员可以管理 +# 所有者的所有 NFT。 +# @param _owner NFT 的所有者。 +# @param _operator 我们正在为其设置操作员权限的地址。 +# @param _approved 操作员权限的状态(如果授予操作员权限则为 true,如果 +# 撤销则为 false)。 event ApprovalForAll: owner: indexed(address) operator: indexed(address) approved: bool ``` -有时候,拥有一个能够管理某个帐户所有特定类型代币(由一个特定合约 管理的所有代币)的_运营者_是很有用的,这类似于委托书。 例如,我可能想把这样一种权力赋予一个合约,即 检查我是否已经 6 个月没有联系它了,如果属实,就会把我的资产分配给我的继承者(如果他们中一人要求这样做,合约在没有 被交易调用时什么都做不了)。 在 ERC-20 中,我们只需给继承合约提供一个高限额即可。 但这对 ERC-721 不起作用,因为代币是非同质化的。 这是对应的。 +有时,拥有一个可以管理一个帐户所有特定类型代币(由特定合约管理的代币)的_操作员_是很有用的,这类似于授权委托书。 例如,我可能想将这种权力授予一个合约,让它检查我是否 +有六个月没有联系它,如果是,就将我的资产分配给我的继承人(如果其中一个继承人提出请求,因为合约在没有 +被交易调用的情况下什么也做不了)。 在 ERC-20 中,我们可以给继承合约一个高额的授权额度, +但这不适用于 ERC-721,因为它的代币是非同质化的。 这与上述情况等效。 -`approved` 值表示事件是等待批准,还是等待撤回批准。 +`approved` 值告诉我们该事件是用于批准还是撤销批准。 ### 状态变量 {#state-vars} -这些变量包含代币的当前状态:哪些是可用的以及谁拥有它们。 其中大多数 是 `HashMap` 对象,即[存在于两个类型之间的单向映射](https://vyper.readthedocs.io/en/latest/types.html#mappings)。 +这些变量包含代币的当前状态:哪些代币可用以及谁拥有它们。 这些变量大多是 +`HashMap` 对象,即[存在于两种类型之间的单向映射](https://vyper.readthedocs.io/en/latest/types.html#mappings)。 ```python -# @dev Mapping from NFT ID to the address that owns it. +# @dev 从 NFT ID 到其所有者地址的映射。 idToOwner: HashMap[uint256, address] -# @dev Mapping from NFT ID to approved address. +# @dev 从 NFT ID 到批准地址的映射。 idToApprovals: HashMap[uint256, address] ``` -以太坊中的用户和合约标识用 160 位地址表示。 这两个变量从代币 ID 映射 到代币所有者及批准的转让者(一次最多 1 个映射)。 在以太坊中,未初始化 数据始终为零,因此如果没有所有者或批准的转让者,该代币的值 为零。 +在以太坊中,用户和合约身份由 160 位地址表示。 这两个变量将代币 ID 映射 +到其所有者和被批准转移它们的人(每个代币最多一个)。 在以太坊中, +未初始化的数据始终为零,因此如果没有所有者或批准的转移者,该代币的 +值为零。 ```python -# @dev Mapping from owner address to count of his tokens. +# @dev 从所有者地址到其代币数量的映射。 ownerToNFTokenCount: HashMap[address, uint256] ``` -此变量保存每个所有者的代币数量。 没有从所有者到代币的映射,因此 识别特定所有者所拥有代币的唯一方法是在区块链的事件历史记录 中回溯并查看相应的 `Transfer` 事件。 我们可以使用此变量了解我们拥有全部非同质化代币的 时间,而无需进一步回溯。 +此变量保存每个所有者的代币数量。 没有从所有者到代币的映射,因此 +识别特定所有者所拥有代币的唯一方法是回溯区块链的事件历史 +并查看相应的 `Transfer` 事件。 我们可以使用这个变量来知道我们何时拥有了所有的 NFT,而不需要 +再往前追溯。 -注意,此算法只适用于用户接口和外部服务器。 在区块链自身运行的代码无法 读取过去的事件。 +请注意,此算法仅适用于用户界面和外部服务器。 在区块链上运行的 +代码本身无法读取过去的事件。 ```python -# @dev Mapping from owner address to mapping of operator addresses. +# @dev 从所有者地址到操作员地址映射的映射。 ownerToOperators: HashMap[address, HashMap[address, bool]] ``` -一个帐户可能有多个运营者。 仅有 `HashMap` 不足以跟踪它们,因为每个键都会生成单一值。 然而,可以将 `HashMap[address, bool]` 作为值。 默认情况下,每个地址的都值是 `False`,这意味着它 不是运营者。 你可以根据需要将值设置为 `True`。 +一个帐户可以有多个操作员。 一个简单的 `HashMap` 不足以 +跟踪它们,因为每个键只对应一个值。 相反,你可以使用 +`HashMap[address, bool]` 作为值。 默认情况下,每个地址的值都是 `False`,这意味着它 +不是操作员。 你可以根据需要将值设置为 `True`。 ```python -# @dev Address of minter, who can mint a token +# @dev 铸币者地址,可以铸造代币 minter: address ``` -必须以某种方式创建新代币。 在此合约中,只允许一个实体创建 代币,即 `minter`。 例如,这可能足以满足游戏的需要。 但对于其他用途,可能需要创建一个 更复杂的业务逻辑。 +新代币必须以某种方式创建。 在这个合约中,只有一个实体被允许这样做,那就是 +`minter`(铸币者)。 例如,这对于一个游戏来说可能已经足够了。 对于其他目的,可能需要 +创建更复杂的业务逻辑。 ```python -# @dev Mapping of interface id to bool about whether or not it's supported +# @dev 接口 ID 到布尔值的映射,表示是否支持该接口 supportedInterfaces: HashMap[bytes32, bool] -# @dev ERC165 interface ID of ERC165 +# @dev ERC165 的 ERC165 接口 ID ERC165_INTERFACE_ID: constant(bytes32) = 0x0000000000000000000000000000000000000000000000000000000001ffc9a7 -# @dev ERC165 interface ID of ERC721 +# @dev ERC721 的 ERC165 接口 ID ERC721_INTERFACE_ID: constant(bytes32) = 0x0000000000000000000000000000000000000000000000000000000080ac58cd ``` -[ERC-165](https://eips.ethereum.org/EIPS/eip-165) 为合约规定了一种机制,用来表明应用程序 如何与合约通信以及合约符合哪些 ERC。 在这种情况下,合约符合 ERC-165 和 ERC-721。 +[ERC-165](https://eips.ethereum.org/EIPS/eip-165) 指定了一种机制,让合约可以公开应用程序 +如何与其通信,以及它符合哪些 ERC。 在这种情况下,该合约符合 ERC-165 和 ERC-721。 ### 函数 {#functions} -以下函数确实实现了 ERC-721。 +这些是实际实现 ERC-721 的函数。 #### 构造函数 {#constructor} @@ -194,15 +232,17 @@ ERC721_INTERFACE_ID: constant(bytes32) = 0x0000000000000000000000000000000000000 def __init__(): ``` -和 Python 中一样,在 Vyper 中,构造函数也被称为 `__init__`。 +在 Vyper 中,与 Python 一样,构造函数被称为 `__init__`。 ```python """ - @dev Contract constructor. + @dev 合约构造函数。 """ ``` -在 Python 和 Vyper 中,通过指定多行字符串(以 `"""` 起始和结束),你还可以创建注释,但不能以任何方式使用它。 这些注释也可以包括 [NatSpec](https://vyper.readthedocs.io/en/latest/natspec.html) 注释。 +在 Python 和 Vyper 中,你也可以通过指定一个多行字符串(以 `"""` 开始和结束) +来创建注释,并且不以任何方式使用它。 这些注释也可以包含 +[NatSpec](https://vyper.readthedocs.io/en/latest/natspec.html)。 ```python self.supportedInterfaces[ERC165_INTERFACE_ID] = True @@ -210,57 +250,64 @@ def __init__(): self.minter = msg.sender ``` -要访问状态变量,可以使用 `self.`(也是与 Python 中的相同)。 +要访问状态变量,请使用 `self.`(同样,与 Python 中一样)。 #### 视图函数 {#views} -这些函数不修改区块链状态,因此在外部调用时它们可以 免费执行。 如果视图函数是合约调用的,它们仍然必须在每个节点 上执行,因此需要消耗燃料。 +这些函数不修改区块链的状态,因此如果从外部调用,可以 +免费执行。 如果视图函数由合约调用,它们仍必须在 +每个节点上执行,因此会消耗燃料。 ```python @view @external ``` -函数定义前面以 (`@`) 开头的这些关键词称为_修改器_。 它们 规定能够调用函数的环境。 +在函数定义之前,以 at 符号(`@`)开头的这些关键字被称为_装饰器_。 它们 +指定了可以调用函数的环境。 -- `@view` 指定此函数为 view 函数。 -- `@external` 指定该特定函数可以由交易及其它合约调用。 +- `@view` 指定此函数是视图函数。 +- `@external` 指定此特定函数可由交易和其他合约调用。 ```python def supportsInterface(_interfaceID: bytes32) -> bool: ``` -与 Python 相比,Vyper 是一种[静态类型语言](https://wikipedia.org/wiki/Type_system#Static_type_checking)。 如果没有先确定[数据类型](https://vyper.readthedocs.io/en/latest/types.html),就无法声明变量或函数参数。 因此在上例中,输入参数是一个 256 位的 `bytes32` 值 (256 位是[以太坊虚拟机](/developers/docs/evm/)的原生字长宽度)。 输出是一个 布尔值。 按照惯例,函数参数的名称以下划线 (`_`) 开头。 +与 Python 相反,Vyper 是一种[静态类型语言](https://wikipedia.org/wiki/Type_system#Static_type_checking)。 +如果不确定[数据类型](https://vyper.readthedocs.io/en/latest/types.html),就无法声明变量或函数参数。 在这种情况下,输入参数是 `bytes32`,一个 256 位的值 +(256 位是[以太坊虚拟机](/developers/docs/evm/)的原生字长)。 输出是一个布尔 +值。 按照惯例,函数参数的名称以下划线 (`_`) 开头。 ```python """ - @dev Interface identification is specified in ERC-165. - @param _interfaceID Id of the interface + @dev 接口标识在 ERC-165 中指定。 + @param _interfaceID 接口的 ID """ return self.supportedInterfaces[_interfaceID] ``` -返回 HashMap `self.supportedInterfaces` 中的值,该 HashMap 在构造函数 (`__init__`) 中设置。 +从 `self.supportedInterfaces` HashMap 返回值,该值在构造函数 (`__init__`) 中设置。 ```python -### VIEW FUNCTIONS ### +### 视图函数 ### ``` -下面这些视图函数让用户和其它合约可以获得代币相关信息。 +这些是向用户和其他合约提供有关代币信息的视图函数。 ```python @view @external def balanceOf(_owner: address) -> uint256: """ - @dev Returns the number of NFTs owned by `_owner`. - Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid. - @param _owner Address for whom to query the balance. + @dev 返回 `_owner` 拥有的 NFT 数量。 + 如果 `_owner` 是零地址,则抛出异常。分配给零地址的 NFT 被视为无效。 + @param _owner 查询余额的地址。 """ assert _owner != ZERO_ADDRESS ``` -此行[宣称](https://vyper.readthedocs.io/en/latest/statements.html#assert) `_owner` 不 为 0。 如果为 0,就会出现错误,操作会被回滚。 +此行[断言](https://vyper.readthedocs.io/en/latest/statements.html#assert) `_owner` 不是 +零。 如果是,则会发生错误并且操作将被回滚。 ```python return self.ownerToNFTokenCount[_owner] @@ -269,70 +316,75 @@ def balanceOf(_owner: address) -> uint256: @external def ownerOf(_tokenId: uint256) -> address: """ - @dev Returns the address of the owner of the NFT. - Throws if `_tokenId` is not a valid NFT. - @param _tokenId The identifier for an NFT. + @dev 返回 NFT 所有者的地址。 + 如果 `_tokenId` 不是有效的 NFT,则抛出异常。 + @param _tokenId NFT 的标识符。 """ owner: address = self.idToOwner[_tokenId] - # Throws if `_tokenId` is not a valid NFT + # 如果 `_tokenId` 不是有效的 NFT,则抛出异常 assert owner != ZERO_ADDRESS return owner ``` -在以太坊虚拟机 (evm) 中,任何没有存储值的存储都为零。 如果 `_tokenId` 处没有代币,那么 `self.idToOwner[_tokenId]` 的值为 0。 在这种情况下,该函数 会回滚操作。 +在以太坊虚拟机 (evm) 中,任何未存储值的存储空间其值都为零。 +如果 `_tokenId` 处没有代币,那么 `self.idToOwner[_tokenId]` 的值为零。 在这种 +情况下,函数会回滚。 ```python @view @external def getApproved(_tokenId: uint256) -> address: """ - @dev Get the approved address for a single NFT. - Throws if `_tokenId` is not a valid NFT. - @param _tokenId ID of the NFT to query the approval of. + @dev 获取单个 NFT 的批准地址。 + 如果 `_tokenId` 不是有效的 NFT,则抛出异常。 + @param _tokenId 要查询其批准情况的 NFT 的 ID。 """ - # Throws if `_tokenId` is not a valid NFT + # 如果 `_tokenId` 不是有效的 NFT,则抛出异常 assert self.idToOwner[_tokenId] != ZERO_ADDRESS return self.idToApprovals[_tokenId] ``` -注意,`getApproved` _可以_返回零。 如果代币有效,则返回 `self.idToApprovals[_tokenId]`。 如果没有批准者,该值为 0。 +注意,`getApproved` _可以_ 返回零。 如果代币有效,它会返回 `self.idToApprovals[_tokenId]`。 +如果没有批准者,该值为零。 ```python @view @external def isApprovedForAll(_owner: address, _operator: address) -> bool: """ - @dev Checks if `_operator` is an approved operator for `_owner`. - @param _owner The address that owns the NFTs. - @param _operator The address that acts on behalf of the owner. + @dev 检查 `_operator` 是否是 `_owner` 的批准操作员。 + @param _owner 拥有 NFT 的地址。 + @param _operator 代表所有者行事的地址。 """ return (self.ownerToOperators[_owner])[_operator] ``` -此函数检查是否允许 `_operator` 管理 `_owner` 在此合约中的所有代币。 因为可以有多个运营者,所以这是一个两级 HashMap。 +此函数检查是否允许 `_operator` 管理此合约中 `_owner` 的所有代币。 +因为可以有多个操作员,所以这是一个两级 HashMap。 -#### 转账帮助函数 {#transfer-helpers} +#### 转账辅助函数 {#transfer-helpers} -这些函数执行代币转账或管理过程中的一些操作。 +这些函数实现了代币转移或管理过程中的部分操作。 ```python -### TRANSFER FUNCTION HELPERS ### +### 转账函数辅助 ### @view @internal ``` -修改器 `@internal` 表示该函数只能由 同一合约内的其他函数访问。 按照惯例,这些函数名称也以下划线 (`_`) 开头。 +这个装饰器 `@internal` 意味着该函数只能从 +同一合约内的其他函数访问。 按照惯例,这些函数名也以下划线 (`_`) 开头。 ```python def _isApprovedOrOwner(_spender: address, _tokenId: uint256) -> bool: """ - @dev Returns whether the given spender can transfer a given token ID - @param spender address of the spender to query - @param tokenId uint256 ID of the token to be transferred - @return bool whether the msg.sender is approved for the given token ID, - is an operator of the owner, or is the owner of the token + @dev 返回给定的支出者是否可以转移给定的代币 ID + @param spender 要查询的支出者地址 + @param tokenId 要转移的代币的 uint256 ID + @return bool,表示 msg.sender 是否被批准用于给定的代币 ID, + 是所有者的操作员,还是代币的所有者 """ owner: address = self.idToOwner[_tokenId] spenderIsOwner: bool = owner == _spender @@ -341,117 +393,123 @@ def _isApprovedOrOwner(_spender: address, _tokenId: uint256) -> bool: return (spenderIsOwner or spenderIsApproved) or spenderIsApprovedForAll ``` -有三种方式可以允许地址转移代币: +有三种方式可以允许一个地址转移代币: 1. 该地址是代币的所有者 -2. 该地址经批准可以使用该代币 -3. 该地址是代表代币所有者的运营者 +2. 该地址被批准使用该代币 +3. 该地址是代币所有者的操作员 -上面的函数可以是一个视图函数,因为它并不改变状态。 为了降低运营成本,任何_可以_ 成为视图函数的函数都_应该_成为视图函数。 +上面的函数可以是一个视图函数,因为它不改变状态。 为了降低运营成本,任何 +可以成为视图函数的函数都_应该_是视图函数。 ```python @internal def _addTokenTo(_to: address, _tokenId: uint256): """ - @dev Add a NFT to a given address - Throws if `_tokenId` is owned by someone. + @dev 将一个 NFT 添加到给定地址 + 如果 `_tokenId` 已被某人拥有,则抛出异常。 """ - # Throws if `_tokenId` is owned by someone + # 如果 `_tokenId` 已被某人拥有,则抛出异常 assert self.idToOwner[_tokenId] == ZERO_ADDRESS - # Change the owner + # 更改所有者 self.idToOwner[_tokenId] = _to - # Change count tracking + # 更改计数跟踪 self.ownerToNFTokenCount[_to] += 1 @internal def _removeTokenFrom(_from: address, _tokenId: uint256): """ - @dev Remove a NFT from a given address - Throws if `_from` is not the current owner. + @dev 从给定地址移除一个 NFT + 如果 `_from` 不是当前所有者,则抛出异常。 """ - # Throws if `_from` is not the current owner + # 如果 `_from` 不是当前所有者,则抛出异常 assert self.idToOwner[_tokenId] == _from - # Change the owner + # 更改所有者 self.idToOwner[_tokenId] = ZERO_ADDRESS - # Change count tracking + # 更改计数跟踪 self.ownerToNFTokenCount[_from] -= 1 ``` -当转账出现问题时,我们会撤销调用。 +当转账出现问题时,我们会回滚该调用。 ```python @internal def _clearApproval(_owner: address, _tokenId: uint256): """ - @dev Clear an approval of a given address - Throws if `_owner` is not the current owner. + @dev 清除给定地址的批准 + 如果 `_owner` 不是当前所有者,则抛出异常。 """ - # Throws if `_owner` is not the current owner + # 如果 `_owner` 不是当前所有者,则抛出异常 assert self.idToOwner[_tokenId] == _owner if self.idToApprovals[_tokenId] != ZERO_ADDRESS: - # Reset approvals + # 重置批准 self.idToApprovals[_tokenId] = ZERO_ADDRESS ``` -仅在必要时更改值。 状态变量位于存储中。 写入存储是 EVM(以太坊虚拟机)执行的最昂贵的操作之一(就 [燃料](/developers/docs/gas/)而言)。 因此,尽量减少写入操作,即使是写入现有值, 成本也很高。 +仅在必要时更改值。 状态变量存在于存储中。 写入存储是 +EVM(以太坊虚拟机)执行的最昂贵的操作之一(就 +[燃料](/developers/docs/gas/)而言)。 因此,最好尽量减少写入操作,即使写入 +现有值也会产生高昂的成本。 ```python @internal def _transferFrom(_from: address, _to: address, _tokenId: uint256, _sender: address): """ - @dev Execute transfer of a NFT. - Throws unless `msg.sender` is the current owner, an authorized operator, or the approved - address for this NFT. (NOTE: `msg.sender` not allowed in private function so pass `_sender`.) - Throws if `_to` is the zero address. - Throws if `_from` is not the current owner. - Throws if `_tokenId` is not a valid NFT. + @dev 执行 NFT 的转移。 + 除非 `msg.sender` 是当前所有者、授权操作员或此 NFT 的批准 + 地址,否则抛出异常。(注意:私有函数中不允许使用 `msg.sender`,因此传递 `_sender`。) + 如果 `_to` 是零地址,则抛出异常。 + 如果 `_from` 不是当前所有者,则抛出异常。 + 如果 `_tokenId` 不是有效的 NFT,则抛出异常。 """ ``` -我们使用此内部函数是因为有两种代币转账方式(常规和安全方式),但 我们希望代码中只有一个位置进行此操作,以使审计更容易。 +我们有这个内部函数,因为有两种转移代币的方式(常规和安全),但 +我们希望只在代码中的一个位置执行它,以使审计更容易。 ```python - # Check requirements + # 检查要求 assert self._isApprovedOrOwner(_sender, _tokenId) - # Throws if `_to` is the zero address + # 如果 `_to` 是零地址,则抛出异常 assert _to != ZERO_ADDRESS - # Clear approval. Throws if `_from` is not the current owner + # 清除批准。如果 `_from` 不是当前所有者,则抛出异常 self._clearApproval(_from, _tokenId) - # Remove NFT. Throws if `_tokenId` is not a valid NFT + # 移除 NFT。如果 `_tokenId` 不是有效的 NFT,则抛出异常 self._removeTokenFrom(_from, _tokenId) - # Add NFT + # 添加 NFT self._addTokenTo(_to, _tokenId) - # Log the transfer + # 记录转账 log Transfer(_from, _to, _tokenId) ``` -要在 Vyper 中触发一个事件,可以使用 `log` 语句([请点击此处了解更多详情](https://vyper.readthedocs.io/en/latest/event-logging.html#event-logging))。 +要在 Vyper 中发出事件,请使用 `log` 语句([在此处查看更多详细信息](https://vyper.readthedocs.io/en/latest/event-logging.html#event-logging))。 #### 转账函数 {#transfer-funs} ```python -### TRANSFER FUNCTIONS ### +### 转账函数 ### @external def transferFrom(_from: address, _to: address, _tokenId: uint256): """ - @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved - address for this NFT. - Throws if `_from` is not the current owner. - Throws if `_to` is the zero address. - Throws if `_tokenId` is not a valid NFT. - @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else - they maybe be permanently lost. - @param _from The current owner of the NFT. - @param _to The new owner. - @param _tokenId The NFT to transfer. + @dev 除非 `msg.sender` 是当前所有者、授权操作员或此 NFT 的批准 + 地址,否则抛出异常。 + 如果 `_from` 不是当前所有者,则抛出异常。 + 如果 `_to` 是零地址,则抛出异常。 + 如果 `_tokenId` 不是有效的 NFT,则抛出异常。 + @notice 调用者有责任确认 `_to` 能够接收 NFT,否则 + 它们可能会永久丢失。 + @param _from NFT 的当前所有者。 + @param _to 新的所有者。 + @param _tokenId 要转移的 NFT。 """ self._transferFrom(_from, _to, _tokenId, msg.sender) ``` -此函数允许你向任意地址转账。 除非该地址是用户或是知道如何转移代币的 合约,否则你转移的任何代币都将卡在该地址中变得毫无用处。 +此函数允许你转移到任意地址。 除非该地址是用户,或者是一个知道 +如何转移代币的合约,否则你转移的任何代币都将卡在该地址中并变得无用。 ```python @external @@ -462,30 +520,34 @@ def safeTransferFrom( _data: Bytes[1024]=b"" ): """ - @dev Transfers the ownership of an NFT from one address to another address. - Throws unless `msg.sender` is the current owner, an authorized operator, or the - approved address for this NFT. - Throws if `_from` is not the current owner. - Throws if `_to` is the zero address. - Throws if `_tokenId` is not a valid NFT. - If `_to` is a smart contract, it calls `onERC721Received` on `_to` and throws if - the return value is not `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. - NOTE: bytes4 is represented by bytes32 with padding - @param _from The current owner of the NFT. - @param _to The new owner. - @param _tokenId The NFT to transfer. - @param _data Additional data with no specified format, sent in call to `_to`. + @dev 将一个 NFT 的所有权从一个地址转移到另一个地址。 + 除非 `msg.sender` 是当前所有者、授权操作员或此 NFT 的 + 批准地址,否则抛出异常。 + 如果 `_from` 不是当前所有者,则抛出异常。 + 如果 `_to` 是零地址,则抛出异常。 + 如果 `_tokenId` 不是有效的 NFT,则抛出异常。 + 如果 `_to` 是一个智能合约,它会在 `_to` 上调用 `onERC721Received`,如果 + 返回值不是 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`,则抛出异常。 + 注意:bytes4 由带填充的 bytes32 表示 + @param _from NFT 的当前所有者。 + @param _to 新的所有者。 + @param _tokenId 要转移的 NFT。 + @param _data 没有指定格式的附加数据,在调用 `_to` 时发送。 """ self._transferFrom(_from, _to, _tokenId, msg.sender) ``` -可以先进行转账,因为如果出现问题,我们无论如何都会回滚该操作,因此 调用中的一切操作都会被取消。 +可以先执行转移,因为如果出现问题,我们无论如何都会回滚, +所以调用中完成的所有操作都将被取消。 ```python - if _to.is_contract: # check if `_to` is a contract address + if _to.is_contract: # 检查 `_to` 是否是合约地址 ``` -首先检查地址是否为合约(如果有代码)。 如果不是,假定它是一个用户 地址,并且该用户能够使用或转移代币。 但不要让该地址 给你一种虚假的安全感。 如果你将代币转移到一个没有人知道私钥的地址,即使使用了 `safeTransferFrom`,也可能损失代币。 +首先检查该地址是否是合约(即它是否有代码)。 如果不是,则假定它是一个用户 +地址,并且该用户将能够使用或转移代币。 但不要让它给你一种 +虚假的安全感。 即使使用 `safeTransferFrom`,如果你将代币转移 +到一个没有人知道其私钥的地址,你仍然可能会丢失代币。 ```python returnValue: bytes32 = ERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) @@ -494,43 +556,44 @@ def safeTransferFrom( 调用目标合约,看它是否可以接收 ERC-721 代币。 ```python - # Throws if transfer destination is a contract which does not implement 'onERC721Received' + # 如果转移目标是一个未实现 'onERC721Received' 的合约,则抛出异常 assert returnValue == method_id("onERC721Received(address,address,uint256,bytes)", output_type=bytes32) ``` -如果目的地是一个合约,但它不接受 ERC-721 代币(或者决定不接受这笔特定转账),则回滚。 +如果目标是一个合约,但它不接受 ERC-721 代币(或者决定不接受此 +特定转移),则回滚。 ```python @external def approve(_approved: address, _tokenId: uint256): """ - @dev Set or reaffirm the approved address for an NFT. The zero address indicates there is no approved address. - Throws unless `msg.sender` is the current NFT owner, or an authorized operator of the current owner. - Throws if `_tokenId` is not a valid NFT. (NOTE: This is not written the EIP) - Throws if `_approved` is the current owner. (NOTE: This is not written the EIP) - @param _approved Address to be approved for the given NFT ID. - @param _tokenId ID of the token to be approved. + @dev 为一个 NFT 设置或重新确认批准地址。零地址表示没有批准地址。 + 除非 `msg.sender` 是当前的 NFT 所有者,或者是当前所有者的授权操作员,否则抛出异常。 + 如果 `_tokenId` 不是有效的 NFT,则抛出异常。(注意:这并未写入 EIP) + 如果 `_approved` 是当前所有者,则抛出异常。(注意:这并未写入 EIP) + @param _approved 要为给定 NFT ID 批准的地址。 + @param _tokenId 要批准的代币 ID。 """ owner: address = self.idToOwner[_tokenId] - # Throws if `_tokenId` is not a valid NFT + # 如果 `_tokenId` 不是有效的 NFT,则抛出异常 assert owner != ZERO_ADDRESS - # Throws if `_approved` is the current owner + # 如果 `_approved` 是当前所有者,则抛出异常 assert _approved != owner ``` -根据惯例,如果你不想要批准者,可以指定零地址而不是你自己。 +按照惯例,如果你不想有批准者,你应该指定零地址,而不是你自己。 ```python - # Check requirements + # 检查要求 senderIsOwner: bool = self.idToOwner[_tokenId] == msg.sender senderIsApprovedForAll: bool = (self.ownerToOperators[owner])[msg.sender] assert (senderIsOwner or senderIsApprovedForAll) ``` -要设置批准,你可以是所有者,也可以是所有者授权的运营者。 +要设置批准,你要么是所有者,要么是所有者授权的操作员。 ```python - # Set the approval + # 设置批准 self.idToApprovals[_tokenId] = _approved log Approval(owner, _approved, _tokenId) @@ -538,14 +601,14 @@ def approve(_approved: address, _tokenId: uint256): @external def setApprovalForAll(_operator: address, _approved: bool): """ - @dev Enables or disables approval for a third party ("operator") to manage all of - `msg.sender`'s assets. It also emits the ApprovalForAll event. - Throws if `_operator` is the `msg.sender`. (NOTE: This is not written the EIP) - @notice This works even if sender doesn't own any tokens at the time. - @param _operator Address to add to the set of authorized operators. - @param _approved True if the operators is approved, false to revoke approval. + @dev 为第三方(“操作员”)启用或禁用批准,以管理 + `msg.sender` 的所有资产。它还会发出 ApprovalForAll 事件。 + 如果 `_operator` 是 `msg.sender`,则抛出异常。(注意:这并未写入 EIP) + @notice 即使发送者当时不拥有任何代币,此操作也有效。 + @param _operator 要添加到授权操作员集合中的地址。 + @param _approved 如果操作员被批准,则为 True;如果撤销批准,则为 false。 """ - # Throws if `_operator` is the `msg.sender` + # 如果 `_operator` 是 `msg.sender`,则抛出异常 assert _operator != msg.sender self.ownerToOperators[msg.sender][_operator] = _approved log ApprovalForAll(msg.sender, _operator, _approved) @@ -553,10 +616,12 @@ def setApprovalForAll(_operator: address, _approved: bool): #### 铸造新代币和销毁现有代币 {#mint-burn} -创建合约的帐户就是 `minter`,是获得授权可以铸造 新非同质化代币的超级用户。 然而,即使是铸币者,也不允许其销毁现有代币。 只有所有者或所有者授权的实体 才能那样做。 +创建合约的帐户是 `minter`(铸币者),即被授权铸造 +新 NFT 的超级用户。 然而,即使是它,也不允许销毁现有代币。 只有所有者或所有者 +授权的实体才能这样做。 ```python -### MINT & BURN FUNCTIONS ### +### 铸造和销毁函数 ### @external def mint(_to: address, _tokenId: uint256) -> bool: @@ -566,67 +631,81 @@ def mint(_to: address, _tokenId: uint256) -> bool: ```python """ - @dev Function to mint tokens - Throws if `msg.sender` is not the minter. - Throws if `_to` is zero address. - Throws if `_tokenId` is owned by someone. - @param _to The address that will receive the minted tokens. - @param _tokenId The token id to mint. - @return A boolean that indicates if the operation was successful. + @dev 铸造代币的函数 + 如果 `msg.sender` 不是铸币者,则抛出异常。 + 如果 `_to` 是零地址,则抛出异常。 + 如果 `_tokenId` 已被某人拥有,则抛出异常。 + @param _to 将接收铸造代币的地址。 + @param _tokenId 要铸造的代币 id。 + @return 一个布尔值,指示操作是否成功。 """ - # Throws if `msg.sender` is not the minter + # 如果 `msg.sender` 不是铸币者,则抛出异常 assert msg.sender == self.minter ``` -只有铸币者(创建 ERC-721 合约的帐户)可以铸造新代币。 如果我们将来想改变铸币者的 身份,这可能会成为一个问题。 在生产合约 中,你可能需要一个函数,允许 铸币者将铸币者特权转让给其他人。 +只有铸币者(创建 ERC-721 合约的帐户)可以铸造新代币。 如果我们将来想改变铸币者的 +身份,这可能会成为一个问题。 在 +生产合约中,你可能需要一个允许铸币者将 +铸币者特权转移给他人的函数。 ```python - # Throws if `_to` is zero address + # 如果 `_to` 是零地址,则抛出异常 assert _to != ZERO_ADDRESS - # Add NFT. Throws if `_tokenId` is owned by someone + # 添加 NFT。如果 `_tokenId` 已被某人拥有,则抛出异常 self._addTokenTo(_to, _tokenId) log Transfer(ZERO_ADDRESS, _to, _tokenId) return True ``` -根据惯例,新代币铸造视作来自零地址的转账。 +按照惯例,新代币的铸造被视为从零地址的转移。 ```python @external def burn(_tokenId: uint256): """ - @dev Burns a specific ERC721 token. - Throws unless `msg.sender` is the current owner, an authorized operator, or the approved - address for this NFT. - Throws if `_tokenId` is not a valid NFT. - @param _tokenId uint256 id of the ERC721 token to be burned. + @dev 销毁一个特定的 ERC721 代币。 + 除非 `msg.sender` 是当前所有者、授权操作员或此 NFT 的批准 + 地址,否则抛出异常。 + 如果 `_tokenId` 不是有效的 NFT,则抛出异常。 + @param _tokenId 要销毁的 ERC721 代币的 uint256 id。 """ - # Check requirements + # 检查要求 assert self._isApprovedOrOwner(msg.sender, _tokenId) owner: address = self.idToOwner[_tokenId] - # Throws if `_tokenId` is not a valid NFT + # 如果 `_tokenId` 不是有效的 NFT,则抛出异常 assert owner != ZERO_ADDRESS self._clearApproval(owner, _tokenId) self._removeTokenFrom(owner, _tokenId) log Transfer(owner, ZERO_ADDRESS, _tokenId) ``` -任何可以转移代币的人都可以销毁它。 虽然销毁代币看起来等同于 转移到零地址,但零地址实际上并没有接收到代币。 这样我们可以释放所有用于代币的 存储,因而可以降低交易的燃料成本。 +任何被允许转移代币的人都可以销毁它。 虽然销毁看起来等同于 +转移到零地址,但零地址实际上并不接收代币。 这使我们能够 +释放用于该代币的所有存储空间,从而可以降低交易的燃料成本。 ## 使用此合约 {#using-contract} -与 Solidity 相比,Vyper 中没有继承。 这种有意而为之的设计选择,是为了使代码 更清晰,从而更容易受保护。 因此,要创建你自己的 Vyper ERC-721 合约,你可以 利用[此合约](https://github.com/vyperlang/vyper/blob/master/examples/tokens/ERC721.vy),并修改 它以实现想要的业务逻辑。 +与 Solidity 相反,Vyper 没有继承。 这是一个刻意的设计选择,旨在使 +代码更清晰,从而更容易保护。 因此,要创建你自己的 Vyper ERC-721 合约,你可以使用此 +合约并修改它 +以实现你想要的业务逻辑。 -### 总结 {#conclusion} +## 结论 {#conclusion} -回顾一下,下面是此合约中最重要的几点: +作为回顾,以下是此合约中一些最重要的概念: -- 要通过安全转账方式接收 ERC-721 代币,合约必须实现 `ERC721Receiver` 接口。 -- 即使使用了安全转账方式,如果你将代币发送到私钥未知 的地址,代币仍然会被卡住。 -- 当操作出现问题时,最好 `revert` 该调用,而不是只返回 失败值。 -- 有了所有者,ERC-721 代币才存在。 -- 有三种经过授权的 NFT 转账方式。 你可以是所有者,可以针对特定代币获得批准, 或者可以是所有者全部代币的运营者。 -- 过去的事件只在区块链之外可见。 区块链中运行的代码无法看到它们。 +- 要通过安全转移接收 ERC-721 代币,合约必须实现 `ERC721Receiver` 接口。 +- 即使你使用安全转移,如果将代币发送到一个其私钥 + 未知的地址,代币仍然可能会卡住。 +- 当操作出现问题时,一个好主意是 `revert`(回滚)该调用,而不是仅仅返回 + 一个失败值。 +- 当 ERC-721 代币有所有者时,它们才存在。 +- 有三种方式可以被授权转移 NFT。 你可以是所有者,被批准用于特定代币, + 或者是所有者所有代币的操作员。 +- 过去的事件仅在区块链外部可见。 在区块链内部运行的代码无法查看它们。 现在去实现安全的 Vyper 合约吧。 + +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 + diff --git a/public/content/translations/zh/developers/tutorials/erc20-annotated-code/index.md b/public/content/translations/zh/developers/tutorials/erc20-annotated-code/index.md index a1927070a0a..deee115ca1c 100644 --- a/public/content/translations/zh/developers/tutorials/erc20-annotated-code/index.md +++ b/public/content/translations/zh/developers/tutorials/erc20-annotated-code/index.md @@ -1,30 +1,39 @@ --- -title: "ERC-20 合约概览" -description: OpenZeppelin 的 ERC-20 合约内容和解读 +title: "ERC-20 合约详解" +description: "OpenZeppelin ERC-20 合约中有什么,为什么?" author: Ori Pomerantz lang: zh -tags: - - "solidity" - - "erc-20" +tags: [ "Solidity", "erc-20" ] skill: beginner published: 2021-03-09 --- ## 简介 {#introduction} -以太坊最常见的用途之一是由一个团队来打造一种可以交易的代币,在某种意义上是他们自己的货币。 这些代币通常遵循一个标准, [ERC-20](/developers/docs/standards/tokens/erc-20/)。 此标准使得人们能够以此来开发可以用于所有 ERC-20 代币的工具,如流动资金池和钱包。 在这篇文章中,我们将带领大家分析 [OpenZeppelin Solidity ERC20 实现](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)以及 [ ERC20 接口定义](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol)。 +以太坊最常见的用途之一是由一个团队来打造一种可以交易的代币,在某种意义上是他们自己的货币。 这些代币通常遵循一个标准: +[ERC-20](/developers/docs/standards/tokens/erc-20/)。 此标准使得编写适用于所有 ERC-20 +代币的工具(例如流动性资金池和钱包)成为可能。 在本文中,我们将分析 +[OpenZeppelin Solidity ERC20 实现](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)以及 +[接口定义](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol)。 -这里使用的是附加说明的源代码。 如果想要实现 ERC-20, [请阅读此教程](https://docs.openzeppelin.com/contracts/2.x/erc20-supply)。 +这是带注释的源代码。 如果你想实现 ERC-20, +[请阅读本教程](https://docs.openzeppelin.com/contracts/2.x/erc20-supply)。 ## 接口 {#the-interface} -像 ERC-20 这样的标准,其目的是允许符合标准的多种代币,都可以在应用程序之间进行互操作,例如钱包和分布式交易所。 为实现这个目的,我们要创建一个 [接口](https://www.geeksforgeeks.org/solidity-basics-of-interface/)。 任何需要使用代币合约的代码 可以在接口中使用相同的定义,并且与使用它的所有代币合约兼容。无论是像 MetaMask 这样的钱包、 诸如 etherscan.io 之类的去中心化应用程序,或一种不同的合约,例如流动资金池。 +ERC-20 等标准的目的是让多种代币实现能够在应用程序(如钱包和去中心化交易所)之间互操作。 为实现此目的,我们创建一个 +[接口](https://www.geeksforgeeks.org/solidity/solidity-basics-of-interface/)。 任何需要使用代币合约的代码 +都可以在接口中使用相同的定义,并与所有使用它的代币合约兼容,无论它是像 +MetaMask 这样的钱包,像 etherscan.io 这样的去中心化应用程序,还是像流动性资金池这样不同的合约。 -![ERC-20 接口说明](erc20_interface.png) +![ERC-20 接口图示](erc20_interface.png) -如果你是一位经验丰富的程序员,你可能记得在 [Java](https://www.w3schools.com/java/java_interface.asp) 中,甚至在 [C 头文件](https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html) 中看到过类似的构造。 +如果你是一位经验丰富的程序员,你可能还记得在 [Java](https://www.w3schools.com/java/java_interface.asp) +甚至 [C 头文件](https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html)中见过类似的构造。 -这是来自 OpenZeppelin 的 [ERC-20 接口](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol) 的定义。 这是将[人类可读标准](https://eips.ethereum.org/EIPS/eip-20)转换为 Solidity 代码。 当然, 接口本身并不定义_如何_做事。 这一点在下文合约的源代码中作了解释。 +这是 OpenZeppelin 的 +[ERC-20 接口](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol) 定义。 它是将[人类可读标准](https://eips.ethereum.org/EIPS/eip-20)翻译成 Solidity 代码。 当然, +接口本身并不定义_如何_做任何事情。 这一点在下文合约的源代码中作了解释。   @@ -32,7 +41,8 @@ published: 2021-03-09 // SPDX-License-Identifier: MIT ``` -Solidity 文件中一般需要标识软件许可证。 [你可以在这里看到许可证列表](https://spdx.org/licenses/)。 如果需要不同的 许可证,只需在注释中加以说明。 +Solidity 文件应该包含许可证标识符。 [你可以在此处查看许可证列表](https://spdx.org/licenses/)。 如果你需要其他 +许可证,只需在注释中说明即可。   @@ -40,17 +50,20 @@ Solidity 文件中一般需要标识软件许可证。 [你可以在这里看到 pragma solidity >=0.6.0 <0.8.0; ``` -Solidity 语言仍在迅速地发展,新版本可能不适配旧的代码 ([请点击此处查看](https://docs.soliditylang.org/en/v0.7.0/070-breaking-changes.html))。 因此,最好不仅指定一个最低的 语言版本,也指定一个最高的版本,即测试过代码的最新版本。 +Solidity 语言仍在快速发展,新版本可能与旧代码不兼容 +([在此处查看](https://docs.soliditylang.org/en/v0.7.0/070-breaking-changes.html))。 因此,最好不仅指定语言的最低 +版本,还指定最高版本,即你测试过代码的最新版本。   ```solidity /** - * @dev Interface of the ERC20 standard as defined in EIP. + * @dev EIP 中定义的 ERC20 标准接口。 */ ``` -注释中的 `@dev` 是 [NatSpec 格式](https://docs.soliditylang.org/en/develop/natspec-format.html)的一部分,用于 从源代码生成文档。 +注释中的 `@dev` 是 [NatSpec 格式](https://docs.soliditylang.org/en/develop/natspec-format.html) 的一部分,用于从源代码生成 +文档。   @@ -58,135 +71,162 @@ Solidity 语言仍在迅速地发展,新版本可能不适配旧的代码 ([ interface IERC20 { ``` -根据惯例,接口名称以 `I` 开头。 +按照惯例,接口名称以 `I` 开头。   ```solidity /** - * @dev Returns the amount of tokens in existence. + * @dev 返回存在的代币数量。 */ function totalSupply() external view returns (uint256); ``` -此函数标记为 `external`,表示[它只能从合约之外调用](https://docs.soliditylang.org/en/v0.7.0/cheatsheet.html#index-2)。 它返回的是合约中代币的总供应量 这个值按以太坊中最常见的类型返回,即无符号的 256 位(256 位是 以太坊虚拟机的原生字长宽度)。 此函数也是视图 `view` 类型,这意味着它不会改变合约状态,这样它可以在单个节点上执行,而不需要在区块链的每个节点上执行。 这类函数不会生成交易,也不会消耗[燃料](/developers/docs/gas/)。 +此函数是 `external`,表示[它只能从合约外部调用](https://docs.soliditylang.org/en/v0.7.0/cheatsheet.html#index-2)。 +它返回合约中代币的总供应量。 这个值按以太坊中最常见的类型返回,即无符号的 256 位(256 位是 +以太坊虚拟机的原生字长)。 此函数也是 `view` 函数,意味着它不会改变状态,所以它可以在单个节点上执行,而不必让 +区块链中的每个节点都运行它。 这类函数不会产生交易,也不消耗[燃料](/developers/docs/gas/)。 -**注意:**理论上讲,合约创建者可能会通过返回比实际数量少的总供应量来做骗局,让每个代币 比实际看起来更有价值。 然而,这种担忧忽视了区块链的真正内涵。 所有在区块链上发生的事情都要通过每个节点 进行验证。 为了实现这一点,每个合约的机器语言代码和存储都可以在每个节点上找到。 虽然无需发布你的合约代码,但这样其它人都不会认真对待你,除非你发布源代码和用于编译的 Solidity 版本,这样人们可以用它来验证你提供的机器语言代码。 例如,请查看[此合约](https://etherscan.io/address/0xa530F85085C6FE2f866E7FdB716849714a89f4CD#code)。 +\*\*注意:\*\*理论上,合约创建者似乎可以通过返回比实际值小的总供应量来作弊,使每个代币看起来 +比实际更有价值。 然而,这种担忧忽视了区块链的真正本质。 区块链上发生的一切都可以由 +每个节点验证。 为实现这一点,每个合约的机器语言代码和存储都位于每个节点上。 虽然你不需要发布合约的 Solidity +代码,但除非你发布源代码以及用于编译它的 Solidity 版本,否则没有人会把你当回事,这样才能根据你提供的机器语言代码进行 +验证。 +例如,请参阅[此合约](https://eth.blockscout.com/address/0xa530F85085C6FE2f866E7FdB716849714a89f4CD?tab=contract)。   ```solidity /** - * @dev Returns the amount of tokens owned by `account`. + * @dev 返回 `account` 拥有的代币数量。 */ function balanceOf(address account) external view returns (uint256); ``` -顾名思义,`balanceOf` 返回一个帐户的余额。 以太坊帐户在 Solidity 中通过 `address` 类型识别,该类型有 160 位。 它也是 `external` 和 `view` 类型。 +顾名思义,`balanceOf` 返回账户余额。 以太坊账户在 Solidity 中使用 `address` 类型进行标识,该类型占 160 位。 +它也是 `external` 和 `view`。   ```solidity /** - * @dev Moves `amount` tokens from the caller's account to `recipient`. + * @dev 将 `amount` 数量的代币从调用者的账户转移到 `recipient`。 * - * Returns a boolean value indicating whether the operation succeeded. + * 返回一个布尔值,表示操作是否成功。 * - * Emits a {Transfer} event. + * 触发一个 {Transfer} 事件。 */ function transfer(address recipient, uint256 amount) external returns (bool); ``` -`transfer` 函数将代币从调用者地址转移到另一个地址。 这涉及到状态的更改,所以它不是 `view` 类型。 当用户调用此函数时,它会创建交易并消耗燃料。 还会触发一个 `Transfer` 事件,以通知区块链上的所有人。 +`transfer` 函数将代币从调用者转移到另一个地址。 这涉及状态变更,所以它不是 `view` 函数。 +当用户调用此函数时,它会创建交易并消耗燃料。 它还会触发一个 `Transfer` 事件,将该事件通知 +区块链上的所有人。 -该函数有两种输出,对应两种不同的调用: +该函数有两种输出,对应两种不同的调用者: -- 直接从用户接口调用函数的用户。 此类用户通常会提交一个交易 并且不会等待响应,因为响应可能需要无限期的时间。 用户可以查看交易收据 (通常通过交易哈希值识别)或者查看 `Transfer` 事件,以确定发生了什么。 -- 将函数作为整个交易一部分调用的其他合约 这些合约可立即获得结果, 由于它们在相同的交易里运行,因此可以使用函数返回值。 +- 直接从用户界面调用函数的用户。 通常,用户提交交易后 + 不会等待响应,因为响应可能需要不确定的时间。 用户可以 + 通过查找交易收据(通过交易哈希值识别)或查找 + `Transfer` 事件来查看发生了什么。 +- 将函数作为整个交易一部分调用的其他合约。 这些合约会立即获得结果, + 因为它们在同一笔交易中运行,所以它们可以使用函数返回值。 -更改合约状态的其他函数创建的同类型输出。 +更改合约状态的其他函数会创建相同类型的输出。   -限额允许帐户使用属于另一位所有者的代币。 比如,当合约作为卖方时,这个函数就很实用。 合约无法 监听事件,如果买方要将代币直接转给卖方合约, 该合约无法知道已经获得付款。 因此,买方允许 卖方合约支付一定的额度,而让卖方转账相应金额。 这通过卖方合约调用的函数完成,这样卖方合约 可以知道是否成功。 +授权额度允许一个账户花费属于其他所有者的代币。 +例如,对于充当卖方的合约,这很有用。 合约无法 +监控事件,因此如果买方将代币直接转移给卖方合约 +,该合约不会知道它已收到付款。 因此,买方授权 +卖方合约花费一定金额,然后卖方转走该金额。 +这是通过卖方合约调用的函数完成的,因此卖方合约 +可以知道它是否成功。 ```solidity /** - * @dev Returns the remaining number of tokens that `spender` will be - * allowed to spend on behalf of `owner` through {transferFrom}. This is - * zero by default. + * @dev 返回 `spender` 通过 {transferFrom} 可代表 `owner` 花费的 + * 剩余代币数量。默认 + * 为零。 * - * This value changes when {approve} or {transferFrom} are called. + * 调用 {approve} 或 {transferFrom} 时,此值会发生变化。 */ function allowance(address owner, address spender) external view returns (uint256); ``` -`allowance` 函数允许任何人查询一个 地址 (`owner`) 给另一个地址 (`spender`) 的许可额度。 +`allowance` 函数允许任何人查询一个 +地址(`owner`)授权另一个地址(`spender`)花费的额度。   ```solidity /** - * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * @dev 将 `spender` 对调用者代币的授权额度设置为 `amount`。 * - * Returns a boolean value indicating whether the operation succeeded. + * 返回一个布尔值,表示操作是否成功。 * - * IMPORTANT: Beware that changing an allowance with this method brings the risk - * that someone may use both the old and the new allowance by unfortunate - * transaction ordering. One possible solution to mitigate this race - * condition is to first reduce the spender's allowance to 0 and set the - * desired value afterwards: + * 重要提示:请注意,使用此方法更改授权额度会带来风险, + * 有人可能因不利的交易排序而同时使用新旧两种授权额度。 + * 缓解此竞态条件的一个可行方案是,先将花费者的授权额度降至 0, + * 然后再设置所需的值: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * - * Emits an {Approval} event. + * 触发一个 {Approval} 事件。 */ function approve(address spender, uint256 amount) external returns (bool); ``` -`approve` 函数创建了一个许可额度。 请务必阅读关于 如何避免函数被滥用的信息。 在以太坊中,你可以控制自己交易的顺序, 但无法控制其他方交易的执行顺序, 除非在看到其他方的交易发生之前 不提交你自己的交易。 +`approve` 函数创建一个授权额度。 请务必阅读有关 +如何滥用它的消息。 在以太坊中,你可以控制自己交易的顺序, +但无法控制其他人交易的执行顺序, +除非在看到对方的交易发生之前 +不提交自己的交易。   ```solidity /** - * @dev Moves `amount` tokens from `sender` to `recipient` using the - * allowance mechanism. `amount` is then deducted from the caller's - * allowance. + * @dev 使用 + * 授权机制将 `amount` 数量的代币从 `sender` 转移到 `recipient`。然后从调用者的授权额度中扣除 `amount`。 * - * Returns a boolean value indicating whether the operation succeeded. + * 返回一个布尔值,表示操作是否成功。 * - * Emits a {Transfer} event. + * 触发一个 {Transfer} 事件。 */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); ``` -最后,消费者使用 `transferFrom` 函数用来使用许可额度。 +最后,`transferFrom` 由花费者用来实际花费授权额度。   ```solidity /** - * @dev Emitted when `value` tokens are moved from one account (`from`) to - * another (`to`). + * @dev 当 `value` 数量的代币从一个帐户 (`from`) 转移到 + * 另一个 (`to`) 时触发。 * - * Note that `value` may be zero. + * 请注意,`value` 可能为零。 */ event Transfer(address indexed from, address indexed to, uint256 value); /** - * @dev Emitted when the allowance of a `spender` for an `owner` is set by - * a call to {approve}. `value` is the new allowance. + * @dev 当通过 + * 调用 {approve} 为 `owner` 设置 `spender` 的授权额度时触发。`value` 是新的授权额度。 */ event Approval(address indexed owner, address indexed spender, uint256 value); } ``` -在 ERC-20 合约状态发生变化时就会激发这些事件。 +当 ERC-20 合约的状态发生变化时,会触发这些事件。 ## 实际合约 {#the-actual-contract} -这是实现 ERC-20 标准的实际合约, [摘自此处](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)。 不能照原样使用,但可以 通过[继承](https://www.tutorialspoint.com/solidity/solidity_inheritance.htm)将其扩展,使之可用。 +这是实现 ERC-20 标准的实际合约, +[摘自此处](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)。 +它不应按原样使用,但你可以 +[继承](https://www.tutorialspoint.com/solidity/solidity_inheritance.htm)它以将其扩展为可用的东西。 ```solidity // SPDX-License-Identifier: MIT @@ -195,9 +235,9 @@ pragma solidity >=0.6.0 <0.8.0;   -### 导入声明 {#import-statements} +### Import 语句 {#import-statements} -除了上述接口定义外,合约定义还要导入两个其他文件: +除了上面的接口定义,合约定义还导入了另外两个文件: ```solidity @@ -206,37 +246,42 @@ import "./IERC20.sol"; import "../../math/SafeMath.sol"; ``` -- `GSN/Context.sol` 是使用 [OpenGSN](https://www.opengsn.org/) 所需的文件,该系统允许用户在没有以太币的情况下 使用区块链。 请注意,这里的文件是旧版本,如果需要集成 OpenGSN, [请使用此教程](https://docs.opengsn.org/javascript-client/tutorial.html)。 -- [SafeMath 库](https://ethereumdev.io/using-safe-math-library-to-prevent-from-overflows/),用于 完成没有溢出问题的加法和减法。 这非常必要,否则会出现,用户仅有一个代币,花掉 两个代币后,反而有了 2^256-1 个代币。 +- `GSN/Context.sol` 是使用 [OpenGSN](https://www.opengsn.org/) 所需的定义,该系统允许没有以太币的用户 + 使用区块链。 请注意,这是一个旧版本,如果你想与 OpenGSN 集成 + [请使用本教程](https://docs.opengsn.org/javascript-client/tutorial.html)。 +- [SafeMath 库](https://ethereumdev.io/using-safe-math-library-to-prevent-from-overflows/),用于防止 Solidity **<0.8.0** 版本中的 + 算术上溢/下溢。 在 Solidity ≥0.8.0 中,算术运算在 + 上溢/下溢时会自动还原,因此不再需要 SafeMath。 此合约使用 SafeMath 是为了与 + 旧版编译器向后兼容。   -这里的注释说明了合约的目的。 +此注释说明了合约的目的。 ```solidity /** - * @dev Implementation of the {IERC20} interface. + * @dev {IERC20} 接口的实现。 * - * This implementation is agnostic to the way tokens are created. This means - * that a supply mechanism has to be added in a derived contract using {_mint}. - * For a generic mechanism see {ERC20PresetMinterPauser}. + * 此实现与代币的创建方式无关。这意味着 + * 必须使用 {_mint} 在派生合约中添加供应机制。 + * 有关通用机制,请参阅 {ERC20PresetMinterPauser}。 * - * TIP: For a detailed writeup see our guide - * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How - * to implement supply mechanisms]. + * 提示:有关详细的说明,请参阅我们的指南 + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[如何 + * 实现供应机制]。 * - * We have followed general OpenZeppelin guidelines: functions revert instead - * of returning `false` on failure. This behavior is nonetheless conventional - * and does not conflict with the expectations of ERC20 applications. + * 我们遵循了通用的 OpenZeppelin 指南:函数在失败时会还原,而 + * 不会返回 `false`。但是,此行为是常规行为, + * 并且与 ERC20 应用程序的预期不冲突。 * - * Additionally, an {Approval} event is emitted on calls to {transferFrom}. - * This allows applications to reconstruct the allowance for all accounts just - * by listening to said events. Other implementations of the EIP may not emit - * these events, as it isn't required by the specification. + * 此外,在调用 {transferFrom} 时会触发 {Approval} 事件。 + * 这允许应用程序仅通过监听所述事件 + * 即可重建所有账户的授权额度。EIP 的其他实现 + * 可能不会触发这些事件,因为规范没有要求。 * - * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} - * functions have been added to mitigate the well-known issues around setting - * allowances. See {IERC20-approve}. + * 最后,添加了非标准的 {decreaseAllowance} 和 {increaseAllowance} + * 函数,以缓解围绕设置 + * 授权额度的众所周知的问题。请参阅 {IERC20-approve}。 */ ``` @@ -257,27 +302,36 @@ contract ERC20 is Context, IERC20 { ``` -此行将 `SafeMath` 库附加到 `uint256` 类型。 你可以在 [此处](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol)找到此程序库。 +此行将 `SafeMath` 库附加到 `uint256` 类型。 你可以在 +[此处](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol)找到此库。 -### 变量的定义 {#variable-definitions} +### 变量定义 {#variable-definitions} -这些定义具体指定了合约的状态变量。 虽然声明这些变量为 `private`,但 这只意味着区块链上的其他合约无法读取它们。 _区块链上 没有秘密_,所有节点上的软件在每个区块上 都有每个合约的状态。 根据惯例,状态变量名称为 `_`。 +这些定义指定了合约的状态变量。 这些变量被声明为 `private`,但这只意味着区块链上的其他合约无法读取它们。 区块链上 +_没有秘密_,每个节点上的软件都有每个区块中 +每个合约的状态。 按照惯例,状态变量命名为 `_`。 -前两个变量是[映射](https://www.tutorialspoint.com/solidity/solidity_mappings.htm), 表示它们的结果与[关联数组](https://wikipedia.org/wiki/Associative_array)相同, 不同之处在于关键词为数值。 存储空间仅分配给数值不同于 默认值(零)的条目。 +前两个变量是[映射](https://www.tutorialspoint.com/solidity/solidity_mappings.htm), +这意味着它们的行为大致与[关联数组](https://wikipedia.org/wiki/Associative_array)相同, +只是键是数值。 存储空间仅分配给值不同于 +默认值(零)的条目。 ```solidity mapping (address => uint256) private _balances; ``` -第一个映射,`_balances`,是代币地址和对应的余额。 要查看 余额,请使用此语法:`_balances[
]`。 +第一个映射 `_balances` 是地址及其各自的此代币余额。 要访问 +余额,请使用此语法:`_balances[
]`。   ```solidity - 映射 (address => mapping (address => uint256)) private _allowances; + mapping (address => mapping (address => uint256)) private _allowances; ``` -此变量,`_allowances` 存储之前提到过的许可限额。 第一个索引是 代币的所有者,第二个索引是获得许可限额的合约。 要查询地址 A 可以 从地址 B 帐户中支出的额度,请使用 `_allowances[B][A]`。 +此变量 `_allowances` 存储前面解释的授权额度。 第一个索引是 +代币的所有者,第二个索引是具有授权额度的合约。 要访问地址 A 可以 +从地址 B 的账户中花费的金额,请使用 `_allowances[B][A]`。   @@ -295,126 +349,142 @@ contract ERC20 is Context, IERC20 { uint8 private _decimals; ``` -这三个变量用于提高可读性。 前两项的含义不言自明,但 `_decimals` 并非如此。 +这三个变量用于提高可读性。 前两项的含义不言自明,但 `_decimals` +并非如此。 -一方面,以太坊不具有浮点数或分数变量。 另一方面, 人们希望能够拆分代币。 人们选择将黄金做为货币的一个原因是 当有人想要购买一只牛的一小部分时,就很难找零。 +一方面,以太坊没有浮点或分数变量。 另一方面, +人们希望能够拆分代币。 人们选择将黄金作为货币的一个原因是, +当有人想用牛换鸭子时,很难找零。 -解决方案是保持整数值,但是计数时使用一个价值非常小的分数代币, 而不是真正的代币。 就以太币而言,分数代币称为 wei,10^18 个 wei 等于一个 以太币。 在撰写本文时,10,000,000,000,000 wei 约等于一美分或欧分。 +解决方案是跟踪整数,但计数时使用一个价值非常小的分数代币, +而不是真正的代币。 就以太币而言,分数代币称为 wei,10^18 个 wei 等于一个 +ETH。 在撰写本文时,10,000,000,000,000 wei 约等于一美分或欧分。 -应用程序需要知道如何显示代币余额。 如果某位用户有 3,141,000,000,000,000,000 wei,那是否是 3.14 个以太币? 31.41 个以太币? 还是 3,141 个以太币? 对于以太币,10^18 个 wei 等于 1 个以太币,但对于你的 代币,你可以选择一个不同的值。 如果无法合理拆分代币,你可以将 `_decimals` 值设为零。 如果想要使用与以太币相同的标准,请使用 **18**。 +应用程序需要知道如何显示代币余额。 如果某位用户有 3,141,000,000,000,000,000 wei,那是否是 +3.14 个 ETH? 31.41 个 ETH? 3,141 个 ETH? 对于以太币,10^18 wei 等于 1 个 ETH,但对于你的 +代币,你可以选择一个不同的值。 如果拆分代币没有意义,你可以将 +`_decimals` 值设为零。 如果想要使用与 ETH 相同的标准,请使用值 **18**。 ### 构造函数 {#the-constructor} ```solidity /** - * @dev Sets the values for {name} and {symbol}, initializes {decimals} with - * a default value of 18. + * @dev 设置 {name} 和 {symbol} 的值,用 + * 默认值 18 初始化 {decimals}。 * - * To select a different value for {decimals}, use {_setupDecimals}. + * 要为 {decimals} 选择不同的值,请使用 {_setupDecimals}。 * - * All three of these values are immutable: they can only be set once during - * construction. + * 所有这三个值都是不可变的:它们只能在 + * 构造期间设置一次。 */ constructor (string memory name_, string memory symbol_) public { + // In Solidity ≥0.7.0, 'public' is implicit and can be omitted. + _name = name_; _symbol = symbol_; _decimals = 18; } ``` -构造函数在首次创建合约时调用。 根据惯例,函数参数名为 `_`。 +构造函数在首次创建合约时调用。 按照惯例,函数参数名为 `_`。 -### 用户接口函数 {#user-interface-functions} +### 用户界面函数 {#user-interface-functions} ```solidity /** - * @dev Returns the name of the token. + * @dev 返回代币的名称。 */ function name() public view returns (string memory) { return _name; } /** - * @dev Returns the symbol of the token, usually a shorter version of the - * name. + * @dev 返回代币的符号,通常是 + * 名称的缩写。 */ function symbol() public view returns (string memory) { return _symbol; } /** - * @dev Returns the number of decimals used to get its user representation. - * For example, if `decimals` equals `2`, a balance of `505` tokens should - * be displayed to a user as `5,05` (`505 / 10 ** 2`). + * @dev 返回用于获取其用户表示的小数位数。 + * 例如,如果 `decimals` 等于 `2`,`505` 个代币的余额应 + * 向用户显示为 `5,05` (`505 / 10 ** 2`)。 * - * Tokens usually opt for a value of 18, imitating the relationship between - * ether and wei. This is the value {ERC20} uses, unless {_setupDecimals} is - * called. + * 代币通常选择值 18,模仿 + * 以太币和 wei 之间的关系。这是 {ERC20} 使用的值,除非 + * 调用 {_setupDecimals}。 * - * NOTE: This information is only used for _display_ purposes: it in - * no way affects any of the arithmetic of the contract, including - * {IERC20-balanceOf} and {IERC20-transfer}. + * 注意:此信息仅用于_显示_目的:它 + * 绝不影响合约的任何算术,包括 + * {IERC20-balanceOf} 和 {IERC20-transfer}。 */ function decimals() public view returns (uint8) { return _decimals; } ``` -这些函数,`name`、`symbol` 和 `decimals` 帮助用户界面了解合约,从而正常演示合约。 +这些函数,`name`、`symbol` 和 `decimals` 帮助用户界面了解你的合约,以便它们能够正确显示。 -返回类型为 `string memory`,意味着返回在内存中存储的字符串。 变量,如 字符串,可以存储在三个位置: +返回类型是 `string memory`,表示返回存储在内存中的字符串。 变量,例如 +字符串,可以存储在三个位置: -| | 有效时间 | 合约访问 | 燃料成本 | +| | 生命周期 | 合约访问 | 燃料成本 | | ---- | ----- | ---- | ------------------- | -| 内存 | 函数调用 | 读/写 | 几十到几百不等(距离越远费用越高) | -| 调用数据 | 函数调用 | 只读 | 不可用作返回类型,只可用作函数参数 | -| 存储 | 直到被修改 | 读/写 | 高(读取需要 800,写入需要 2万) | +| 内存 | 函数调用 | 读/写 | 几十到几百不等(位置越高成本越高) | +| 调用数据 | 函数调用 | 只读 | 不能用作返回类型,只能用作函数参数类型 | +| 存储 | 直到被修改 | 读/写 | 高(读取为 800,写入为 2 万) | 在这种情况下,`memory` 是最好的选择。 ### 读取代币信息 {#read-token-information} -这些是提供代币信息的函数,不管是总量还是 帐户余额。 +这些是提供代币信息的函数,无论是总供应量还是 +账户余额。 ```solidity /** - * @dev See {IERC20-totalSupply}. + * @dev 请参阅 {IERC20-totalSupply}。 */ function totalSupply() public view override returns (uint256) { return _totalSupply; } ``` -`totalSupply` 函数返回代币的总量。 +`totalSupply` 函数返回代币的总供应量。   ```solidity /** - * @dev See {IERC20-balanceOf}. + * @dev 请参阅 {IERC20-balanceOf}。 */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } ``` -读取一个帐户的余额。 请注意,任何人都可以查看他人帐户的余额。 试图隐藏此信息没有意义,因为它在每个节点上 都是可见的。 _区块链上没有秘密_ +读取账户余额。 请注意,任何人都可以获取其他任何人的账户 +余额。 试图隐藏此信息没有意义,因为它在每个节点上 +都是可见的。 _区块链上没有秘密。_ -### 代币转账 {#transfer-tokens} +### 转移代币 {#transfer-tokens} ```solidity /** - * @dev See {IERC20-transfer}. + * @dev 请参阅 {IERC20-transfer}。 * - * Requirements: + * 要求: * - * - `recipient` cannot be the zero address. - * - the caller must have a balance of at least `amount`. + * - `recipient` 不能是零地址。 + * - 调用者必须拥有至少 `amount` 的余额。 */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { ``` -调用 `transfer` 函数以从发送人的帐户转移代币到另一个帐户。 注意 虽然函数返回的是布尔值,但那个值始终为**真实值**。 如果转账失败, 合约会撤销调用。 +`transfer` 函数用于将代币从发送者的账户转移到另一个账户。 请注意 +,即使它返回一个布尔值,该值也始终为 **true**。 如果转移 +失败,合约将还原调用。   @@ -424,44 +494,51 @@ contract ERC20 is Context, IERC20 { } ``` -`_transfer` 函数完成了实际工作。 这是一个私有函数,只能由 其他合约函数调用。 根据常规,私人函数名为 `_`,与状态 变量相同。 +`_transfer` 函数执行实际工作。 它是一个私有函数,只能由 +其他合约函数调用。 按照惯例,私有函数命名为 `_`,与状态 +变量相同。 -在 Solidity 中,我们通常使用 `msg.sender` 代表信息发送人。 然而,这会破坏 [OpenGSN](http://opengsn.org/) 的规则。 如果我们想使用代币进行交易而不用以太币,我们 需要使用 `_msgSender()`。 对于正常交易,它返回 `msg.sender`,但是对于没有以太币的交易, 则返回原始签名而不是传递信息的合约。 +通常在 Solidity 中,我们使用 `msg.sender` 表示消息发送者。 然而,这会破坏 +[OpenGSN](http://opengsn.org/)。 如果我们想允许使用我们的代币进行无以太币交易,我们 +需要使用 `_msgSender()`。 对于正常交易,它返回 `msg.sender`,但对于无以太币的交易, +它返回原始签名者而不是中继消息的合约。 -### 许可额度函数 {#allowance-functions} +### 授权额度函数 {#allowance-functions} -这些是实现许可额度功能的函数:`allowance`、`approve`、`transferFrom` 和 `_approve`。 此外,除基本标准外,OpenZeppelin 实现还包含了一些能够提高 安全性的功能:`increaseAllowance` 和 ` decreaseAllowance `。 +这些是实现授权额度功能的函数:`allowance`、`approve`、`transferFrom` +和 `_approve`。 此外,OpenZeppelin 实现超出了基本标准,包含了一些提高 +安全性的功能:`increaseAllowance` 和 `decreaseAllowance`。 -#### 许可额度函数 {#allowance} +#### allowance 函数 {#allowance} ```solidity /** - * @dev See {IERC20-allowance}. + * @dev 请参阅 {IERC20-allowance}。 */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } ``` -`allowance` 函数使每个人都能检查任何许可额度。 +`allowance` 函数允许任何人检查任何授权额度。 -#### 审批函数 {#approve} +#### approve 函数 {#approve} ```solidity /** - * @dev See {IERC20-approve}. + * @dev 请参阅 {IERC20-approve}。 * - * Requirements: + * 要求: * - * - `spender` cannot be the zero address. + * - `spender` 不能是零地址。 */ function approve(address spender, uint256 amount) public virtual override returns (bool) { ``` -调用此函数以创建许可额度。 它与上述 `transfer` 函数相似: +此函数用于创建授权额度。 它与上面的 `transfer` 函数相似: -- 该函数仅调用一个完成真正工作的内部函数(本例中为 `_approve`)。 -- 函数要么返回 `true`(如果成功),要么撤销(如果失败)。 +- 该函数仅调用一个执行实际工作的内部函数(本例中为 `_approve`)。 +- 函数要么返回 `true`(如果成功),要么还原(如果失败)。   @@ -471,25 +548,27 @@ contract ERC20 is Context, IERC20 { } ``` -我们使用内部函数尽量减少发生状态变化之处。 _任何_可以改变状态的 函数都是一种潜在的安全风险,需要对其安全性进行审核。 这样我们就能减少出错的机会。 +我们使用内部函数来尽量减少发生状态变化的地方。 _任何_改变 +状态的函数都是潜在的安全风险,需要进行安全审计。 这样我们出错的机会就更少了。 -#### TransferFrom 函数 {#transferFrom} +#### transferFrom 函数 {#transferFrom} -这个函数被消费者用于使用许可额度。 这里需要两步操作:将消费的金额转账, 并在许可额度中减去这笔金额。 +这个函数由花费者调用以花费授权额度。 这需要两个操作:转移花费的金额 +并从授权额度中减去该金额。 ```solidity /** - * @dev See {IERC20-transferFrom}. + * @dev 请参阅 {IERC20-transferFrom}。 * - * Emits an {Approval} event indicating the updated allowance. This is not - * required by the EIP. See the note at the beginning of {ERC20}. + * 触发一个 {Approval} 事件,指示更新后的授权额度。EIP + * 并未要求此项。请参阅 {ERC20} 开头的注释。 * - * Requirements: + * 要求: * - * - `sender` and `recipient` cannot be the zero address. - * - `sender` must have a balance of at least `amount`. - * - the caller must have allowance for ``sender``'s tokens of at least - * `amount`. + * - `sender` 和 `recipient` 不能是零地址。 + * - `sender` 必须拥有至少 `amount` 的余额。 + * - 调用者必须拥有至少 `amount` 的 ``sender`` 代币授权额度 + * 。 */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { @@ -498,7 +577,9 @@ contract ERC20 is Context, IERC20 {   -`a.sub(b, "message")` 函数调用做了两件事。 首先,它计算了 `a-b`,这是新的许可额度。 之后,它检查这一结果是否为负数。 如果结果为负,将撤销调用,并发出相应的信息。 请注意,撤销调用后,之前在调用中完成的任何处理都会被忽略,所以我们不需要 撤消 `_transfer`。 +`a.sub(b, "message")` 函数调用做了两件事。 首先,它计算 `a-b`,这是新的授权额度。 +其次,它检查此结果是否为负数。 如果结果为负,将还原调用,并发出提供的消息。 请注意,当调用还原时,该调用期间先前完成的任何处理都将被忽略,因此我们不需要 +撤销 `_transfer`。 ```solidity _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, @@ -507,50 +588,60 @@ contract ERC20 is Context, IERC20 { } ``` -#### OpenZeppelin 安全加法 {#openzeppelin-safety-additions} +#### OpenZeppelin 安全补充 {#openzeppelin-safety-additions} -将许可额度从一个非零值设定为另一个非零值是有危险的, 因为你只能控制自己的交易顺序,而无法控制其他人的交易顺序。 假设现在有两个用户,天真的 Alice 和不诚实的 Bill。 Alice 想要从 Bill 处获取一些服务, 她认为值五个代币,所以她给了 Bill 五个代币的许可额度。 +将非零授权额度设置为另一个非零值是危险的, +因为你只能控制自己交易的顺序,而不能控制其他人的交易顺序。 假设现在有两个用户,天真的 Alice 和不诚实的 Bill。 Alice 想要从 Bill 处获取一些服务, +她认为值五个代币,所以她给了 Bill 五个代币的授权额度。 -之后有了一些变化,Bill 的价格提高到了十个代币。 Alice 仍然想要购买服务,就发送了一笔交易,将 Bill 的许可额度设置为 10。 当 Bill 在交易池中看到这个新的交易时, 他就会发送一笔交易,以花费 Alice 的五个代币,并且设定高得多的 燃料价格,这样就会更快挖矿。 这样的话,Bill 可以先花五个代币,然后 当 Alice 的新许可额度放款后,他就可以再花费十个代币,这样总共花费了 15 个代币, 超过了 Alice 本欲授权的金额。 这种技术叫做 [抢先交易](https://consensysdiligence.github.io/smart-contract-best-practices/attacks/#front-running) +之后有了一些变化,Bill 的价格提高到了十个代币。 Alice 仍然想要购买服务,就发送了一笔交易,将 Bill 的授权额度设置为 10。 当 Bill 在交易池中看到这个新的交易时, +他就会发送一笔交易,以花费 Alice 的五个代币,并且设定高得多的 +燃料价格,这样就会更快挖出。 这样,Bill 可以先花五个代币,然后 +当 Alice 的新授权额度被挖出后,他就可以再花费十个代币,这样总共花费了 15 个代币, +超过了 Alice 本欲授权的金额。 这种技术称为 +[抢先交易](https://consensysdiligence.github.io/smart-contract-best-practices/attacks/#front-running) -| Alice 的交易 | Alice 的随机数 | Bill 的交易 | Bill 的随机数 | Bill 的许可额度 | Bill 从 Alice 处获得的总收入 | -| ----------------- | ---------- | ----------------------------- | --------- | ---------- | -------------------- | -| approve(Bill, 5) | 10 | | | 5 | 0 | -| | | transferFrom(Alice, Bill, 5) | 10,123 | 0 | 5 | -| approve(Bill, 10) | 11 | | | 10 | 5 | -| | | transferFrom(Alice, Bill, 10) | 10,124 | 0 | 15 | +| Alice 的交易 | Alice 的随机数 | Bill 的交易 | Bill 的随机数 | Bill 的授权额度 | Bill 从 Alice 处获得的总收入 | +| ------------------------------------ | ---------- | ------------------------------------------------ | --------- | ---------- | -------------------- | +| approve(Bill, 5) | 10 | | | 5 | 0 | +| | | transferFrom(Alice, Bill, 5) | 10,123 | 0 | 5 | +| approve(Bill, 10) | 11 | | | 10 | 5 | +| | | transferFrom(Alice, Bill, 10) | 10,124 | 0 | 15 | -为了避免这个问题,有两个函数(`increaseAllowance` 和 `decreaseAllowance`)使你 能够修改指定数额的许可额度。 所以,如果 Bill 已经花费了五个代币, 他就只能再花五个代币。 根据时间的不同,有两种方法可以生效, 这两种方法都会使 Bill 最终只得到十个代币: +为避免此问题,这两个函数(`increaseAllowance` 和 `decreaseAllowance`)允许你 +修改指定数额的授权额度。 所以,如果 Bill 已经花费了五个代币, +他就只能再花五个代币。 根据时间的不同,有两种方法可以生效, +这两种方法都会使 Bill 最终只得到十个代币: A: -| Alice 的交易 | Alice 的随机数 | Bill 的交易 | Bill 的随机数 | Bill 的许可额度 | Bill 从 Alice 处获得的总收入 | -| -------------------------- | ----------:| ---------------------------- | ---------:| ----------:| -------------------- | -| approve(Bill, 5) | 10 | | | 5 | 0 | -| | | transferFrom(Alice, Bill, 5) | 10,123 | 0 | 5 | -| increaseAllowance(Bill, 5) | 11 | | | 0+5 = 5 | 5 | -| | | transferFrom(Alice, Bill, 5) | 10,124 | 0 | 10 | +| Alice 的交易 | Alice 的随机数 | Bill 的交易 | Bill 的随机数 | Bill 的授权额度 | Bill 从 Alice 处获得的总收入 | +| --------------------------------------------- | ---------: | ----------------------------------------------- | --------: | ---------: | -------------------- | +| approve(Bill, 5) | 10 | | | 5 | 0 | +| | | transferFrom(Alice, Bill, 5) | 10,123 | 0 | 5 | +| increaseAllowance(Bill, 5) | 11 | | | 0+5 = 5 | 5 | +| | | transferFrom(Alice, Bill, 5) | 10,124 | 0 | 10 | B: -| Alice 的交易 | Alice 的随机数 | Bill 的交易 | Bill 的随机数 | Bill 的许可额度 | Bill 从 Alice 处获得的总收入 | -| -------------------------- | ----------:| ----------------------------- | ---------:| ----------:| --------------------:| -| approve(Bill, 5) | 10 | | | 5 | 0 | -| increaseAllowance(Bill, 5) | 11 | | | 5+5 = 10 | 0 | -| | | transferFrom(Alice, Bill, 10) | 10,124 | 0 | 10 | +| Alice 的交易 | Alice 的随机数 | Bill 的交易 | Bill 的随机数 | Bill 的授权额度 | Bill 从 Alice 处获得的总收入 | +| --------------------------------------------- | ---------: | ------------------------------------------------ | --------: | ---------: | -------------------: | +| approve(Bill, 5) | 10 | | | 5 | 0 | +| increaseAllowance(Bill, 5) | 11 | | | 5+5 = 10 | 0 | +| | | transferFrom(Alice, Bill, 10) | 10,124 | 0 | 10 | ```solidity /** - * @dev Atomically increases the allowance granted to `spender` by the caller. + * @dev 以原子方式增加调用者授予 `spender` 的授权额度。 * - * This is an alternative to {approve} that can be used as a mitigation for - * problems described in {IERC20-approve}. + * 这是 {approve} 的替代方案,可用于缓解 + * {IERC20-approve} 中描述的问题。 * - * Emits an {Approval} event indicating the updated allowance. + * 触发一个 {Approval} 事件,指示更新后的授权额度。 * - * Requirements: + * 要求: * - * - `spender` cannot be the zero address. + * - `spender` 不能是零地址。 */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); @@ -558,23 +649,24 @@ B: } ``` -`a.add(b)` 函数是一个安全加法。 在罕见的情况下,`a`+`b`>=`2^256`,不会发生 普通加法会出现的溢出错误。 +`a.add(b)` 函数是一个安全加法。 在 `a`+`b`>=`2^256` 的罕见情况下,它不会像 +普通加法那样发生环绕。 ```solidity /** - * @dev Atomically decreases the allowance granted to `spender` by the caller. + * @dev 以原子方式减少调用者授予 `spender` 的授权额度。 * - * This is an alternative to {approve} that can be used as a mitigation for - * problems described in {IERC20-approve}. + * 这是 {approve} 的替代方案,可用于缓解 + * {IERC20-approve} 中描述的问题。 * - * Emits an {Approval} event indicating the updated allowance. + * 触发一个 {Approval} 事件,指示更新后的授权额度。 * - * Requirements: + * 要求: * - * - `spender` cannot be the zero address. - * - `spender` must have allowance for the caller of at least - * `subtractedValue`. + * - `spender` 不能是零地址。 + * - `spender` 必须拥有至少 + * `subtractedValue` 的调用者授权额度。 */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, @@ -585,29 +677,31 @@ B: ### 修改代币信息的函数 {#functions-that-modify-token-information} -这些是完成实际工作的四个函数:`_transfer`、`_mint`、`_burn` 和 `_approve`。 +这些是执行实际工作的四个函数:`_transfer`、`_mint`、`_burn` 和 `_approve`。 -#### \_transfer 函数 {#_transfer} +#### _transfer 函数 {#_transfer} ```solidity /** - * @dev Moves tokens `amount` from `sender` to `recipient`. + * @dev 将 `amount` 数量的代币从 `sender` 转移到 `recipient`。 * - * This is internal function is equivalent to {transfer}, and can be used to - * e.g., implement automatic token fees, slashing mechanisms, etc. + * 这个内部函数等同于 {transfer},可用于 + * 例如,实现自动代币费用、惩罚机制等。 * - * Emits a {Transfer} event. + * 触发一个 {Transfer} 事件。 * - * Requirements: + * 要求: * - * - `sender` cannot be the zero address. - * - `recipient` cannot be the zero address. - * - `sender` must have a balance of at least `amount`. + * - `sender` 不能是零地址。 + * - `recipient` 不能是零地址。 + * - `sender` 必须拥有至少 `amount` 的余额。 */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { ``` -`_transfer` 这个函数将代币从一个帐户转到另一个帐户。 有两个函数调用它,分别是 `transfer`(从发送人本人帐户发送)和 `transferFrom`(使用许可额度,从其他人的帐户发送)。 +这个函数 `_transfer` 将代币从一个账户转移到另一个账户。 它由 +`transfer`(用于从发送者自己的账户转移)和 `transferFrom`(用于使用授权额度 +从其他人的账户转移)调用。   @@ -616,7 +710,8 @@ B: require(recipient != address(0), "ERC20: transfer to the zero address"); ``` -实际上以太坊中没有人拥有零地址(即不存在对应公钥可以转换为零地址的私钥)。 有人使用该地址时,通常是一个软件漏洞,所以 如果将零地址用作发送人或接收人,交易将失败。 +实际上以太坊中没有人拥有零地址(即不存在对应公钥可以转换为零地址的私钥)。 当人们使用该地址时,通常是一个软件漏洞,所以 +如果将零地址用作发送人或接收人,交易将失败。   @@ -627,12 +722,15 @@ B: 使用该合约有两种方法: -1. 将其作为模板,编写自己的代码 -1. [从它继承](https://www.bitdegree.org/learn/solidity-inheritance)一个合约,并且重写你需要修改的函数 +1. 将其用作你自己的代码的模板 +2. [继承它](https://www.bitdegree.org/learn/solidity-inheritance),并仅覆盖你需要修改的那些函数 -第二种方法要好得多,因为 OpenZeppelin ERC-20 代码已经过审核,其安全性也已得到证实。 当你的合约继承它时, 可以清楚地表明修改了哪些函数,只需要审核这些特定的函数,人们就会信任你的合约。 +第二种方法要好得多,因为 OpenZeppelin ERC-20 代码已经过审核,其安全性也已得到证实。 当你使用继承时, +你可以清楚地表明你修改了哪些函数,而信任你的合约的人只需要审核那些特定的函数。 -代币每次易手时,通常都需要调用一个函数。 然而,`_transfer` 是一个非常重要的函数, 重新编写可能会不安全(见下文),所以最好不要重写。 解决方案是重写 `_beforeTokenTransfer` 函数,这是一个[挂钩函数](https://wikipedia.org/wiki/Hooking)。 你可以重写此函数,之后每次转账都会调用它。 +代币每次易手时,执行一个函数通常很有用。 然而,`_transfer` 是一个非常重要的函数, +编写它可能会不安全(见下文),所以最好不要覆盖它。 解决方案是 `_beforeTokenTransfer`,一个 +[钩子函数](https://wikipedia.org/wiki/Hooking)。 你可以覆盖此函数,每次转移都会调用它。   @@ -641,7 +739,10 @@ B: _balances[recipient] = _balances[recipient].add(amount); ``` -这些是实际实现转账的代码。 请注意,将转账金额从发送人帐户上扣除,然后加到接收人帐户之间, 不得有任何**动作**。 这很重要,因为如果 中间调用不同的合约,可能会被用来骗过这个合约。 目前转账为最小操作单元,即中间什么都不会发生。 +这些是实际执行转移的代码。 请注意,它们之间**没有任何东西**,并且我们在将转账金额加到接收人账户之前,先从发送人账户中扣除 +。 这很重要,因为如果 +中间调用了另一个合约,可能会被用来骗过这个合约。 这样,转移 +是原子性的,中间不会发生任何事情。   @@ -650,23 +751,32 @@ B: } ``` -最后,激发一个 `Transfer` 事件。 智能合约无法访问事件,但区块链外运行的代码 可以监听事件并对其作出反应。 例如,钱包可以跟踪所有者获得更多代币事件。 +最后,触发一个 `Transfer` 事件。 智能合约无法访问事件,但区块链外运行的代码 +可以监听事件并对其作出反应。 例如,钱包可以跟踪所有者何时获得更多代币。 -#### \_mint 和 \_burn 函数 {#_mint-and-_burn} +#### _mint 和 _burn 函数 {#_mint-and-_burn} -这两个函数(`_mint` 和 `_burn`)修改代币的总供应量。 它们都是内部函数,在原有合约中没有任何调用它们的函数。 因此,仅通过继承合约并添加你自己的逻辑, 来决定在什么条件下可以铸造新代币或消耗现有代币时, 它们才是有用的。 +这两个函数(`_mint` 和 `_burn`)修改代币的总供应量。 +它们是内部函数,在此合约中没有调用它们的函数, +因此,仅当你继承该合约并添加自己的 +逻辑来决定在何种条件下铸造新代币或销毁现有 +代币时,它们才有用。 -**注意:**每一个 ERC-20 代币都通过自己的业务逻辑来决定代币管理。 例如,一个固定供应总量的合约可能只在构造函数中调用 `_mint`,而从不调用 `_burn`。 一个销售代币的合约 将在支付时调用 `_mint`,并大概在某个时间点调用 `_burn`, 以避免过快的通货膨胀。 +\*\*注意:\*\*每个 ERC-20 代币都有自己的业务逻辑来决定代币管理。 +例如,一个固定供应量的合约可能只在构造函数中调用 `_mint` +,而从不调用 `_burn`。 一个销售代币的合约 +将在收到付款时调用 `_mint`,并大概在某个时间点调用 `_burn`, +以避免失控的通货膨胀。 ```solidity - /** @dev Creates `amount` tokens and assigns them to `account`, increasing - * the total supply. + /** @dev 创建 `amount` 数量的代币并将其分配给 `account`,增加 + * 总供应量。 * - * Emits a {Transfer} event with `from` set to the zero address. + * 触发一个 {Transfer} 事件,其中 `from` 设置为零地址。 * - * Requirements: + * 要求: * - * - `to` cannot be the zero address. + * - `to` 不能是零地址。 */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); @@ -681,17 +791,17 @@ B:   -``` +```solidity /** - * @dev Destroys `amount` tokens from `account`, reducing the - * total supply. + * @dev 从 `account` 销毁 `amount` 数量的代币,减少 + * 总供应量。 * - * Emits a {Transfer} event with `to` set to the zero address. + * 触发一个 {Transfer} 事件,其中 `to` 设置为零地址。 * - * Requirements: + * 要求: * - * - `account` cannot be the zero address. - * - `account` must have at least `amount` tokens. + * - `account` 不能是零地址。 + * - `account` 必须拥有至少 `amount` 的代币。 */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); @@ -706,23 +816,26 @@ B: `_burn` 函数与 `_mint` 函数几乎完全相同,但它们的方向相反。 -#### \_approve 函数 {#_approve} +#### _approve 函数 {#_approve} -这是实际设定许可额度的函数。 请注意,它允许所有者指定 一个高于所有者当前余额的许可额度。 这是允许的,因为在转账时 会核查余额,届时可能不同于 创建许可额度时的金额。 +这是实际指定授权额度的函数。 请注意,它允许所有者指定 +一个高于所有者当前余额的授权额度。 这是可以的,因为余额在 +转移时会进行检查,届时余额可能不同于创建授权额度时的 +余额。 ```solidity /** - * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. + * @dev 将 `spender` 对 `owner` 代币的授权额度设置为 `amount`。 * - * This internal function is equivalent to `approve`, and can be used to - * e.g., set automatic allowances for certain subsystems, etc. + * 此内部函数等同于 `approve`,可用于 + * 例如,为某些子系统设置自动授权额度等。 * - * Emits an {Approval} event. + * 触发一个 {Approval} 事件。 * - * Requirements: + * 要求: * - * - `owner` cannot be the zero address. - * - `spender` cannot be the zero address. + * - `owner` 不能是零地址。 + * - `spender` 不能是零地址。 */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); @@ -733,7 +846,8 @@ B:   -激发一个 `Approval` 事件。 根据应用程序的编写, 消费者合约可以从代币所有者或监听事件的服务器获知审批结果。 +触发一个 `Approval` 事件。 根据应用程序的编写方式, +花费者合约可以从所有者或监听这些事件的服务器获知批准结果。 ```solidity emit Approval(owner, spender, amount); @@ -741,57 +855,73 @@ B: ``` -### 修改小数点设置变量 {#modify-the-decimals-variable} +### 修改 Decimals 变量 {#modify-the-decimals-variable} ```solidity /** - * @dev Sets {decimals} to a value other than the default one of 18. + * @dev 将 {decimals} 设置为不同于默认值 18 的值。 * - * WARNING: This function should only be called from the constructor. Most - * applications that interact with token contracts will not expect - * {decimals} to ever change, and may work incorrectly if it does. + * 警告:此函数应仅从构造函数中调用。大多数 + * 与代币合约交互的应用程序不希望 + * {decimals} 发生变化,如果发生变化可能会导致工作不正常。 */ function _setupDecimals(uint8 decimals_) internal { _decimals = decimals_; } ``` -此函数修改了 `>_decimals` 变量,此变量用于设置用户接口如何计算金额。 你应该从构造函数里面调用。 在之后的任何时候调用都是不正当的, 应用程序一般不会处理。 +此函数修改 `_decimals` 变量,该变量用于告知用户界面如何解释金额。 +你应该从构造函数中调用它。 在之后的任何时候调用都是不诚实的, +应用程序也并非设计用于处理这种情况。 ### 钩子 {#hooks} ```solidity /** - * @dev Hook that is called before any transfer of tokens. This includes - * minting and burning. + * @dev 在任何代币转移之前调用的钩子函数。这包括 + * 铸造和销毁。 * - * Calling conditions: + * 调用条件: * - * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens - * will be to transferred to `to`. - * - when `from` is zero, `amount` tokens will be minted for `to`. - * - when `to` is zero, `amount` of ``from``'s tokens will be burned. - * - `from` and `to` are never both zero. + * - 当 `from` 和 `to` 都非零时,`amount` 数量的 ``from`` 代币 + * 将被转移到 `to`。 + * - 当 `from` 为零时,将为 `to` 铸造 `amount` 数量的代币。 + * - 当 `to` 为零时,将销毁 `amount` 数量的 ``from`` 代币。 + * - `from` 和 `to` 永远不会都为零。 * - * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + * 要了解有关钩子函数的更多信息,请转到 xref:ROOT:extending-contracts.adoc#using-hooks[使用钩子函数]。 */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } } ``` -这是转账过程中要调用的挂钩函数。 该函数是空的,但如果你需要 它做一些事情,只需覆盖它即可。 +这是在转移过程中要调用的钩子函数。 这里是空的,但如果你需要 +它做一些事情,只需覆盖它即可。 + +## 结论 {#conclusion} -## 总结 {#conclusion} +为了复习,以下是此合约中一些最重要的思想(在我看来,你的可能有所不同): -复习一下,这些是我认为此合约中最重要的概念(你们的看法可能与我不同) +- _区块链上没有秘密_。 智能合约可以访问的任何信息 + 都对全世界可见。 +- 你可以控制自己交易的顺序,但不能控制其他人交易发生的时间。 这就是为什么更改授权额度可能很危险,因为它让 + 花费者可以花费两个授权额度的总和。 +- `uint256` 类型的值会环绕。 换言之,_0-1=2^256-1_。 如果这不是期望的 + 行为,你必须检查它(或使用为你执行此操作的 SafeMath 库)。 请注意,这在 + [Solidity 0.8.0](https://docs.soliditylang.org/en/breaking/080-breaking-changes.html) 中已更改。 +- 在特定位置执行特定类型的所有状态更改,因为这使审计更容易。 + 这就是为什么我们有 `_approve`,它由 `approve`、`transferFrom`、 + `increaseAllowance` 和 `decreaseAllowance` 调用 +- 状态更改应是原子性的,中间没有任何其他操作(如你在 `_transfer` 中看到的 + )。 这是因为在状态更改期间,你处于不一致的状态。 例如, + 在你从发送者的余额中扣除和添加到接收者的余额之间的 + 时间里,存在的代币比应有的要少。 如果它们之间 + 有操作,特别是调用另一个合约,这可能会被滥用。 -- _区块链上没有秘密_ 智能合约可以访问的任何信息 都可以提供给全世界。 -- 你可以控制自己交易的订单,但在其他人的交易发生时, 则不能控制。 这就是为什么更改许可额度时会有风险,因为它 允许消费者花掉这两个许可额度的总和。 -- `uint256` 类型值的溢出。 换言之,_0-1=2^256-1_。 如果这不是预期的 行为,你必须自行检查(或使用 SafeMath 库执行该服务)。 请注意, [Solidity 0.8.0](https://docs.soliditylang.org/en/breaking/080-breaking-changes.html) 中对此进行了更改。 -- 将特定类型变量的状态改变放在一个特定的地方,这样可以使审核更容易。 这就是我们使用以下等函数的原因,例如 `_approve` 函数,它可以被`approve`、`transferFrom`、 `increaseAllowance` 和 `decreaseAllowance` 调用。 -- 状态更改应为最小操作单元,其中没有任何其他动作 (如在 `_transfer` 中所见)。 这是因为在状态更改期间,会出现不一致的情况。 例如, 在减少发送人的余额,和增加接收人的余额之间, 代币总量会小于应有总量。 如果在这两个时刻之间有任何操作, 特别是调用不同的合约,则可能出现滥用。 +现在你已经了解了 OpenZeppelin ERC-20 合约是如何编写的, +尤其是如何使其更加安全,你可以去编写自己的安全合约和应用程序了。 -现在你已经了解了 OpenZeppelin ERC-20 合约是怎么编写的, 尤其是如何使之更加安全,你即可编写自己的安全合约和应用程序。 +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 diff --git a/public/content/translations/zh/developers/tutorials/erc20-with-safety-rails/index.md b/public/content/translations/zh/developers/tutorials/erc20-with-safety-rails/index.md index 435ec89c661..8ab3075da73 100644 --- a/public/content/translations/zh/developers/tutorials/erc20-with-safety-rails/index.md +++ b/public/content/translations/zh/developers/tutorials/erc20-with-safety-rails/index.md @@ -1,62 +1,64 @@ --- -title: ERC-20 安全保障 -description: 如何帮助人们避免犯下低级错误 +title: "带安全保障的 ERC-20" +description: "如何帮助人们避免犯下低级错误" author: Ori Pomerantz lang: zh -tags: - - "erc-20" +tags: [ "erc-20" ] skill: beginner published: 2022-08-15 --- ## 简介 {#introduction} -以太坊的厉害之处之一在于不存在可以修改或取消你的交易的中心化组织。 但同时,以太坊也面临许多困难,其中之一便是没有任何中心化组织有权力消除用户错误或非法交易。 在这篇文章中,你将了解以太坊用户在使用 [ERC-20](/developers/docs/standards/tokens/erc-20/) 代币时犯下的一些常见错误以及如何创建 ERC-20 合约来帮助用户避免犯这些错误,或者赋予中心化组织某些权力(例如冻结帐户的权力)。 +以太坊的优点之一在于,没有任何中心化机构可以修改或撤销你的交易。 以太坊的一大问题也正在于此:没有任何中心化机构有权撤销用户错误或非法交易。 在本文中,你将了解用户在使用 [ERC-20](/developers/docs/standards/tokens/erc-20/) 代币时常犯的一些错误,以及如何创建 ERC-20 合约来帮助用户避免这些错误,或赋予中心化机构某些权力(例如冻结帐户)。 -请注意:虽然我们将使用 [OpenZeppelin ERC-20 代币合约](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20),本文未对此进行详细阐述。 你可以在[这里](/developers/tutorials/erc20-annotated-code)找到此信息。 +请注意,虽然我们将使用 [OpenZeppelin ERC-20 代币合约](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20),但本文不会对其进行详细解释。 你可以在[此处](/developers/tutorials/erc20-annotated-code)找到此信息。 -如果你想要查看完整的源代码: +如果你想查看完整的源代码: -1. 请打开 [Remix IDE](https://remix.ethereum.org/)。 -2. 点击克隆 github 图标 (![clone github icon](icon-clone.png))。 -3. 克隆 github 存储库 `https://github.com/qbzzt/20220815-erc20-safety-rails`。 -4. 打开**合约 > erc20-safety-rails.sol**。 +1. 打开 [Remix IDE](https://remix.ethereum.org/)。 +2. 点击克隆 GitHub 图标(![克隆 github 图标](icon-clone.png))。 +3. 克隆 GitHub 仓库 `https://github.com/qbzzt/20220815-erc20-safety-rails`。 +4. 打开 **contracts > erc20-safety-rails.sol**。 ## 创建 ERC-20 合约 {#creating-an-erc-20-contract} -在添加安全保障功能之前,我们首先需要 ERC-20 合约。 在这篇文章中,我们将使用 [the OpenZeppelin 合约向导](https://docs.openzeppelin.com/contracts/5.x/wizard)。 在另一个浏览器中将其打开,然后遵循以下说明: +在添加安全保障功能之前,我们首先需要 ERC-20 合约。 在本文中,我们将使用 [OpenZeppelin 合约向导](https://docs.openzeppelin.com/contracts/5.x/wizard)。 在另一个浏览器中将其打开,然后遵循以下说明: + +1. 选择 **ERC20**。 -1. 选择 **ERC-20**。 2. 请输入以下设置: - | 参数 | 值 | - | -------------- | ---------------- | - | 姓名 | SafetyRailsToken | - | Symbol | SAFE | - | Premint | 1000 | - | 特性 | 无 | - | Access Control | Ownable | - | Upgradability | 无 | + | 参数 | Value | + | ---- | ---------------- | + | 名称 | SafetyRailsToken | + | 符号 | SAFE | + | 预铸 | 1000 | + | 功能 | 无 | + | 访问控制 | Ownable | + | 可升级性 | 无 | + +3. 向上滚动并点击 **Open in Remix**(适用于 Remix)或 **Download** 以使用不同的环境。 我将假设你正在使用 Remix,如果你使用其他工具,请做相应更改。 -3. 向上滚动并点击 **Open in Remix**(适用于 Remix)或点击 **Download** 以使用另一个环境。 假设你正在使用 Remix,如果你想使用其他环境,只需要做些适当调整即可。 -4. 我们现在已经拥有一份功能齐全的 ERC-20 合约。 你可以展开 `.deps`>`npm` 查看导入的代码。 -5. 编译、部署并使用该合约,确认其作为 ERC-20 合约能否正常发挥作用。 如果你需要学习如何使用 Remix,请[使用本教程](https://remix.ethereum.org/?#activate=udapp,solidity,LearnEth)。 +4. 我们现在已经拥有一份功能齐全的 ERC-20 合约。 你可以展开 `.deps` > `npm` 查看导入的代码。 + +5. 编译、部署并试用该合约,看看它是否能作为 ERC-20 合约正常运行。 如果你需要学习如何使用 Remix,请[参阅此教程](https://remix.ethereum.org/?#activate=udapp,solidity,LearnEth)。 ## 常见错误 {#common-mistakes} -### 错误 {#the-mistakes} +### 这些错误 {#the-mistakes} -用户有时会向错误的地址发送代币。 尽管有时我们很难理解他们这么做的目的,但有两种错误类型经常发生且很容易检测到: +用户有时会向错误的地址发送代币。 虽然我们无法读懂他们的心思,不知道他们想做什么,但有两种经常发生且易于检测的错误类型: -1. 给合约自己的地址发送代币。 例如,[Optimism 的 OP 代币](https://optimism.mirror.xyz/qvd0WfuLKnePm1Gxb9dpGchPf5uDz5NSMEFdgirDS4c)在不到 2 个月的时间内累计[超过 120,000个](https://optimistic.etherscan.io/address/0x4200000000000000000000000000000000000042#tokentxns)。 这代表着人们可能刚刚失去的大量财富。 +1. 将代币发送到合约自己的地址。 例如,[Optimism 的 OP 代币](https://optimism.mirror.xyz/qvd0WfuLKnePm1Gxb9dpGchPf5uDz5NSMEFdgirDS4c)在不到两个月的时间里累积了[超过 120,000](https://optimism.blockscout.com/address/0x4200000000000000000000000000000000000042) 个 OP 代币。 这代表着一笔巨额财富,而人们很可能就这样白白损失了。 -2. 将代币发送到一个空地址,该地址并不对应一个[外部帐户](/developers/docs/accounts/#externally-owned-accounts-and-key-pairs)或者一份[智能合约](/developers/docs/smart-contracts)。 尽管我没有关于这类情况发生频率的统计资料,但[这种事件发生一次,就能让用户损失 20,000,000 代币](https://gov.optimism.io/t/message-to-optimism-community-from-wintermute/2595)。 +2. 将代币发送到空地址,即不对应[外部帐户](/developers/docs/accounts/#externally-owned-accounts-and-key-pairs)或[智能合约](/developers/docs/smart-contracts)的地址。 虽然我没有关于这种情况发生频率的统计数据,但有[一次事件可能造成了 20,000,000 代币的损失](https://gov.optimism.io/t/message-to-optimism-community-from-wintermute/2595)。 -### 防止转账 {#preventing-transfers} +### 阻止转账 {#preventing-transfers} -Open Zeppelin ERC-20 合约包含[一个钩子(`_beforeTokenTransfer`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L364-L368)),在转账代币之前会调用此钩子。 默认情况下,这个钩子不会发生任何作用,但是我们可以在钩子上挂起自己的功能,例如在出现问题时进行回滚的检查。 +OpenZeppelin ERC-20 合约包含一个[钩子 `_beforeTokenTransfer`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L364-L368),它在代币转账前被调用。 默认情况下,这个钩子不执行任何操作,但我们可以在其上挂载自己的功能,例如在出现问题时进行回滚检查。 -若要使用此钩子,请在构造函数后面添加此函数: +要使用这个钩子,请在构造函数后添加以下函数: ```solidity function _beforeTokenTransfer(address from, address to, uint256 amount) @@ -67,42 +69,42 @@ Open Zeppelin ERC-20 合约包含[一个钩子(`_beforeTokenTransfer`](https:/ } ``` -如果你不熟悉 Solidity,你可能对此函数的某些部分感到陌生。 +如果你不太熟悉 Solidity,此函数的某些部分对你来说可能比较陌生: ```solidity internal virtual ``` -`virtual` 关键字表明,正如我们可以从 `ERC-20` 继承函数并重写此函数一样,其他合约也可以从我们这里继承函数并重写此函数。 +`virtual` 关键字表示,就像我们从 `ERC20` 继承功能并重写此函数一样,其他合约也可以从我们这里继承并重写此函数。 ```solidity override(ERC20) ``` -我们必须明确指定我们正在[重写](https://docs.soliditylang.org/en/v0.8.15/contracts.html#function-overriding) `_beforeTokenTransfer` 的 ERC20 代币定义。 一般来说,从安全的角度来看,显式定义比隐式定义要好得多—如果你做过的事就在眼前,你就不会忘记你已经做了这件事。 这也是我们需要指定重写哪个超类的 `_beforeTokenTransfer` 的原因。 +我们必须明确指定我们正在[重写](https://docs.soliditylang.org/en/v0.8.15/contracts.html#function-overriding) `_beforeTokenTransfer` 的 ERC20 代币定义。 通常,从安全角度来看,显式定义比隐式定义要好得多——如果做过的事情就在眼前,你就不会忘记。 这也是我们需要指定正在重写哪个超类的 `_beforeTokenTransfer` 的原因。 ```solidity super._beforeTokenTransfer(from, to, amount); ``` -这一行调用我们从其中继承函数的合约的 `_beforeTokenTransfer` 函数。 在这种情况下,只有 `ERC20` 和 `Ownable` 没有这个钩子。 尽管目前 `ERC20._beforeTokenTransfer` 没有执行任何操作,但我们还是会调用它,以防将来添加功能(然后我们决定重新部署合约,因为合约在部署后不会改变)。 +这行代码调用我们所继承的、且包含此函数的合约的 `_beforeTokenTransfer` 函数。 在本例中,只有 `ERC20` 有这个钩子,`Ownable` 没有。 尽管目前 `ERC20._beforeTokenTransfer` 不执行任何操作,但我们仍然调用它,以防将来添加新功能(然后我们决定重新部署合约,因为合约在部署后无法更改)。 -### 对要求进行编码 {#coding-the-requirements} +### 将要求编写为代码 {#coding-the-requirements} -我们希望在函数中添加以下要求: +我们想向函数中添加这些要求: - `to` 地址不能等于 `address(this)`,即 ERC-20 合约本身的地址。 -- `to` 地址不能为空,必须为以下任一地址: - - 外部帐户 (EOA)。 我们无法直接检查地址是否为外部帐户,但可以检查地址的以太币余额。 外部帐户几乎总是有余额的,即使不再使用也是如此—余额很难降至最后一 Wei。 - - 智能合约。 测试一个地址是否是智能合约要难一些。 有一个检查外部代码长度的操作码,被称为 [`EXTCODESIZE`](https://www.evm.codes/#3b),但它不能直接在 Solidity 中使用。 为此,我们必须使用以太坊虚拟机汇编语言 [Yul](https://docs.soliditylang.org/en/v0.8.15/yul.html)。 我们还可以使用 Solidity 的其他值([`
.code` 和 `
.codehash`](https://docs.soliditylang.org/en/v0.8.15/units-and-global-variables.html#members-of-address-types)),但开销更大。 +- `to` 地址不能为空,它必须是以下之一: + - 一个外部帐户 (EOA)。 我们无法直接检查一个地址是否为 EOA,但可以检查该地址的 ETH 余额。 EOA 几乎总是有余额,即使不再使用也是如此——很难将余额清零到最后一个 wei。 + - 一个智能合约。 测试一个地址是否为智能合约要更难一些。 有一个检查外部代码长度的操作码,名为 [`EXTCODESIZE`](https://www.evm.codes/#3b),但它不能直接在 Solidity 中使用。 我们必须为此使用 [Yul](https://docs.soliditylang.org/en/v0.8.15/yul.html),它是一种 EVM 汇编语言。 我们也可以使用 Solidity 中的其他值([`
.code` 和 `
.codehash`](https://docs.soliditylang.org/en/v0.8.15/units-and-global-variables.html#members-of-address-types)),但它们成本更高。 -让我们逐行查看新代码: +我们来逐行查看新代码: ```solidity - require(to != address(this), "Can't send tokens to the contract address"); + require(to != address(this), "不能将代币发送到合约地址"); ``` -这是第一个要求,即检查确保 `to` 和 `this(address)` 不同。 +这是第一个要求,检查 `to` 和 `this(address)` 是否不相同。 ```solidity bool isToContract; @@ -111,48 +113,48 @@ Open Zeppelin ERC-20 合约包含[一个钩子(`_beforeTokenTransfer`](https:/ } ``` -这就是我们检查地址是否为合约的方法。 我们无法直接从 Yul 接收输出,因此我们定义了一个变量来保留结果(本例中为 `isToContract`)。 Yul 的工作方式是将每个操作码都视为一个函数。 因此我们首先调用 [`EXTCODESIZE`](https://www.evm.codes/#3b) 来获取合约大小,然后使用 [`GT`](https://www.evm.codes/#11) 来检查它是否为零(我们处理的是无符号整数,所以它当然不能为负)。 然后,我们将结果写入 `isToContract` 中。 +我们通过这种方式检查一个地址是否为合约。 我们无法直接从 Yul 接收输出,因此我们定义了一个变量来保存结果(在本例中为 `isToContract`)。 Yul 的工作方式是,每个操作码都被视为一个函数。 所以我们首先调用 [`EXTCODESIZE`](https://www.evm.codes/#3b) 来获取合约大小,然后使用 [`GT`](https://www.evm.codes/#11) 来检查它是否不为零(我们处理的是无符号整数,所以它当然不可能是负数)。 然后我们将结果写入 `isToContract`。 ```solidity - require(to.balance != 0 || isToContract, "Can't send tokens to an empty address"); + require(to.balance != 0 || isToContract, "不能将代币发送到空地址"); ``` -最后,我们还要实际检查地址是否为空。 +最后,我们进行空地址的实际检查。 -## 管理访问 {#admin-access} +## 管理访问权限 {#admin-access} -有时,拥有可以撤消错误的管理员是很有用的。 为了减少滥用的可能性,该管理员可以是[多重签名](https://blog.logrocket.com/security-choices-multi-signature-wallets/),因此必须有多人同意才能进行操作。 本文将介绍两种管理功能: +有时候,有一个可以撤销错误的管理员是很有用的。 为了减少潜在的滥用,这个管理员可以是一个[多签](https://blog.logrocket.com/security-choices-multi-signature-wallets/),这样就需要多个人同意才能执行一项操作。 本文将介绍两种管理功能: -1. 冻结和解冻帐户。 例如,当帐户可能被泄露时,这就很有用。 +1. 冻结和解冻帐户。 例如,当帐户可能被盗用时,这就很有用。 2. 资产清理。 - 有时,欺诈者会将欺诈性代币发送到真实代币的合约中以获得合法性。 例如,[参见此处](https://optimistic.etherscan.io/token/0x2348b1a1228ddcd2db668c3d30207c3e1852fbbe?a=0x4200000000000000000000000000000000000042)。 合法的 ERC-20 合约是 [0x4200....0042](https://optimistic.etherscan.io/address/0x4200000000000000000000000000000000000042)。 冒充它的合约是 [0x234....bbe](https://optimistic.etherscan.io/address/0x2348b1a1228ddcd2db668c3d30207c3e1852fbbe)。 + 有时,诈骗者会向真实代币的合约发送诈骗代币,以使其看起来合法。 例如,[请看这里](https://optimism.blockscout.com/token/0x2348B1a1228DDCd2dB668c3d30207c3E1852fBbe?tab=holders)。 合法的 ERC-20 合约是 [0x4200....0042](https://optimism.blockscout.com/token/0x4200000000000000000000000000000000000042)。 冒充它的诈骗合约是 [0x234....bbe](https://optimism.blockscout.com/token/0x2348B1a1228DDCd2dB668c3d30207c3E1852fBbe)。 也有可能有人误将合法的 ERC-20 代币发送到我们的合约中,这也是我们希望有办法将这些代币取出的另一个原因。 -OpenZeppelin 提供两种机制来实现管理访问: +OpenZeppelin 提供了两种机制来实现管理访问: -- [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/access-control#ownership-and-ownable) 合约只有一个所有者。 具有 `onlyOwner`[ 修改器](https://www.tutorialspoint.com/solidity/solidity_function_modifiers.htm)的函数只能由该所有者调用。 所有者可以将所有权转让给其他人或完全放弃。 所有其他帐户的权利通常是相同的。 +- [`Ownable`](https://docs.openzeppelin.com/contracts/5.x/access-control#ownership-and-ownable) 合约只有一个所有者。 带有 `onlyOwner` [修饰符](https://www.tutorialspoint.com/solidity/solidity_function_modifiers.htm)的函数只能由该所有者调用。 所有者可以将所有权转让给其他人或完全放弃所有权。 所有其他帐户的权利通常是相同的。 - [`AccessControl`](https://docs.openzeppelin.com/contracts/5.x/access-control#role-based-access-control) 合约具有[基于角色的访问控制 (RBAC)](https://en.wikipedia.org/wiki/Role-based_access_control)。 -为简单起见,本文将使用 `Ownable`。 +为简单起见,本文使用 `Ownable`。 ### 冻结和解冻合约 {#freezing-and-thawing-contracts} -冻结和解冻合约需要几处更改: +冻结和解冻合约需要进行几项更改: -- 从地址到[布尔值](https://en.wikipedia.org/wiki/Boolean_data_type)的[映射](https://www.tutorialspoint.com/solidity/solidity_mappings.htm)来追踪哪些地址被冻结。 所有值的初始值都是 0,对于布尔值来说,它被解释为“false”。 这正是我们想要的,因为默认情况下帐户不会被冻结。 +- 一个从地址到[布尔值](https://en.wikipedia.org/wiki/Boolean_data_type)的[映射](https://www.tutorialspoint.com/solidity/solidity_mappings.htm),用于跟踪哪些地址被冻结。 所有值的初始值都为零,对于布尔值,这被解释为 false。 这正是我们想要的,因为默认情况下帐户不会被冻结。 ```solidity mapping(address => bool) public frozenAccounts; ``` -- 当帐户被冻结或解冻时,用于通知相关人员的[事件](https://www.tutorialspoint.com/solidity/solidity_events.htm)。 从技术上讲,这些操作并不需要事件,但它有助于链下代码能够监听这些事件并了解正在发生的情况。 当发生与他人相关的事情时,智能合约能够发出这些信息,这被认为是一种很好的方式。 +- 使用[事件](https://www.tutorialspoint.com/solidity/solidity_events.htm)来通知所有相关方帐户被冻结或解冻。 从技术上讲,这些操作并不需要事件,但它有助于链下代码能够侦听这些事件并了解正在发生的情况。 当发生可能与其他人相关的事情时,智能合约发出事件被认为是一种良好实践。 - 这些事件都有索引,因此可以搜索帐户被冻结或解冻的所有时间。 + 这些事件已编入索引,因此可以搜索某个帐户所有被冻结或解冻的时间。 ```solidity - // When accounts are frozen or unfrozen + // 当帐户被冻结或解冻时 event AccountFrozen(address indexed _addr); event AccountThawed(address indexed _addr); ``` @@ -165,27 +167,27 @@ OpenZeppelin 提供两种机制来实现管理访问: onlyOwner ``` - 标记为 [`public`](https://www.tutorialspoint.com/solidity/solidity_contracts.htm) 的函数可由其他智能合约调用,也可由交易直接调用。 + 标记为 [`public`](https://www.tutorialspoint.com/solidity/solidity_contracts.htm) 的函数可以从其他智能合约调用,也可以通过交易直接调用。 ```solidity { - require(!frozenAccounts[addr], "Account already frozen"); + require(!frozenAccounts[addr], "帐户已被冻结"); frozenAccounts[addr] = true; emit AccountFrozen(addr); } // freezeAccount ``` - 如果帐户已被冻结,则会回滚。 否则,冻结帐户并 `emit` 一个事件。 + 如果帐户已被冻结,则回滚。 否则,冻结它并 `emit` 一个事件。 - 更改 `_beforeTokenTransfer` 以防止资金从冻结帐户中转出。 请注意,资金仍可转入冻结帐户。 ```solidity - require(!frozenAccounts[from], "The account is frozen"); + require(!frozenAccounts[from], "该帐户已被冻结"); ``` ### 资产清理 {#asset-cleanup} -要释放此合约持有的 ERC-20 代币,我们需要调用它们所属代币合约上的函数,即 [ `transfer`](https://eips.ethereum.org/EIPS/eip-20#transfer) 或 [`approve`](https://eips.ethereum.org/EIPS/eip-20#approve)。 在这种情况下,没有必要将燃料浪费在许可额度上,我们也可以直接转账。 +要释放此合约持有的 ERC-20 代币,我们需要在该代币所属的代币合约上调用一个函数,即 [`transfer`](https://eips.ethereum.org/EIPS/eip-20#transfer) 或 [`approve`](https://eips.ethereum.org/EIPS/eip-20#approve)。 在这种情况下,没有必要将燃料浪费在许可额度上,我们不如直接转账。 ```solidity function cleanupERC20( @@ -198,7 +200,7 @@ OpenZeppelin 提供两种机制来实现管理访问: IERC20 token = IERC20(erc20); ``` -这是我们收到地址时为合约创建对象的语法。 我们可以做到这一点,是因为我们将 ERC20 代币的定义作为源代码的一部分(见第 4 行),该文件包括 [IERC20](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol) 的定义,即 OpenZeppelin ERC-20 合约的接口。 +这是我们在收到地址时为合约创建对象的语法。 我们可以这样做,因为我们的源代码中包含了 ERC20 代币的定义(见第 4 行),并且该文件包含了 [IERC20 的定义](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol),即 OpenZeppelin ERC-20 合约的接口。 ```solidity uint balance = token.balanceOf(address(this)); @@ -206,8 +208,10 @@ OpenZeppelin 提供两种机制来实现管理访问: } ``` -这是一个清理函数,所以我们可能不想留下任何代币。 与其手动从用户那里获取余额,我们不如将这一过程自动化。 +这是一个清理函数,所以我们大概不希望留下任何代币。 与其让用户手动获取余额,我们不如将这个过程自动化。 ## 结论 {#conclusion} -这并不是一个完美的解决方案—“用户犯错误”的问题没有完美的解决方案。 不过,使用这类检查至少可以避免一些错误。 冻结帐户的功能虽然危险,但可以通过阻止黑客窃取资金来限制某些黑客攻击的危害。 +这不是一个完美的解决方案——“用户犯错”问题没有完美的解决方案。 不过,使用这类检查至少可以避免一些错误。 冻结帐户的功能虽然危险,但可以通过拒绝黑客获得被盗资金来限制某些黑客攻击造成的损害。 + +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 diff --git a/public/content/translations/zh/developers/tutorials/ethereum-for-web2-auth/index.md b/public/content/translations/zh/developers/tutorials/ethereum-for-web2-auth/index.md new file mode 100644 index 00000000000..0968f82f1eb --- /dev/null +++ b/public/content/translations/zh/developers/tutorials/ethereum-for-web2-auth/index.md @@ -0,0 +1,886 @@ +--- +title: "使用以太坊进行 web2 身份验证" +description: "阅读本教程后,开发者将能够把以太坊登录 (web3) 与 SAML 登录集成。SAML 是 web2 中用于提供单点登录和其他相关服务的标准。 这允许通过以太坊签名对访问 web2 资源的请求进行身份验证,用户属性则来自认证。" +author: Ori Pomerantz +tags: [ "web2", "认证", "eas" ] +skill: beginner +lang: zh +published: 2025-04-30 +--- + +## 简介 + +[SAML](https://www.onelogin.com/learn/saml) 是 web2 中使用的一种标准,允许[身份提供者 (IdP)](https://en.wikipedia.org/wiki/Identity_provider#SAML_identity_provider) 为[服务提供者 (SP)](https://en.wikipedia.org/wiki/Service_provider_\(SAML\)) 提供用户信息。 + +在本教程中,您将学习如何将以太坊签名与 SAML 集成,以允许用户使用其以太坊钱包向尚不支持原生以太坊的 web2 服务进行身份验证。 + +请注意,本教程面向两类不同的受众: + +- 了解以太坊并需要学习 SAML 的以太坊人士 +- 了解 SAML 和 web2 身份验证并需要学习以太坊的 Web2 人士 + +因此,本教程会包含许多您已了解的介绍性材料。 您可以随意跳过。 + +### 面向以太坊人士的 SAML + +SAML 是一种中心化协议。 服务提供者 (SP) 仅在与身份提供者 (IdP) 或签署 IdP 证书的[证书颁发机构](https://www.ssl.com/article/what-is-a-certificate-authority-ca/)存在预先信任关系时,才会接受来自 IdP 的断言(例如“这是我的用户 John,他应有权执行 A、B 和 C”)。 + +例如,SP 可以是为公司提供差旅服务的旅行社,而 IdP 可以是公司的内部网站。 当员工需要预订商务差旅时,旅行社会先将他们发送至公司进行身份验证,然后才允许他们实际预订差旅。 + +![SAML 流程分步说明](./fig-01-saml.png) + +这就是浏览器、SP 和 IdP 这三个实体协商访问权限的方式。 SP 无需提前了解任何有关使用浏览器的用户的信息,只需信任 IdP 即可。 + +### 面向 SAML 人士的以太坊 + +以太坊是一个去中心化系统。 + +![以太坊登录](./fig-02-eth-logon.png) + +用户拥有私钥(通常保存在浏览器扩展程序中)。 您可以从私钥派生出公钥,再从公钥派生出 20 字节的地址。 当用户需要登录系统时,系统会要求他们使用随机数(一次性值)签署一条信息。 服务器可以验证签名是由该地址创建的。 + +![从认证中获取额外数据](./fig-03-eas-data.png) + +签名仅验证以太坊地址。 要获取其他用户属性,您通常会使用[认证](https://attest.org/)。 一份认证通常包含以下字段: + +- **认证者**,进行认证的地址 +- **接收者**,认证适用的地址 +- **数据**,被认证的数据,例如姓名、权限等。 +- **模式**,用于解释数据的模式 ID。 + +由于以太坊的去中心化特性,任何用户都可以创建认证。 认证者的身份对于确定哪些认证是可靠的至关重要。 + +## 设置 + +第一步是让 SAML SP 和 SAML IdP 能够相互通信。 + +1. 下载软件。 本文的示例软件[在 Github 上](https://github.com/qbzzt/250420-saml-ethereum)。 不同阶段存储在不同分支中,此阶段您需要 `saml-only` + + ```sh + git clone https://github.com/qbzzt/250420-saml-ethereum -b saml-only + cd 250420-saml-ethereum + pnpm install + ``` + +2. 使用自签名证书创建密钥。 这意味着该密钥本身就是其证书颁发机构,需要手动将其导入服务提供者。 有关详细信息,请参阅 [OpenSSL 文档](https://docs.openssl.org/master/man1/openssl-req/)。 + + ```sh + mkdir keys + cd keys + openssl req -new -x509 -days 365 -nodes -sha256 -out saml-sp.crt -keyout saml-sp.pem -subj /CN=sp/ + openssl req -new -x509 -days 365 -nodes -sha256 -out saml-idp.crt -keyout saml-idp.pem -subj /CN=idp/ + cd .. + ``` + +3. 启动服务器(SP 和 IdP) + + ```sh + pnpm start + ``` + +4. 浏览到 SP 的 URL [http://localhost:3000/](http://localhost:3000/),然后单击按钮重定向到 IdP(端口 3001)。 + +5. 向 IdP 提供您的电子邮件地址,然后单击**登录服务提供者**。 您会看到您被重定向回服务提供者(端口 3000),并且它通过您的电子邮件地址识别了您。 + +### 详细说明 + +以下是分步说明: + +![没有以太坊的常规 SAML 登录](./fig-04-saml-no-eth.png) + +#### src/config.mts + +此文件包含身份提供者和服务提供者的配置。 通常这两者是不同的实体,但为了简单起见,我们可以在这里共享代码。 + +```typescript +const fs = await import("fs") + +const protocol="http" +``` + +我们目前只是在测试,所以使用 HTTP 没问题。 + +```typescript +export const spCert = fs.readFileSync("keys/saml-sp.crt").toString() +export const idpCert = fs.readFileSync("keys/saml-idp.crt").toString() +``` + +读取公钥,公钥通常对两个组件都可用(可以直接信任,也可以由受信任的证书颁发机构签名)。 + +```typescript +export const spPort = 3000 +export const spHostname = "localhost" +export const spDir = "sp" + +export const idpPort = 3001 +export const idpHostname = "localhost" +export const idpDir = "idp" + +export const spUrl = `${protocol}://${spHostname}:${spPort}/${spDir}` +export const idpUrl = `${protocol}://${idpHostname}:${idpPort}/${idpDir}` +``` + +两个组件的 URL。 + +```typescript +export const spPublicData = { +``` + +服务提供者的公开数据。 + +```typescript + entityID: `${spUrl}/metadata`, +``` + +按照惯例,在 SAML 中,`entityID` 是实体的元数据所在的 URL。 此元数据对应于此处的公共数据,但其格式为 XML。 + +```typescript + wantAssertionsSigned: true, + authnRequestsSigned: false, + signingCert: spCert, + allowCreate: true, + assertionConsumerService: [{ + Binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', + Location: `${spUrl}/assertion`, + }] + } +``` + +对我们来说,最重要的定义是 `assertionConsumerServer`。 它意味着,要向服务提供者断言某事(例如,“向您发送此信息的用户是 somebody@example.com”),我们需要使用 [HTTP POST](https://www.w3schools.com/tags/ref_httpmethods.asp) 到 URL `http://localhost:3000/sp/assertion`。 + +```typescript +export const idpPublicData = { + entityID: `${idpUrl}/metadata`, + signingCert: idpCert, + wantAuthnRequestsSigned: false, + singleSignOnService: [{ + Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", + Location: `${idpUrl}/login` + }], + singleLogoutService: [{ + Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", + Location: `${idpUrl}/logout` + }], + } +``` + +身份提供者的公共数据是类似的。 它指定要登录用户,您需要 POST 到 `http://localhost:3001/idp/login`,要注销用户,则 POST 到 `http://localhost:3001/idp/logout`。 + +#### src/sp.mts + +这是实现服务提供者的代码。 + +```typescript +import * as config from "./config.mts" +const fs = await import("fs") +const saml = await import("samlify") +``` + +我们使用 [`samlify`](https://www.npmjs.com/package/samlify) 程序库来实现 SAML。 + +```typescript +import * as validator from "@authenio/samlify-node-xmllint" +saml.setSchemaValidator(validator) +``` + +`samlify` 程序库需要一个包来验证 XML 是否正确、是否使用预期的公钥签名等。 为此,我们使用 [`@authenio/samlify-node-xmllint`](https://www.npmjs.com/package/@authenio/samlify-node-xmllint)。 + +```typescript +const express = (await import("express")).default +const spRouter = express.Router() +const app = express() +``` + +`express`](https://expressjs.com/) [`Router`](https://expressjs.com/en/5x/api.html#router) 是一个可以挂载在网站内部的“迷你网站”。 在本例中,我们用它将所有服务提供者的定义组合在一起。 + +```typescript +const spPrivateKey = fs.readFileSync("keys/saml-sp.pem").toString() + +const sp = saml.ServiceProvider({ + privateKey: spPrivateKey, + ...config.spPublicData +}) +``` + +服务提供者自身的表示是所有的公共数据以及用于签署信息的私钥。 + +```typescript +const idp = saml.IdentityProvider(config.idpPublicData); +``` + +公共数据包含服务提供者需要了解的关于身份提供者的一切信息。 + +```typescript +spRouter.get(`/metadata`, + (req, res) => res.header("Content-Type", "text/xml").send(sp.getMetadata()) +) +``` + +为了实现与其他 SAML 组件的互操作性,服务和身份提供者应在 `/metadata` 中以 XML 格式提供其公共数据(称为元数据)。 + +```typescript +spRouter.post(`/assertion`, +``` + +这是浏览器用来标识自己的页面。 断言包括用户标识符(此处我们使用电子邮件地址),并且可以包括其他属性。 这是上述序列图中步骤 7 的处理程序。 + +```typescript + async (req, res) => { + // console.log(`SAML 响应:\n${Buffer.from(req.body.SAMLResponse, 'base64').toString('utf-8')}`) +``` + +您可以使用注释掉的命令来查看断言中提供的 XML 数据。 它经过 [base64 编码](https://en.wikipedia.org/wiki/Base64)。 + +```typescript + try { + const loginResponse = await sp.parseLoginResponse(idp, 'post', req); +``` + +解析来自身份服务器的登录请求。 + +```typescript + res.send(` + + +

你好 ${loginResponse.extract.nameID}

+ + + `) + res.send(); +``` + +发送 HTML 响应,只是为了向用户显示我们已成功登录。 + +```typescript + } catch (err) { + console.error('处理 SAML 响应时出错:', err); + res.status(400).send('SAML 身份验证失败'); + } + } +) +``` + +如果失败,通知用户。 + +```typescript +spRouter.get('/login', +``` + +当浏览器尝试获取此页面时,创建一个登录请求。 这是上述序列图中步骤 1 的处理程序。 + +```typescript + async (req, res) => { + const loginRequest = await sp.createLoginRequest(idp, "post") +``` + +获取信息以发布登录请求。 + +```typescript + res.send(` + + + +``` + +此页面会自动提交表单(见下文)。 这样,用户无需执行任何操作即可被重定向。 这是上述序列图中的步骤 2。 + +```typescript +
+``` + +POST 到 `loginRequest.entityEndpoint`(身份提供者端点的 URL)。 + +```typescript + +``` + +输入名称为 `loginRequest.type` (`SAMLRequest`)。 该字段的内容是 `loginRequest.context`,它也是经过 base64 编码的 XML。 + +```typescript +
+ + + `) + } +) + +app.use(express.urlencoded({extended: true})) +``` + +[此中间件](https://expressjs.com/en/5x/api.html#express.urlencoded) 读取 [HTTP 请求](https://www.tutorialspoint.com/http/http_requests.htm)的正文。 默认情况下,express 会忽略它,因为大多数请求都不需要它。 我们需要它,因为 POST 会使用正文。 + +```typescript +app.use(`/${config.spDir}`, spRouter) +``` + +将路由器挂载在服务提供者目录 (`/sp`) 中。 + +```typescript +app.get("/", (req, res) => { + res.send(` + + + + + + `) +}) +``` + +如果浏览器尝试获取根目录,请为其提供一个指向登录页面的链接。 + +```typescript +app.listen(config.spPort, () => { + console.log(`服务提供者正在运行于 http://${config.spHostname}:${config.spPort}`) +}) +``` + +使用此 express 应用监听 `spPort`。 + +#### src/idp.mts + +这是身份提供者。 它与服务提供者非常相似,下面的解释针对的是不同的部分。 + +```typescript +const xmlParser = new (await import("fast-xml-parser")).XMLParser( + { + ignoreAttributes: false, // 保留属性 + attributeNamePrefix: "@_", // 属性前缀 + } +) +``` + +我们需要读取并理解从服务提供者收到的 XML 请求。 + +```typescript +const getLoginPage = requestId => ` +``` + +此函数创建带有自动提交表单的页面,该页面在上述序列图的步骤 4 中返回。 + +```typescript + + + 登录页面 + + +

登录页面

+
+ + 电子邮件地址: +
+ +``` + +我们发送给服务提供者两个字段: + +1. 我们正在响应的 `requestId`。 +2. 用户标识符(我们目前使用用户提供的电子邮件地址)。 + +```typescript +
+ + + +const idpRouter = express.Router() + +idpRouter.post("/loginSubmitted", async (req, res) => { + const loginResponse = await idp.createLoginResponse( +``` + +这是上述序列图中步骤 5 的处理程序。 [`idp.createLoginResponse`](https://github.com/tngan/samlify/blob/master/src/entity-idp.ts#L73-L125) 创建登录响应。 + +```typescript + sp, + { + authnContextClassRef: 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport', + audience: sp.entityID, +``` + +受众是服务提供者。 + +```typescript + extract: { + request: { + id: req.body.requestId + } + }, +``` + +从请求中提取的信息。 我们在请求中关心的唯一参数是 requestId,它让服务提供者能够匹配请求及其响应。 + +```typescript + signingKey: { privateKey: idpPrivateKey, publicKey: config.idpCert } // 确保签名 +``` + +我们需要 `signingKey` 来获取签署响应的数据。 服务提供者不信任未签名的请求。 + +```typescript + }, + "post", + { + email: req.body.email +``` + +这是我们发送回服务提供者的包含用户信息的字段。 + +```typescript + } + ); + + res.send(` + + + + +
+ +
+ + + `) +}) +``` + +同样,使用自动提交的表单。 这是上述序列图中的步骤 6。 + +```typescript + +// 用于登录请求的 IdP 端点 +idpRouter.post(`/login`, +``` + +这是接收来自服务提供者的登录请求的端点。 这是上述序列图中的步骤 3 的处理程序。 + +```typescript + async (req, res) => { + try { + // 权宜之计,因为我无法让 parseLoginRequest 工作。 + // const loginRequest = await idp.parseLoginRequest(sp, 'post', req) + const samlRequest = xmlParser.parse(Buffer.from(req.body.SAMLRequest, 'base64').toString('utf-8')) + res.send(getLoginPage(samlRequest["samlp:AuthnRequest"]["@_ID"])) +``` + +我们应该能够使用 [`idp.parseLoginRequest`](https://github.com/tngan/samlify/blob/master/src/entity-idp.ts#L127-L144) 来读取身份验证请求的 ID。 然而,我无法使其正常工作,也不值得花太多时间在这上面,所以我只是用了一个[通用的 XML 解析器](https://www.npmjs.com/package/fast-xml-parser)。 我们需要的信息是 `` 标签内的 `ID` 属性,它位于 XML 的顶层。 + +## 使用以太坊签名 + +既然我们能将用户身份发送到服务提供者,下一步就是以可信的方式获取用户身份。 Viem 允许我们直接向钱包请求用户地址,但这相当于向浏览器请求信息。 我们无法控制浏览器,所以我们不能自动信任从它那里得到的响应。 + +因此,IdP 将向浏览器发送一个字符串以供签名。 如果浏览器中的钱包签署了这个字符串,就意味着它确实是那个地址(也就是说,它知道与该地址对应的私钥)。 + +要看到此操作的实际效果,请停止现有的 IdP 和 SP,然后运行以下命令: + +```sh +git checkout eth-signatures +pnpm install +pnpm start +``` + +然后浏览[到 SP](http://localhost:3000) 并按照指示操作。 + +请注意,此时我们不知道如何从以太坊地址获取电子邮件地址,因此我们向 SP 报告 `@bad.email.address`。 + +### 详细说明 + +更改在前一个图中的步骤 4-5。 + +![带以太坊签名的 SAML](./fig-05-saml-w-signature.png) + +我们唯一更改的文件是 `idp.mts`。 以下是更改的部分。 + +```typescript +import { v4 as uuidv4 } from 'uuid' +import { verifyMessage } from 'viem' +``` + +我们需要这两个额外的程序库。 我们使用 [`uuid`](https://www.npmjs.com/package/uuid) 来创建[随机数](https://en.wikipedia.org/wiki/Cryptographic_nonce)值。 值本身不重要,重要的是它只使用一次。 + +[`viem`](https://viem.sh/) 程序库让我们能够使用以太坊定义。 这里我们需要它来验证签名是否确实有效。 + +```typescript +const loginPrompt = "要访问服务提供者,请签署此随机数:" +``` + +钱包会请求用户允许签署该信息。 只包含随机数的信息可能会让用户感到困惑,所以我们加入了这个提示。 + +```typescript +// 在此处保留 requestID +let nonces = {} +``` + +我们需要请求信息才能对其做出响应。 我们可以在请求时发送它(步骤 4),然后在响应时接收它(步骤 5)。 然而,我们不能信任从浏览器获得的信息,因为它可能受恶意用户的控制。 所以最好将其存储在这里,以随机数作为密钥。 + +请注意,为简单起见,我们在此将其作为变量。 然而,这有几个缺点: + +- 我们容易受到拒绝服务攻击。 恶意用户可以多次尝试登录,从而耗尽我们的内存。 +- 如果 IdP 进程需要重新启动,我们就会丢失现有的值。 +- 我们无法在多个进程之间进行负载均衡,因为每个进程都有自己的变量。 + +在生产系统上,我们会使用数据库并实现某种过期机制。 + +```typescript +const getSignaturePage = requestId => { + const nonce = uuidv4() + nonces[nonce] = requestId +``` + +创建一个随机数,并存储 `requestId` 以备将来使用。 + +```typescript + return ` + + + + + +

请签名

+ +
+ + + +` +} +``` + +其余的只是标准 HTML。 + +```typescript +idpRouter.get("/signature/:nonce/:account/:signature", async (req, res) => { +``` + +这是序列图中的步骤 5 的处理程序。 + +```typescript + const requestId = nonces[req.params.nonce] + if (requestId === undefined) { + res.send("错误的随机数") + return ; + } + + nonces[req.params.nonce] = undefined +``` + +获取请求 ID,并从 `nonces` 中删除该随机数以确保其不能被重用。 + +```typescript + try { +``` + +因为签名无效的方式有很多,所以我们将此包装在 `try ...` 中。 `catch` 区块以捕获任何抛出的错误。 + +```typescript + const validSignature = await verifyMessage({ + address: req.params.account, + message: `${loginPrompt}${req.params.nonce}`, + signature: req.params.signature + }) +``` + +使用 [`verifyMessage`](https://viem.sh/docs/actions/public/verifyMessage#verifymessage) 实现序列图中的步骤 5.5。 + +```typescript + if (!validSignature) + throw("签名无效") + } catch (err) { + res.send("错误:" + err) + return ; + } +``` + +处理程序的其余部分与我们之前在 `/loginSubmitted` 处理程序中所做的相同,只有一个小改动。 + +```typescript + const loginResponse = await idp.createLoginResponse( + . + . + . + { + email: req.params.account + "@bad.email.address" + } + ); +``` + +我们没有实际的电子邮件地址(我们将在下一节中获取),因此暂时返回以太坊地址,并明确标记它不是电子邮件地址。 + +```typescript +// 用于登录请求的 IdP 端点 +idpRouter.post(`/login`, + async (req, res) => { + try { + // 权宜之计,因为我无法让 parseLoginRequest 工作。 + // const loginRequest = await idp.parseLoginRequest(sp, 'post', req) + const samlRequest = xmlParser.parse(Buffer.from(req.body.SAMLRequest, 'base64').toString('utf-8')) + res.send(getSignaturePage(samlRequest["samlp:AuthnRequest"]["@_ID"])) + } catch (err) { + console.error('处理 SAML 响应时出错:', err); + res.status(400).send('SAML 身份验证失败'); + } + } +) +``` + +在步骤 3 的处理程序中,现在使用 `getSignaturePage` 代替 `getLoginPage`。 + +## 获取电子邮件地址 + +下一步是获取服务提供者请求的标识符,即电子邮件地址。 为此,我们使用[以太坊认证服务 (EAS)](https://attest.org/)。 + +获取认证的最简单方法是使用 [GraphQL 应用程序接口](https://docs.attest.org/docs/developer-tools/api)。 我们使用以下查询: + +``` +query GetAttestationsByRecipient { + attestations( + where: { + recipient: { equals: "${getAddress(ethAddr)}" } + schemaId: { equals: "0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977" } + } + take: 1 + ) { + data + id + attester + } +} +``` + +此 [`schemaId`](https://optimism.easscan.org/schema/view/0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977) 仅包含一个电子邮件地址。 此查询请求此模式的认证。 认证的主题称为 `recipient`。 它总是一个以太坊地址。 + +警告:我们在这里获取认证的方式存在两个安全问题。 + +- 我们访问的 API 端点 `https://optimism.easscan.org/graphql` 是一个中心化组件。 我们可以获取 `id` 属性,然后在链上进行查找以验证认证是否真实,但 API 端点仍然可以通过不告知我们某些认证来对其进行审查。 + + 这个问题并非无法解决,我们可以运行自己的 GraphQL 端点,并从链上日志中获取认证,但这对于我们的目的来说过于繁琐。 + +- 我们不查看认证者身份。 任何人都可以向我们提供虚假信息。 在实际实现中,我们会有一组受信任的认证者,并且只查看他们的认证。 + +要看到此操作的实际效果,请停止现有的 IdP 和 SP,然后运行以下命令: + +```sh +git checkout email-address +pnpm install +pnpm start +``` + +然后提供您的电子邮件地址。 您有两种方法可以做到这一点: + +- 使用私钥导入钱包,并使用测试私钥 `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80`。 + +- 为您的电子邮件地址添加认证: + + 1. 在认证浏览器中浏览到[该模式](https://optimism.easscan.org/schema/view/0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977)。 + + 2. 单击**用模式认证**。 + + 3. 输入您的以太坊地址作为接收者,您的电子邮件地址作为 email address,并选择**链上**。 然后单击**创建认证**。 + + 4. 在您的钱包中批准交易。 您需要在 [Optimism 区块链](https://app.optimism.io/bridge/deposit)上有一些 ETH 来支付燃料费。 + +无论哪种方式,完成后请浏览至 [http://localhost:3000](http://localhost:3000) 并按照指示操作。 如果您导入了测试私钥,您收到的电子邮件将是 `test_addr_0@example.com`。 如果您使用自己的地址,它应该是您认证的任何内容。 + +### 详细说明 + +![从以太坊地址到电子邮件的转换](./fig-06-saml-sig-n-email.png) + +新的步骤是 GraphQL 通信,即步骤 5.6 和 5.7。 + +同样,以下是 `idp.mts` 的更改部分。 + +```typescript +import { GraphQLClient } from 'graphql-request' +import { SchemaEncoder } from '@ethereum-attestation-service/eas-sdk' +``` + +导入我们需要的程序库。 + +```typescript +const graphqlEndpointUrl = "https://optimism.easscan.org/graphql" +``` + +[每个区块链都有一个单独的端点](https://docs.attest.org/docs/developer-tools/api)。 + +```typescript +const graphqlClient = new GraphQLClient(graphqlEndpointUrl, { fetch }) +``` + +创建一个新的 `GraphQLClient` 客户端,我们可以用它来查询端点。 + +```typescript +const graphqlSchema = 'string emailAddress' +const graphqlEncoder = new SchemaEncoder(graphqlSchema) +``` + +GraphQL 只给我们一个包含字节的不透明数据对象。 为了理解它,我们需要模式。 + +```typescript +const ethereumAddressToEmail = async ethAddr => { +``` + +一个从以太坊地址转换到电子邮件地址的函数。 + +```typescript + const query = ` + query GetAttestationsByRecipient { +``` + +这是一个 GraphQL 查询。 + +```typescript + 认证( +``` + +我们正在寻找认证。 + +```typescript + where: { + recipient: { equals: "${getAddress(ethAddr)}" } + schemaId: { equals: "0xfa2eff59a916e3cc3246f9aec5e0ca00874ae9d09e4678e5016006f07622f977" } + } +``` + +我们想要的认证是那些在我们模式中,接收者是 `getAddress(ethAddr)` 的认证。 [`getAddress`](https://viem.sh/docs/utilities/getAddress#getaddress) 函数确保我们的地址具有正确的[校验和](https://github.com/ethereum/ercs/blob/master/ERCS/erc-55.md)。 这对于 GraphQL 来说是必要的,因为它是大小写敏感的。 "0xBAD060A7"、"0xBad060A7" 和 "0xbad060a7" 是不同的值。 + +```typescript + take: 1 +``` + +无论我们找到多少认证,我们都只想要第一个。 + +```typescript + ) { + data + id + attester + } + }` +``` + +我们想要接收的字段。 + +- `attester`:提交认证的地址。 通常这用于决定是否信任认证。 +- `id`:认证 ID。 您可以使用此值[在链上读取认证](https://optimism.blockscout.com/address/0x4200000000000000000000000000000000000021?tab=read_proxy&source_address=0x4E0275Ea5a89e7a3c1B58411379D1a0eDdc5b088#0xa3112a64)以验证 GraphQL 查询中的信息是否正确。 +- `data`:模式数据(在本例中为电子邮件地址)。 + +```typescript + const queryResult = await graphqlClient.request(query) + + if (queryResult.attestations.length == 0) + return "no_address@available.is" +``` + +如果没有认证,则返回一个明显不正确但对服务提供者来说看似有效的值。 + +```typescript + const attestationDataFields = graphqlEncoder.decodeData(queryResult.attestations[0].data) + return attestationDataFields[0].value.value +} +``` + +如果存在值,则使用 `decodeData` 解码数据。 我们不需要它提供的元数据,只需要值本身。 + +```typescript + const loginResponse = await idp.createLoginResponse( + sp, + { + . + . + . + }, + "post", + { + email: await ethereumAddressToEmail(req.params.account) + } + ); +``` + +使用新函数获取电子邮件地址。 + +## 去中心化呢? + +在这种配置下,只要我们依赖可信的认证者进行以太坊到电子邮件地址的映射,用户就无法冒充他们不是的人。 然而,我们的身份提供者仍然是一个中心化组件。 任何拥有身份提供者私钥的人都可以向服务提供者发送虚假信息。 + +可能有一个使用[多方计算 (MPC)](https://en.wikipedia.org/wiki/Secure_multi-party_computation) 的解决方案。 我希望在未来的教程中写到它。 + +## 总结 + +采用像以太坊签名这样的登录标准面临着一个“先有鸡还是先有蛋”的问题。 服务提供商希望吸引尽可能广泛的市场。 用户希望能够访问服务,而不必担心支持他们的登录标准。 +创建适配器,例如以太坊 IdP,可以帮助我们克服这个障碍。 + +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 diff --git a/public/content/translations/zh/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/index.md b/public/content/translations/zh/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/index.md index 9bb59646124..5b690c1e99f 100644 --- a/public/content/translations/zh/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/index.md +++ b/public/content/translations/zh/developers/tutorials/getting-started-with-ethereum-development-using-alchemy/index.md @@ -1,60 +1,55 @@ --- -title: 以太坊开发入门 -description: "这是一份针对以太坊开发入门的初学者指南。 我们将带领你从启动一个 API 终端节点开始,到提出一个命令行请求,再到编写你的第一个 web3 脚本。 无需区块链的开发经验!" +title: "以太坊开发入门" +description: "这是一份针对以太坊开发入门的初学者指南。 我们将带领你从启动一个 API 终端节点开始,到提出一个命令行请求,再到编写你的第一个 web3 脚本。 无需区块链开发经验!" author: "Elan Halpern" -tags: - - "javascript" - - "ethers.js" - - "节点" - - "querying" - - "alchemy" +tags: [ "javascript", "ethers.js", "节点", "查询中", "Alchemy" ] skill: beginner lang: zh published: 2020-10-30 -source: Medium +source: "中" sourceUrl: https://medium.com/alchemy-api/getting-started-with-ethereum-development-using-alchemy-c3d6a45c567f --- -![以太坊和Alchemy徽标](./ethereum-alchemy.png) +![以太坊和 Alchemy 徽标](./ethereum-alchemy.png) -这是一份关于以太坊开发的初学者指南。 在本教程中,我们将使用[ Alchemy](https://alchemyapi.io/),这是一个领先的区块链开发者平台,为 70% 的顶级区块链应用程序(包括 Maker、0x、MyEtherWallet、Dharma 和 Kyber)的数百万用户提供支持。 Alchemy 使我们能够访问以太坊链上的 API 端点,这样我们就可以读写交易。 +这是一份关于以太坊开发的初学者指南。 在本教程中,我们将使用 [Alchemy](https://alchemyapi.io/),这是一个领先的区块链开发者平台,为 70% 的顶级区块链应用程序(包括 Maker、0x、MyEtherWallet、Dharma 和 Kyber)的数百万用户提供支持。 Alchemy 使我们能够访问以太坊链上的 API 端点,这样我们就可以读写交易。 -我们将带你注册Alchemy来编写你的第一个web3 脚本! 无需区块链的开发经验! +我们将带你注册 Alchemy 来编写你的第一个 web3 脚本! 无需区块链开发经验! -## 1. 注册免费Alchemy帐户 {#sign-up-for-a-free-alchemy-account} +## 1. 注册一个免费的 Alchemy 帐户 {#sign-up-for-a-free-alchemy-account} -创建 Alchemy 帐户很容易,[点击此处免费注册](https://auth.alchemyapi.io/signup)。 +创建 Alchemy 帐户很容易,[点击此处免费注册](https://auth.alchemy.com/)。 -## 2. 创建一个Alchemy应用程序 {#create-an-alchemy-app} +## 2. 创建 Alchemy 应用 {#create-an-alchemy-app} -为了与以太坊通信,以及为了使用 Alchemy 的产品,你需要一个 API 密钥来验证你的请求。 +为了与以太坊链通信,以及为了使用 Alchemy 的产品,你需要一个 API 密钥来验证你的请求。 -你可以通过[仪表板](http://dashboard.alchemyapi.io/)创建API密钥。 要创建一个新密钥,导航到如下所示的“Create App”: +你可以[从仪表板创建 API 密钥](https://dashboard.alchemy.com/)。 要创建一个新密钥,导航到如下所示的“Create App”: -特别感谢[_ShapeShift_](https://shapeshift.com/)_让我们展示他们的仪表板!_ +特别感谢 [_ShapeShift_](https://shapeshift.com/) _允许我们展示他们的仪表板!_ -![Alchemy仪表板](./alchemy-dashboard.png) +![Alchemy 仪表板](./alchemy-dashboard.png) 填写“Create App”下的详细信息以获取你的新密钥。 在此处还可以看到你以前创建的应用以及你的团队创建的应用。 通过点击任何应用的“View Key”来查看现有密钥。 -![使用Alchemy创建应用程序的截图](./create-app.png) +![使用 Alchemy 创建应用的屏幕截图](./create-app.png) -你也可以通过将鼠标悬停在“Apps”上并选择一个来获取现有API密钥。 你可以在这里“查看密钥”,以及“编辑应用程序”来特定域名加入白名单、查看几个开发者工具,并查看分析。 +你也可以通过将鼠标悬停在“Apps”上并选择一个来获取现有 API 密钥。 你可以在这里“View Key”,以及“Edit App”以将特定域加入白名单、查看几个开发者工具并查看分析。 -![显示用户如何获取API密钥的GIF图](./pull-api-keys.gif) +![显示用户如何获取 API 密钥的 Gif](./pull-api-keys.gif) -## 3. 在命令行中发送请求 {#make-a-request-from-the-command-line} +## 3. 从命令行发出请求 {#make-a-request-from-the-command-line} -使用JSON-RPC和curl通过Alchemy与以太坊区块链交互。 +使用 JSON-RPC 和 curl 通过 Alchemy 与以太坊区块链交互。 -对于手动请求,我们建议通过`JSON RPC`发送`POST`请求来进行交互。 只需传入`Content-Type: application/json`标头和查询作为`POST`主体,具有以下字段: +对于手动请求,我们建议通过 `POST` 请求与 `JSON-RPC` 交互。 只需传入 `Content-Type: application/json` 标头,并将你的查询作为 `POST` 正文,其中包含以下字段: -- `jsonrpc`: JSON-RPC版本,目前只支持`2.0`。 -- `method`:ETH API方法。 [请参阅API参考。](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc) -- `params`:要传递到方法的参数列表。 -- `id`:请求的ID。 将通过响应返回,这样就可以跟踪一个响应属于哪个请求。 +- `jsonrpc`:JSON-RPC 版本——目前仅支持 `2.0`。 +- `method`:ETH API 方法。 [请参阅 API 参考。](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc) +- `params`:要传递给方法的参数列表。 +- `id`:你的请求的 ID。 响应中会返回此 ID,以便你跟踪响应所属的请求。 -这是一个可通过命令行运行的示例,用于查询当前燃气价格: +这是一个可以从命令行运行以检索当前燃料价格的示例: ```bash curl https://eth-mainnet.alchemyapi.io/v2/demo \ @@ -63,7 +58,7 @@ curl https://eth-mainnet.alchemyapi.io/v2/demo \ -d '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":73}' ``` -_**注意:**将 [https://eth-mainnet.alchemyapi.io/v2/demo](https://eth-mainnet.alchemyapi.io/jsonrpc/demo) 替换成你自己的应用程序接口密钥 `https://eth-mainnet.alchemyapi.io/v2/**your-api-key`。_ +_\*\*注意:\*\*请将 [https://eth-mainnet.alchemyapi.io/v2/demo](https://eth-mainnet.alchemyapi.io/jsonrpc/demo) 替换为你自己的 API 密钥 `https://eth-mainnet.alchemyapi.io/v2/**your-api-key`。_ **结果:** @@ -71,37 +66,29 @@ _**注意:**将 [https://eth-mainnet.alchemyapi.io/v2/demo](https://eth-mainne { "id": 73,"jsonrpc": "2.0","result": "0x09184e72a000" // 10000000000000 } ``` -## 4. 设置Web3客户端 {#set-up-your-web3-client} +## 4. 设置你的 Web3 客户端 {#set-up-your-web3-client} -**如果你已有客户端,** 将你当前的节点提供商的 URL 更改为你的 API 密钥的 Alchemy URL: `“https://eth-mainnet.alchemyapi.io/v2/your-api-key”` +\*\*如果你有现有客户端,\*\*请将你当前的节点提供商 URL 更改为包含你 API 密钥的 Alchemy URL:`“https://eth-mainnet.alchemyapi.io/v2/your-api-key"` -**_注意:_**下面的脚本需要在一个**节点环境**中运行或**保存到一个文件运行**,而不是通过命令行运行。 如果你尚未安装节点或npm ,请查看此适用于mac的快速设置指南。 +**_注意:_**下面的脚本需要在**节点环境**中运行或**保存在文件中**运行,而不是从命令行运行。 如果你尚未安装 Node 或 npm,请查看此 [Mac 快速设置指南](https://app.gitbook.com/@alchemyapi/s/alchemy/guides/alchemy-for-macs)。 -许多 [Web3 库](https://docs.alchemyapi.io/guides/getting-started#other-web3-libraries)都可以和 Alchemy 集成。但是,我们建议使用 [Alchemy Web3](https://docs.alchemy.com/reference/api-overview),它是 web3.js 的替代插件,可与 Alchemy 无缝协作。 这个库有很多优点,例如自动重试和可靠的WebSocket支持。 - -要安装 AlchemyWeb3.js,请**导航到项目目录**并运行: - -**使用yarn:** +有许多可以与 Alchemy 集成的 [Web3 库](https://docs.alchemyapi.io/guides/getting-started#other-web3-libraries),但我们建议使用 [Alchemy Web3](https://docs.alchemy.com/reference/api-overview),这是一个 web3.js 的直接替代品,经构建和配置可与 Alchemy 无缝协作。 这个库有很多优点,例如自动重试和可靠的 WebSocket 支持。 +要安装 AlchemyWeb3.js,**导航到你的项目目录**并运行: +**使用 Yarn:** ``` yarn add @alch/alchemy-web3 ``` - -**使用NPM:** - - +**使用 NPM:** ``` npm install @alch/alchemy-web3 ``` - -要与Alchemy的节点基础设施交互,请在NodeJS中运行或将其添加到JavaScript文件: - - +要与 Alchemy 的节点基础设施交互,请在 NodeJS 中运行或将其添加到 JavaScript 文件: ```js const { createAlchemyWeb3 } = require("@alch/alchemy-web3") @@ -110,39 +97,26 @@ const web3 = createAlchemyWeb3( ) ``` +## 5. 编写你的第一个 Web3 脚本! {#write-your-first-web3-script} - - -## 5. 编写你的第一个Web3脚本! {#write-your-first-web3-script} - -现在用一个小的web3编程来练习,我们将编写一个简单的脚本,用于打印出以太坊主网中最新的区块高度。 +现在用一个小的 web3 编程来练习,我们将编写一个简单的脚本,用于打印出以太坊主网中最新的区块高度。 **1. 在终端中创建一个新的项目目录并通过 cd 命令进入该目录(如果尚未这样做):** - - ``` mkdir web3-example cd web3-example ``` - **2. 在项目中安装 Alchemy Web3(或任何 Web3)依赖项(如果尚未这样做):** - - ``` npm install @alch/alchemy-web3 ``` - **3. 创建一个名为 `index.js` 的文件并添加以下内容:** - - -> 最终应将`demo`替换为你的Alchemy HTTP API密钥 。 - - +> 你最终应将 `demo` 替换为你的 Alchemy HTTP API 密钥。 ```js async function main() { @@ -154,29 +128,22 @@ async function main() { main() ``` +不熟悉 async 函数? 请查看这篇 [Medium 帖子](https://medium.com/better-programming/understanding-async-await-in-javascript-1d81bb079b2c)。 -不熟悉 async 函数? 来看看这篇 [Medium 文章](https://medium.com/better-programming/understanding-async-await-in-javascript-1d81bb079b2c)。 - -**4. 使用节点在终端中运行该脚本** - - +**4. 在你的终端中使用 node 运行** ``` node index.js ``` - -**5. 现在应该会在控制台中看到最新的区块编号输出结果!** - - +**5. 现在你应该可以在控制台中看到最新的区块编号输出!** ``` The latest block number is 11043912 ``` +**哇!** 恭喜! 你刚刚使用 Alchemy 编写了你的第一个 Web3 脚本 🎉\*\* -**哇! 恭喜! 你刚刚使用 Alchemy 编写了你的第一个 Web3 脚本🎉** - -不知道下一步该怎么做? 尝试部署你的第一个智能合约,开始练习 Solidity 编程同时参阅我们的 [Hello World 智能合约指南](https://docs.alchemyapi.io/tutorials/hello-world-smart-contract),或使用 [Dashboard Demo App](https://docs.alchemyapi.io/tutorials/demo-app) 测试你的仪表板知识! +不知道下一步该怎么做? 尝试部署你的第一个智能合约,并在我们的 [Hello World 智能合约指南](https://www.alchemy.com/docs/hello-world-smart-contract)中动手进行一些 Solidity 编程,或者使用 [Dashboard 演示应用](https://docs.alchemyapi.io/tutorials/demo-app)测试你的仪表板知识! -免费_[注册 Alchemy](https://auth.alchemyapi.io/signup),查看我们的[相关文档](https://docs.alchemyapi.io/),并关注我们的 [Twitter](https://twitter.com/AlchemyPlatform)_ 了解最新消息。 +_[免费注册 Alchemy](https://auth.alchemy.com/),查看我们的[文档](https://www.alchemy.com/docs/),以及要了解最新消息,请在 [Twitter](https://twitter.com/AlchemyPlatform) 上关注我们_。 diff --git a/public/content/translations/zh/developers/tutorials/guide-to-smart-contract-security-tools/index.md b/public/content/translations/zh/developers/tutorials/guide-to-smart-contract-security-tools/index.md index d750829690f..5b59cd19c5c 100644 --- a/public/content/translations/zh/developers/tutorials/guide-to-smart-contract-security-tools/index.md +++ b/public/content/translations/zh/developers/tutorials/guide-to-smart-contract-security-tools/index.md @@ -1,105 +1,102 @@ --- -title: 智能合约安全工具指南 -description: 三种不同的测试和程序分析技术概述 +title: "智能合约安全工具指南" +description: "三种不同的测试和程序分析技术概述" author: "Trailofbits" lang: zh -tags: - - "solidity" - - "智能合约" - - "安全性" +tags: [ "Solidity", "智能合同", "安全性。" ] skill: intermediate published: 2020-09-07 -source: 构建安全的合约 +source: "构建安全的合约" sourceUrl: https://github.com/crytic/building-secure-contracts/tree/master/program-analysis --- 我们将使用三种独特的测试和程序分析技术: -- **使用 [Slither](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/) 进行静态分析**。通过不同的程序演示(例如控制流程图),同时对程序的所有路径进行模拟和分析。 -- **使用 [Echidna](/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/) 进行模糊测试。** 代码是通过伪随机生成的交易来执行的, 模糊器将尝试找到一个违反某个给定的合约特性的交易序列。 -- **使用 [Manticore](/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/) 进行符号执行。** 一种正式的验证技术,它将每个路径转换为数学公式,在此基础上可对最重要的约束加以检查。 +- **通过 [Slither](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/) 进行静态分析。** 通过不同的程序表示形式(例如控制流图),同时对程序的所有路径进行近似和分析。 +- **使用 [Echidna](/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/) 进行模糊测试。** 通过伪随机生成的交易来执行代码。 模糊器将尝试找到一个违反某个给定属性的交易序列。 +- **使用 [Manticore](/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/) 进行符号执行。** 这是一种形式化验证技术,可将每个执行路径转换为数学公式,在此基础上可检查约束条件。 -每种技术都有优缺点,在[特定情况](#determining-security-properties)下会很有用: +每种技术都有其优缺点,并且在[特定案例](#determining-security-properties)中会很有用: -| 技术 | 工具 | 使用方法 | 速度 | 错误遗漏 | 误报 | +| 技术 | 工具 | 用法 | 速度 | 遗漏的漏洞 | 误报 | | ---- | --------- | -------------- | -- | ----- | -- | -| 静态分析 | Slither | CLI 和脚本 | 秒 | 中度 | 低 | +| 静态分析 | Slither | CLI 和脚本 | 秒 | 中等 | 低 | | 模糊测试 | Echidna | Solidity 属性 | 分钟 | 低 | 无 | -| 符号执行 | Manticore | Solidity 属性和脚本 | 小时 | 无\* | 无 | +| 符号执行 | Manticore | Solidity 属性和脚本 | 小时 | 无\* | 无 | -\* 如果在没有超时情况下遍历所有路径 +\* 如果在没有超时的情况下探索了所有路径 -**Slither** 可以在几秒钟内分析合同,但是静态分析可能会导致误报,不太适合复杂的检查(例如算术检查)。 通过用于按钮访问内置检测器的 API 或用于用户自定义检查的 API 运行 Slither。 +**Slither** 可在数秒内分析合约,但是,静态分析可能会导致误报,并且不太适合复杂的检查(例如,算术检查)。 通过 API 运行 Slither,以便捷地访问内置探测器或进行用户自定义的检查。 -**Echidna** 需要运行几分钟,并且只会产生真阳性的测试结果。 Echidna 会检查用户提供的用 Solidity 编写的安全属性。 由于它的随机侦测的特性,它也许会错失一些漏洞。 +**Echidna** 需要运行数分钟,且只会产生真阳性结果。 Echidna 会检查用户提供的、用 Solidity 编写的安全属性。 由于它基于随机探索,因此可能会遗漏某些漏洞。 -**Manticore** 进行的是“最大权重”分析。 像 Echidna 一样,Manticore 会验证用户提供的特性。 它需要更多的时间来运行,但它可以证明某个特性的有效性,并且不会报告误报。 +**Manticore** 执行“最重量级”的分析。 与 Echidna 一样,Manticore 也可验证用户提供的属性。 它需要更长的运行时间,但能够证明属性的有效性,并且不会产生误报。 -## 推荐工作流程 {#suggested-workflow} +## 建议的工作流程 {#suggested-workflow} -从 Slither 的内置检测器开始,确保现在没有或以后不会引入简单的漏洞。 使用 Slither 检查与继承、变量依赖关系和结构问题相关的属性。 随着代码库的增大,可以使用 Echidna 来测试状态机更复杂的特性。 再次使用 Slither 开发专门用于那些 Solidity 不提供保护的自定义检查,比如防止某个函数被覆盖。 最后,使用 Manticore 对关键安全属性进行有针对性的验证,例如算术运算。 +从 Slither 的内置检测器入手,确保当前不存在或将来不会引入简单的漏洞。 使用 Slither 检查与继承、变量依赖和结构问题相关的属性。 随着代码库的增长,可使用 Echidna 测试状态机更复杂的属性。 再次使用 Slither,为 Solidity 未提供的保护(例如,防止函数被覆写)开发自定义检查。 最后,使用 Manticore 对关键安全属性(例如算术运算)执行针对性验证。 -- 使用 Slither 的 CLI 来捕捉常见问题 +- 使用 Slither 的 CLI 捕获常见问题 - 使用 Echidna 测试合约的高级安全属性 - 使用 Slither 编写自定义静态检查 -- 如果需要深入保证关键安全属性,请使用 Manticore +- 如果你希望深入确保关键安全属性,请使用 Manticore -**关于单元测试的说明**。 单元测试是构建高质量软件的必要条件。 然而,要找出安全漏洞,这些技术并不是最合适的。 它们通常用来测试正向代码行为(例如:代码在正常情况下按预期工作), 但安全漏洞往往存在于开发者未考虑的边缘情况。 在我们进行的数十次智能合约安全测试研究中,[单元测试覆盖率对于我们在客户端的代码中发现的安全漏洞的数量或者严重程度没有影响](https://blog.trailofbits.com/2019/08/08/246-findings-from-our-smart-contract-audits-an-executive-summary/)。 +**关于单元测试的说明**。 单元测试是构建高质量软件所必需的。 然而,这些技术并非是发现安全漏洞的最佳方法。 它们通常用于测试代码的积极行为(即,代码在正常情况下按预期工作),而安全漏洞往往存在于开发者没有考虑到的边缘情况。 在我们对数十个智能合约安全审计的研究中,我们发现[单元测试覆盖率对我们在客户代码中发现的安全漏洞的数量或严重性没有影响](https://blog.trailofbits.com/2019/08/08/246-findings-from-our-smart-contract-audits-an-executive-summary/)。 ## 确定安全属性 {#determining-security-properties} -为了有效测试和验证代码,你必须确定需要注意的地方。 因为花费在安全上的资源是有限的,只有划分出代码库中的薄弱和高价值部分,才能优化你的工作。 威胁建模可以提供帮助。 供考虑的审核方法有: +为有效测试和验证你的代码,你必须确定需要关注的领域。 由于你在安全方面的资源有限,因此确定代码库中薄弱或高价值的部分对于优化你的工作至关重要。 威胁建模可以提供帮助。 请考虑审查: - [快速风险评估](https://infosec.mozilla.org/guidelines/risk/rapid_risk_assessment.html)(时间紧迫时我们的首选方法) -- [数据中心系统威胁建模指南](https://csrc.nist.gov/publications/detail/sp/800-154/draft) (aka NIST 800-154) -- [Shostack 线程建模](https://www.amazon.com/Threat-Modeling-Designing-Adam-Shostack/dp/1118809998) -- [STRIDE](https://wikipedia.org/wiki/STRIDE_(security)) / [DREAD](https://wikipedia.org/wiki/DREAD_(risk_assessment_model)) +- [以数据为中心的系统威胁建模指南](https://csrc.nist.gov/pubs/sp/800/154/ipd) (又名 NIST 800-154) +- [Shostack 威胁建模](https://www.amazon.com/Threat-Modeling-Designing-Adam-Shostack/dp/1118809998) +- [STRIDE](https://wikipedia.org/wiki/STRIDE_\(security\)) / [DREAD](https://wikipedia.org/wiki/DREAD_\(risk_assessment_model\)) - [PASTA](https://wikipedia.org/wiki/Threat_model#P.A.S.T.A.) -- [使用断言](https://blog.regehr.org/archives/1091) +- [断言的使用](https://blog.regehr.org/archives/1091) ### 组件 {#components} -了解要检查的内容也有助于选择正确的工具。 +了解你想要检查的内容也有助于你选择正确的工具。 -通常与智能合约相关的领域比较广泛,包括: +与智能合约经常相关的广泛领域包括: -- **状态机**。大多数合约都可以表示为状态机。 考虑检查以下几点:(1) 不能到达无效状态,(2) 如果状态有效则可以到达,以及 (3) 没有状态会限制合约。 +- **状态机。** 大多数合约都可以表示为状态机。 考虑检查:(1) 无法达到无效状态;(2) 如果一个状态有效,则该状态可以达到;(3) 没有状态会使合约陷入陷阱。 - Echidna 和 Manticore 是测试状态机规范的首选工具。 -- **访问控制。**如果你的系统有特权用户(例如所有者、监管者等),你必须确保 (1) 每个用户只能执行授权操作,并且 (2) 没有用户可以阻止权限更大的用户的操作。 +- **访问控制。** 如果你的系统有特权用户(例如所有者、控制者……) 你必须确保 (1) 每个用户只能执行授权的操作,以及 (2) 没有用户可以阻止更具特权的用户执行操作。 - - Slither、Echidna 和 Manticore 都可以检查访问控制正确与否。 例如,Slither 可以检查是否只有白名单上的函数缺少 onlyOwner 修改器。 Echidna 和 Manticore 可用于更复杂的访问控制,例如仅当合约达到给定状态时才授予权限。 + - Slither、Echidna 和 Manticore 都可以检查访问控制的正确性。 例如,Slither 可以检查是否只有列入白名单的函数缺少 `onlyOwner` 修饰符。 Echidna 和 Manticore 对于更复杂的访问控制很有用,例如仅在合约达到特定状态时才授予权限。 -- **算术运算**。检查算术运算的可靠性至关重要。 在所有地方使用 `SafeMath` 是防止上溢/下溢很好的做法,但你还必需考虑其他算术缺陷,包括四舍五入和限制合约的缺陷。 +- **算术运算。** 检查算术运算的可靠性至关重要。 处处使用 `SafeMath` 是防止溢出/下溢的好方法,但你仍必须考虑其他算术缺陷,包括舍入问题和使合约陷入陷阱的缺陷。 - - 在这里,Manticore 是最佳选择。 如果算术超出 SMT 求解器的范围,则可以使用 Echidna。 + - Manticore 是此处的最佳选择。 如果算术运算超出了 SMT 求解器的范围,则可以使用 Echidna。 -- **继承的正确性**。Solidity 合约在很大程度上依赖于多重继承。 因此,很容易出现一些诸如像缺少`超级`调用的遮蔽函数和曲解了 C3 线性化的顺序之类的错误。 +- **继承的正确性。** Solidity 合约严重依赖多重继承。 诸如遮蔽函数缺少 `super` 调用以及对 c3 线性化顺序的误解等错误都很容易出现。 - - Slither 是确保检测出这些问题的工具。 + - Slither 是确保检测这些问题的工具。 -- **外部交互**。这里指合约之间的互动,一些外部合约不应该被信任。 例如,如果你的合约依赖于外部预言机,那么如果现有预言机有一半被泄漏,它是否仍然是安全的? +- **外部交互。** 合约之间会相互交互,某些外部合约不应被信任。 例如,如果你的合约依赖外部预言机,当一半可用预言机被攻破时,它是否仍然安全? - - Manticore 和 Echidna 是测试你的合约外部互动的最佳选择。 Manticore 有一个内置机制来存留外部合约。 + - Manticore 和 Echidna 是测试你的合约与外部交互的最佳选择。 Manticore 有一个内置机制,可以为外部合约创建存根。 -- **标准一致性**。 以太坊标准(例如 ERC20)记录了他们在设计上的缺陷。 请注意你正在构建的标准的局限性。 - - Slither、Echidna 和 Manticore 可以帮助你发现偏离特定标准的情况。 +- **标准一致性。** 以太坊标准(例如 ERC20)的设计曾出现过缺陷。 请注意你所依据的标准的局限性。 + - Slither、Echidna 和 Manticore 将帮助你检测与特定标准的偏差。 ### 工具选择备忘清单 {#tool-selection-cheatsheet} -| 组件 | 工具 | 示例 | -| ------ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 状态机 | Echidna、Manticore | | -| 访问控制 | Slither、Echidna、Manticore | [Slither 练习 2](https://github.com/crytic/slither/blob/7f54c8b948c34fb35e1d61adaa1bd568ca733253/docs/src/tutorials/exercise2.md)、[Echidna 练习 2](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/exercises/Exercise-2.md) | -| 算术运算 | Manticore、Echidna | [Echidna 练习 1](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/exercises/Exercise-1.md)、[Manticore 练习 1 - 3](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/manticore/exercises) | -| 继承的正确性 | Slither | [Slither 练习 1](https://github.com/crytic/slither/blob/7f54c8b948c34fb35e1d61adaa1bd568ca733253/docs/src/tutorials/exercise1.md) | -| 外部交互 | Manticore、Echidna | | -| 标准一致性 | Slither、Echidna、Manticore | [`slither-erc`](https://github.com/crytic/slither/wiki/ERC-Conformance) | +| 组件 | 工具 | 示例 | +| ------ | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 状态机 | Echidna、Manticore | | +| 访问控制 | Slither、Echidna、Manticore | [Slither 练习 2](https://github.com/crytic/slither/blob/7f54c8b948c34fb35e1d61adaa1bd568ca733253/docs/src/tutorials/exercise2.md)、[Echidna 练习 2](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/exercises/Exercise-2.md) | +| 算术运算 | Manticore、Echidna | [Echidna 练习 1](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/exercises/Exercise-1.md)、[Manticore 练习 1 - 3](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/manticore/exercises) | +| 继承的正确性 | Slither | [Slither 练习 1](https://github.com/crytic/slither/blob/7f54c8b948c34fb35e1d61adaa1bd568ca733253/docs/src/tutorials/exercise1.md) | +| 外部交互 | Manticore、Echidna | | +| 标准一致性 | Slither、Echidna、Manticore | [`slither-erc`](https://github.com/crytic/slither/wiki/ERC-Conformance) | -其他领域需要根据你的目标进行检查, 但以上囊括的大致重点领域对于所有智能合约系统来说都是一个良好的开端。 +根据你的目标,可能还需要检查其他领域,但这些粗粒度的重点领域对于任何智能合约系统来说都是一个很好的起点。 -我们公开的审计包含了经过验证或测试的属性实例。 请考虑阅读以下报告的`自动测试和验证部分`,以查看实际安全属性: +我们的公开审计报告包含经过验证或测试的属性示例。 请考虑阅读以下报告的“自动化测试和验证”部分,以审查真实世界的安全属性: - [0x](https://github.com/trailofbits/publications/blob/master/reviews/0x-protocol.pdf) -- [平衡器](https://github.com/trailofbits/publications/blob/master/reviews/BalancerCore.pdf) +- [Balancer](https://github.com/trailofbits/publications/blob/master/reviews/BalancerCore.pdf) diff --git a/public/content/translations/zh/developers/tutorials/hello-world-smart-contract-fullstack/index.md b/public/content/translations/zh/developers/tutorials/hello-world-smart-contract-fullstack/index.md index f214751ac8f..db1e4bb5c00 100644 --- a/public/content/translations/zh/developers/tutorials/hello-world-smart-contract-fullstack/index.md +++ b/public/content/translations/zh/developers/tutorials/hello-world-smart-contract-fullstack/index.md @@ -1,76 +1,79 @@ --- -title: 针对初学者的 Hello World 智能合约指南 - 全栈 -description: 关于编写和部署一个基于以太坊的简单智能合约的入门教程。 +title: "初学者全栈 Hello World 智能合约" +description: "关于在以太坊上编写和部署一个简单智能合约的入门教程。" author: "nstrike2" tags: - - "solidity" - - "hardhat" - - "alchemy" - - "智能合约" - - "deploying" - - "区块链浏览器" - - "前端" - - "交易" + [ + "Solidity", + "hardhat", + "Alchemy", + "智能合同", + "部署", + "区块浏览器", + "前端", + "交易" + ] skill: beginner lang: zh published: 2021-10-25 --- -如果你是区块链开发的新手,不知道从哪里开始或者如何部署并与智能合约交互,那么这个指南就是为你准备的。 我们将演示如何使用 [MetaMask](https://metamask.io)、[Solidity](https://docs.soliditylang.org/en/v0.8.0/)、[安全帽](https://hardhat.org)以及 [Alchemy](https://alchemyapi.io/eth),在 Goerli 测试网络上创建和部署一个简单的智能合约。 +如果你是区块链开发的新手,不知道从哪里开始或者如何部署并与智能合约交互,那么本指南就是为你准备的。 我们将使用 [MetaMask](https://metamask.io)、[Solidity](https://docs.soliditylang.org/en/v0.8.0/)、[Hardhat](https://hardhat.org) 和 [Alchemy](https://alchemy.com/eth) 逐步创建一个简单的智能合约并将其部署到 Goerli 测试网上。 -你将会需要一个 Alchemy 帐户来完成这个教程。 [注册一个免费帐户](https://www.alchemy.com/)。 +你将需要一个 Alchemy 帐户来完成这个教程。 [注册一个免费帐户](https://www.alchemy.com/)。 -如果你有任何问题,请随时在 [Alchemy Discord](https://discord.gg/gWuC7zB) 中提出! +如果你在任何时候有任何疑问,欢迎随时在 [Alchemy Discord](https://discord.gg/gWuC7zB) 中联系我们! -## 第一部分 - 使用安全帽创建和部署你的智能合约 {#part-1} +## 第一部分 - 使用Hardhat创建和部署你的智能合约 {#part-1} -### 连接以太坊网络 {#connect-to-the-ethereum-network} +### 连接到以太坊网络 {#connect-to-the-ethereum-network} -有多种方法可以向以太坊链发起连接请求。 简单起见,我们将会使用一个 Alchemy 上的免费帐户。Alchemy 是一个区块链开发者平台和应用程序接口,让我们在不用自己运行节点的情况下与以太坊链进行通信。 Alchemy 还有着用于监控和分析的开发者工具;我们将在本教程中利用这些工具来深入了解我们智能合约部署中的情况。 +有很多方法可以向以太坊链发送请求。 为简单起见,我们将使用 Alchemy 上的免费帐户。Alchemy 是一个区块链开发者平台和 API,让我们在不用自己运行节点的情况下与以太坊链进行通信。 Alchemy 还有着用于监控和分析的开发者工具;我们将在本教程中利用这些工具来深入了解我们智能合约部署中的情况。 -### 创建你的应用程序和应用程序接口密钥 {#create-your-app-and-api-key} +### 创建你的应用和 API 密钥 {#create-your-app-and-api-key} -当你创建了一个 Alchemy 帐户后,你可以通过创建应用程序来生成应用程序接口密钥。 这将允许你向 Goerli 测试网发送请求。 如果你不熟悉测试网,你可以[阅读 Alchemy 指南来选择一个网络](https://docs.alchemyapi.io/guides/choosing-a-network)。 +创建 Alchemy 帐户后,你可以通过创建应用来生成 API 密钥。 这将允许你向 Goerli 测试网发送请求。 如果你不熟悉测试网,可以[阅读 Alchemy 关于选择网络的指南](https://www.alchemy.com/docs/choosing-a-web3-network)。 -在 Alchemy 仪表板上,找到位于导航栏的 **Apps** 下拉菜单并点击 **Create App**。 +在 Alchemy 仪表板上,找到位于导航栏的“应用”下拉菜单并点击“创建应用”。 -![创建应用程序 Hello world](./hello-world-create-app.png) +![Hello world 创建应用程序](./hello-world-create-app.png) -给你的应用程序命名为“_Hello World_”并写一个简短的描述。 选择 **Staging** 作为你的环境以及 **Goerli** 作为你的网络。 +给你的应用命名为“_Hello World_”并写一个简短的描述。 选择“**Staging**”作为你的环境以及“**Goerli**”作为你的网络。 ![创建应用程序视图 hello world](./create-app-view-hello-world.png) -_注:请确保选择 **Goerli**,否则本教程将不适用。_ +_注意:请确保选择 **Goerli**,否则本教程将无法正常进行。_ -点击 **Create app**。 你的应用程序应该会出现在下面的表中。 +点击“**Create app**”。 你的应用程序应该会出现在下表中。 -### 创建一个以太坊帐户 {#create-an-ethereum-account} +### 创建以太坊帐户 {#create-an-ethereum-account} 你需要一个以太坊帐户来发送和接受交易。 我们将会使用 MetaMask,这是一个浏览器中的虚拟钱包,可供用户管理他们的以太坊帐户地址。 -你可以[在这里](https://metamask.io/download)免费下载并创建一个 MetaMask 帐户。 When you are creating an account, or if you already have an account, make sure to switch over to the “Goerli Test Network” in the upper right (so that we’re not dealing with real money). +你可以[在此处](https://metamask.io/download)免费下载和创建 MetaMask 帐户。 在你创建帐户时,或者如果你已经有帐户,请确保切换到右上角的“Goerli 测试网络”(这样我们就不会使用实际货币进行交易)。 -### 步骤 4:从水龙头添加以太币 {#step-4-add-ether-from-a-faucet} +### 步骤 4:从水龙头获取以太币 {#step-4-add-ether-from-a-faucet} -为了将你的智能合约部署到测试网络,你需要一些虚拟以太币。 为了获得 Goerli 网络上的以太币,请前往 Goerli 水龙头并输入你的 Goerli 帐户地址。 注意 Goerli 水龙头最近可能不太可靠 - 请查看[测试网络页面](/developers/docs/networks/#goerli)以了解可以尝试的选项列表: +要将你的智能合约部署到测试网,你需要一些虚拟 ETH。 要在 Goerli 网络上获取 ETH,请前往 Goerli 水龙头并输入你的 Goerli 帐户地址。 请注意,Goerli 水龙头最近可能不太可靠 - 请参阅[测试网页面](/developers/docs/networks/#goerli)获取可供尝试的选项列表: -_注:由于网络拥塞,这可能需要一些时间。_ +_注意:由于网络拥堵,这可能需要一些时间。_ +`` -### 步骤 5:查看帐户余额 {#step-5-check-your-balance} +### 第 5 步:检查你的余额 {#step-5-check-your-balance} -为了核查钱包中的以太币,我们使用 [Alchemy 的 Composer 工具](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D)来发送 [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) 请求。 这将返回我们钱包中的以太币金额。 想要了解更多请查看 [Alchemy 关于如何使用 Composer 工具的简短教程](https://youtu.be/r6sjRxBZJuU)。 +为仔细检查 ETH 是否已在你的钱包中,我们来使用 [Alchemy 的 composer 工具](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D)发出一个 [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) 请求。 这将返回我们钱包中的以太币数量。 要了解更多信息,请查看 [Alchemy 关于如何使用 composer 工具的简短教程](https://youtu.be/r6sjRxBZJuU)。 -输入你的 MetaMask 帐户地址并点击 **Send Request**。 你将会看到类似以下代码片段的响应。 +输入你的 MetaMask 帐户地址并点击“**Send Request**”。 你将看到类似以下代码片段的响应。 ```json { "jsonrpc": "2.0", "id": 0, "result": "0x2B5E3AF16B1880000" } ``` -> _注:此结果以 wei 为单位,而非 ETH。 Wei is used as the smallest denomination of ether._ +> _注意:此结果以 wei 为单位,而非 ETH。 Wei 是以太币的最小计量单位。_ -Phew! 这里显示了我们所有的虚拟货币。 +哦! 这里显示了我们所有的虚拟货币。 -### 步骤 6:初始化我们的项目 {#step-6-initialize-our-project} +### 第 6 步:初始化我们的项目 {#step-6-initialize-our-project} 首先,需要为我们的项目创建一个文件夹。 导航到你的命令行并输入以下内容。 @@ -81,14 +84,14 @@ cd hello-world 现在我们进入了项目文件夹,我们将使用 `npm init` 来初始化项目。 -> 如果你尚未安装 npm,请按照[这些说明来安装 Node.js 和 npm](https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm)。 +> 如果你尚未安装 npm,请按照[这些说明安装 Node.js 和 npm](https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm)。 对于本教程而言,你如何回答初始化问题并不重要。 以下是我们的参考操作方式: ``` package name: (hello-world) version: (1.0.0) -description: hello world smart contract +description: hello world 智能合约 entry point: (index.js) test command: git repository: @@ -96,26 +99,26 @@ keywords: author: license: (ISC) -About to write to /Users/.../.../.../hello-world/package.json: +即将写入 /Users/.../.../.../hello-world/package.json: { "name": "hello-world", "version": "1.0.0", - "description": "hello world smart contract", + "description": "hello world 智能合约", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"错误:未指定测试\" && exit 1" }, "author": "", "license": "ISC" } ``` -批准 package.json,我们就可以进行下一步了! +批准 package.json,我们就可以继续了! -### 步骤 7:下载安全帽 {#step-7-download-hardhat} +### 第 7 步:下载Hardhat {#step-7-download-hardhat} -安全帽是一个用于编译、部署、测试和调试以太坊软件的开发环境。 它帮助开发者在本地构建智能合约和去中心化应用程序并部署到实时链上。 +Hardhat是一个用于编译、部署、测试和调试以太坊软件的开发环境。 它帮助开发者在本地构建智能合约和去中心化应用程序并部署到实时链上。 在我们的 `hello-world` 项目中运行: @@ -123,9 +126,9 @@ About to write to /Users/.../.../.../hello-world/package.json: npm install --save-dev hardhat ``` -查看此页面,了解更多有关[安装说明](https://hardhat.org/getting-started/#overview)的详细信息。 +请查看此页面,详细了解[安装说明](https://hardhat.org/getting-started/#overview)。 -### 步骤 8:创建安全帽项目 {#step-8-create-hardhat-project} +### 第 8 步:创建Hardhat项目 {#step-8-create-hardhat-project} 在我们的 `hello-world` 项目文件夹中,运行: @@ -145,17 +148,17 @@ npx hardhat 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. 888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 -👷 Welcome to Hardhat v2.0.11 👷‍ +👷 欢迎来到Hardhat v2.0.11 👷‍ -What do you want to do? … -Create a sample project -❯ Create an empty hardhat.config.js -Quit +你想做什么?… +创建一个示例项目 +❯ 创建一个空的 hardhat.config.js +退出 ``` -这将会在项目中生成一个 `hardhat.config.js` 文件。 我们稍后将在教程中使用它来为我们的项目指定设置。 +这将在项目中生成一个 `hardhat.config.js` 文件。 我们稍后将在教程中使用它来为我们的项目指定设置。 -### 步骤 9:添加项目文件夹 {#step-9-add-project-folders} +### 第 9 步:添加项目文件夹 {#step-9-add-project-folders} 为了使项目有条理,我们将创建两个新的文件夹。 在命令行中,导航到你的 `hello-world` 项目的根目录中并输入: @@ -164,46 +167,46 @@ mkdir contracts mkdir scripts ``` -- `contracts/` 是保存我们的 hello world 智能合约代码文件的位置 -- `scripts/` 是我们存放脚本的位置,用于部署我们的合约和与之交互。 +- `contracts/` 是我们存放 hello world 智能合约代码文件的地方 +- `scripts/` 是我们存放部署和交互合约脚本的地方 -### 步骤 10:编写合约 {#step-10-write-our-contract} +### 第 10 步:编写我们的合约 {#step-10-write-our-contract} 你可能在问自己,到底什么时候才能写代码? 就是现在! -在你最喜爱的编辑器中打开 hello-world 项目。 智能合约通常使用 Solidity 来编写,我们也将使用它来编写智能合约。 +在你最喜爱的编辑器中打开 hello-world 项目。 智能合约通常使用 Solidity 来编写,我们也将使用它来编写智能合约。‌ -1. 导航到 `contracts` 文件夹并创建一个名为 `HelloWorld.sol` 的新文件。 +1. 导航到 `contracts` 文件夹并创建一个名为 `HelloWorld.sol` 的新文件 2. 下面是我们将在本教程中使用的示例 Hello World 智能合约。 将下面的内容复制到 `HelloWorld.sol` 文件中。 -_注:务必阅读注释以理解此合约的内容。_ +_注意:务必阅读注释以理解此合约的内容。_ ``` -// Specifies the version of Solidity, using semantic versioning. -// Learn more: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma +// 指定 Solidity 的版本,使用语义版本控制。 +// 了解更多:https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma pragma solidity >=0.7.3; -// Defines a contract named `HelloWorld`. -// 一个合约是函数和数据(其状态)的集合。 Once deployed, a contract resides at a specific address on the Ethereum blockchain. Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html +// 定义一个名为 `HelloWorld` 的合约。 +// 合约是函数和数据(其状态)的集合。一旦部署,合约就位于以太坊区块链上的一个特定地址。了解更多:https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html contract HelloWorld { - //Emitted when update function is called - //Smart contract events are a way for your contract to communicate that something happened on the blockchain to your app front-end, which can be 'listening' for certain events and take action when they happen. + // 在调用 update 函数时发出 + // 智能合约事件是合约向应用程序前端传达区块链上发生的事情的一种方式,前端可以“监听”某些事件并在事件发生时采取行动。 event UpdatedMessages(string oldStr, string newStr); - // Declares a state variable `message` of type `string`. - // 状态变量是其值永久存储在合约存储中的变量。 The keyword `public` makes variables accessible from outside a contract and creates a function that other contracts or clients can call to access the value. + // 声明一个 `string` 类型的状态变量 `message`。 + // 状态变量是其值永久存储在合约存储中的变量。`public` 关键字使变量可以从合约外部访问,并创建一个其他合约或客户端可以调用以访问该值的函数。 string public message; - // Similar to many class-based object-oriented languages, a constructor is a special function that is only executed upon contract creation. - // 构造器用于初始化合约的数据。 Learn more:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors + // 与许多基于类的面向对象语言类似,构造函数是一个特殊函数,仅在创建合约时执行。 + // 构造函数用于初始化合约的数据。了解更多:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors constructor(string memory initMessage) { - // Accepts a string argument `initMessage` and sets the value into the contract's `message` storage variable). + // 接受一个字符串参数 `initMessage`,并将其值设置到合约的 `message` 存储变量中)。 message = initMessage; } - // A public function that accepts a string argument and updates the `message` storage variable. + // 一个接受字符串参数并更新 `message` 存储变量的 public 函数。 function update(string memory newMessage) public { string memory oldMsg = message; message = newMessage; @@ -214,13 +217,13 @@ contract HelloWorld { 这是一个在创建时存储一条消息的基础智能合约。 可以通过调用 `update` 函数来更新该合约。 -### 步骤 11:将 Metamask 和 Alchemy 连接至你的项目 {#step-11-connect-metamask-alchemy-to-your-project} +### 第 11 步:将 MetaMask 和 Alchemy 连接到你的项目 {#step-11-connect-metamask-alchemy-to-your-project} -我们创建了 MetaMask 钱包、Alchemy 帐户,并且编写了一个智能合约,现在是将这三者连起来的时候了。 +我们已经创建了 MetaMask 钱包、Alchemy 帐户并编写了智能合约,现在是时候将这三者连接起来了。 -从你的钱包发出的每一笔交易都需要使用你独有私钥的签名。 为了给我们的程序提供此权限,我们可以安全地将私钥存储在一个环境文件中。 我们也会在此存储一个 Alchemy 的应用程序接口密钥。 +从你的钱包发出的每一笔交易都需要使用你独有的私钥签名。 为了给我们的程序提供此权限,我们可以安全地将私钥存储在一个环境文件中。 我们也会在此存储一个 Alchemy 的 API 密钥。 -> 如需了解更多关于发送交易的信息,请查看关于使用 web3 发送交易的[教程](https://docs.alchemyapi.io/alchemy/tutorials/sending-transactions-using-web3-and-alchemy)。 +> 要了解有关发送交易的更多信息,请查看有关使用 web3 发送交易的[本教程](https://www.alchemy.com/docs/hello-world-smart-contract#step-11-connect-metamask--alchemy-to-your-project)。 首先,在项目目录中安装 dotenv 软件包: @@ -228,31 +231,31 @@ contract HelloWorld { npm install dotenv --save ``` -然后,在项目根目录下创建一个 `.env` 文件。 在文件中添加你的 MetaMask 私钥和 HTTP Alchemy 应用程序接口 URL。 +然后,在项目根目录下创建一个 `.env` 文件。 在文件中添加你的 MetaMask 私钥和 HTTP Alchemy API URL。 你的环境文件必须以 `.env` 命名,否则不会被识别为环境文件。 不要命名为 `process.env` 或 `.env-custom` 或其他名称。 -- 遵循[这些说明](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key)导出你的私钥 -- 请从下方获取超文本传输协议 Alchemy 应用程序接口网址 +- 按照[这些说明](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key)导出你的私钥 +- 请参阅下文以获取 HTTP Alchemy API URL ![](./get-alchemy-api-key.gif) -你的 `.env` 文件应该类似: +你的 `.env` 文件应如下所示: ``` API_URL = "https://eth-goerli.alchemyapi.io/v2/your-api-key" PRIVATE_KEY = "your-metamask-private-key" ``` -为了将这些变量和代码连接,我们将在步骤 13 中调用 `hardhat.config.js` 文件中的这些变量。 +为了真正将它们连接到我们的代码,我们将在第 13 步的 `hardhat.config.js` 文件中引用这些变量。 -### 步骤 12:安装 Ethers.js {#step-12-install-ethersjs} +### 第 12 步:安装 Ethers.js {#step-12-install-ethersjs} -Ethers.js 是一个程序库,通过以更加方便用户的方法打包[标准 JSON RPC 方法](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc),从而更容易与以太坊互动,以及向以太坊提出请求。 +Ethers.js 是一个库,它通过将[标准 JSON-RPC 方法](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc)封装成更方便用户的方法,从而更容易与以太坊互动并提出请求。 -安全帽可用于集成[插件](https://hardhat.org/plugins/)以获取额外的工具和扩展功能。 我们将利用 [Ethers 插件](https://hardhat.org/docs/plugins/official-plugins#hardhat-ethers)完成合约部署。 +Hardhat允许我们集成[插件](https://hardhat.org/plugins/)以获取额外的工具和扩展功能。 我们将利用 [Ethers 插件](https://hardhat.org/docs/plugins/official-plugins#hardhat-ethers)来进行合约部署。 在你的项目目录中输入: @@ -260,11 +263,11 @@ Ethers.js 是一个程序库,通过以更加方便用户的方法打包[标准 npm install --save-dev @nomiclabs/hardhat-ethers "ethers@^5.0.0" ``` -### 步骤 13:更新 hardhat.config.js {#step-13-update-hardhat-configjs} +### 第 13 步:更新 hardhat.config.js {#step-13-update-hardhat-configjs} -到目前为止,我们已经添加了几个依赖库和插件,现在我们需要更新 `hardhat.config.js`,以便项目使用所有这些新的组件。 +到目前为止,我们已经添加了几个依赖项和插件,现在我们需要更新 `hardhat.config.js`,以便我们的项目了解所有这些依赖项和插件。 -按如下所示更新你的 `hardhat.config.js` 代码: +将你的 `hardhat.config.js` 更新为如下所示: ```javascript /** @@ -289,9 +292,9 @@ module.exports = { } ``` -### 步骤 14:编写合约 {#step-14-compile-our-contract} +### 第 14 步:编译我们的合约 {#step-14-compile-our-contract} -为了确保一切正常,我们来编译一下合约。 `compile` 任务是安全帽的内部任务之一。 +为了确保一切正常,我们来编译一下合约。 `compile` 任务是内置的 hardhat 任务之一。 在命令行中运行: @@ -299,21 +302,21 @@ module.exports = { npx hardhat compile ``` -你可能会看到关于 `SPDX license identifier not provided in source file` 的警告,但不用担心,希望其他方面看起来一切正常! 如果遇到问题,你可以随时在 [Alchemy cord](https://discord.gg/u72VCg3) 社区中发消息询问。 +你可能会看到关于“`SPDX license identifier not provided in source file`”的警告,但无需担心——希望其他的一切正常! 如果编译不成功,可以随时在 [Alchemy discord](https://discord.gg/u72VCg3) 中发消息。 -### 步骤 15:编写部署脚本 {#step-15-write-our-deploy-script} +### 第 15 步:编写我们的部署脚本 {#step-15-write-our-deploy-script} 合约已经写完,配置文件也准备妥当,现在是写合约部署脚本的时候了。 -转到 `scripts/` 文件夹,创建一个名为 `deploy.js` 的新文件,在其中添加以下内容: +导航到 `scripts/` 文件夹并创建一个名为 `deploy.js` 的新文件,向其中添加以下内容: ```javascript async function main() { const HelloWorld = await ethers.getContractFactory("HelloWorld") - // Start deployment, returning a promise that resolves to a contract object + // 开始部署,返回一个解析为合约对象的 promise const hello_world = await HelloWorld.deploy("Hello World!") - console.log("Contract deployed to address:", hello_world.address) + console.log("合约已部署到地址:", hello_world.address) } main() @@ -324,23 +327,23 @@ main() }) ``` -安全帽在[合约教程](https://hardhat.org/tutorial/testing-contracts.html#writing-tests)中对这些代码的每一行均提供了很好的解释,我们在这里直接引用他们的解释。 +Hardhat在他们的[合约教程](https://hardhat.org/tutorial/testing-contracts.html#writing-tests)中极好地解释了每一行代码的作用,我们在此处采用了他们的解释。 ```javascript const HelloWorld = await ethers.getContractFactory("HelloWorld") ``` -ethers.js 中的 `ContractFactory` 是用于部署新智能合约的抽象对象。因此这里的 `HelloWorld` 是我们 hello world 合约实例的[工厂](https://en.wikipedia.org/wiki/Factory_(object-oriented_programming))。 使用 `hardhat-ethers` 插件时,`ContractFactory` 和 `Contract` 实例默认与第一个签名者(所有者)相连。 +ethers.js 中的 `ContractFactory` 是用于部署新智能合约的抽象,因此这里的 `HelloWorld` 是我们 hello world 合约实例的[工厂](https://en.wikipedia.org/wiki/Factory_\(object-oriented_programming\))。 使用 `hardhat-ethers` 插件时,`ContractFactory` 和 `Contract` 实例默认与第一个签名者(所有者)相连。 ```javascript const hello_world = await HelloWorld.deploy() ``` -调用 `ContractFactory` 代码中的 `deploy()` 函数会启动合约部署,然后返回解析为 `Contract` 对象的 `Promise`。 这个对象包括我们智能合约中每个函数的对应调用方法。 +在 `ContractFactory` 上调用 `deploy()` 会启动部署,并返回一个解析为 `Contract` 对象的 `Promise`。 这个对象包括我们智能合约中每个函数的对应调用方法。 -### 步骤 16:部署合约 {#step-16-deploy-our-contract} +### 第 16 步:部署我们的合约 {#step-16-deploy-our-contract} -我们终于准备好部署我们的智能合约啦! 导航到命令行后运行: +我们终于准备好部署我们的智能合约啦! 导航到命令行并运行: ```bash npx hardhat run scripts/deploy.js --network goerli @@ -349,36 +352,36 @@ npx hardhat run scripts/deploy.js --network goerli 你会看到类似以下所示的信息: ```bash -Contract deployed to address: 0x6cd7d44516a20882cEa2DE9f205bF401c0d23570 +合约已部署到地址:0x6cd7d44516a20882cEa2DE9f205bF401c0d23570 ``` **请保存这个地址**。 之后在教程中我们会用到这个地址。 -如果我们在 [Goerli etherscan](https://goerli.etherscan.io) 搜索我们的合约地址,我们应能够看到它已经成功部署。 交易将类似以下: +如果我们前往 [Goerli etherscan](https://goerli.etherscan.io) 并搜索我们的合约地址,应该能看到它已成功部署。 交易将类似以下: ![](./etherscan-contract.png) -`From` 地址应该匹配你的 MetaMask 帐户地址,`To` 地址将是**合约创建**。 如果我们点击进入交易,我们将在 `To` 字段中看到我们的合约地址。 +`From` 地址应匹配你的 MetaMask 帐户地址,`To` 地址将显示**合约创建**。 如果我们点击进入交易,我们将在 `To` 字段中看到我们的合约地址。 ![](./etherscan-transaction.png) 恭喜! 你刚刚在以太坊测试网上部署了一个智能合约。 -为了更深入了解到底发生了什么,我们转到 [Alchemy 仪表板](https://dashboard.alchemyapi.io/explorer)中的 Explorer 选项卡。 如果你有多个 Alchemy 应用程序,请确保按应用程序筛选,然后选择 **Hello World**。 +要了解后台运行情况,我们导航到我们的 [Alchemy 仪表板](https://dashboard.alchemy.com/explorer)中的 Explorer 选项卡。 如果你有多个 Alchemy 应用,请确保按应用筛选并选择“**Hello World**”。 ![](./hello-world-explorer.png) -在这里,你会看到一系列 JSON-RPC 方法,当我们调用 `.deploy()` 函数时,安全帽/Ethers 会在后端完成这些方法。 在这里有两个重要的方法,[`eth_sendRawTransaction`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_sendrawtransaction) 是用于把我们的合约写入 Goerli 链的请求,[`eth_getTransactionByHash`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_gettransactionbyhash) 是根据哈希读取交易信息的请求。 如需了解更多关于发送交易的信息,请查看[我们关于使用 Web3 发送交易的教程](/developers/tutorials/sending-transactions-using-web3-and-alchemy/)。 +在这里,你会看到一系列 JSON-RPC 方法,当我们调用 `.deploy()` 函数时,Hardhat/Ethers 会在后台为我们调用这些方法。 这里有两个重要方法:[`eth_sendRawTransaction`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_sendrawtransaction) 是将我们的合约写入 Goerli 链的请求,而 [`eth_getTransactionByHash`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_gettransactionbyhash) 是在给定哈希的情况下读取我们交易信息的请求。 要了解有关发送交易的更多信息,请查看[我们关于使用 Web3 发送交易的教程](/developers/tutorials/sending-transactions-using-web3-and-alchemy/)。 -## 第二部分 - 和你的智能合约交互 {#part-2-interact-with-your-smart-contract} +## 第二部分:与你的智能合约交互 {#part-2-interact-with-your-smart-contract} 现在我们已经成功地将智能合约部署到 Goerli 网络,让我们学习如何与它交互。 -### 创建 interact.js 文件 {#create-a-interactjs-file} +### 创建一个 interact.js 文件 {#create-a-interactjs-file} 这是我们将在其中编写交互脚本的文件。 我们将使用在第一部分中安装的 Ethers.js 库。 -在 `scripts/` 文件夹中,新建一个文件,命名为 `interact.js`,添加以下代码: +在 `scripts/`文件夹中,新建一个文件,命名为 `interact.js`,添加以下代码: ```javascript // interact.js @@ -388,9 +391,9 @@ const PRIVATE_KEY = process.env.PRIVATE_KEY const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS ``` -### 更新 .env 文件 {#update-your-env-file} +### 更新你的 .env 文件 {#update-your-env-file} -我们将使用新的环境变量,因此需要在[我们之前创建的 ](#step-11-connect-metamask-&-alchemy-to-your-project)`.env` 文件中定义这些变量。 +我们将使用新的环境变量,因此需要在我们[之前创建](#step-11-connect-metamask-&-alchemy-to-your-project)的 `.env` 文件中定义这些变量。 我们需要为 Alchemy `API_KEY` 和部署你的智能合约的 `CONTRACT_ADDRESS` 添加定义。 @@ -405,36 +408,36 @@ PRIVATE_KEY = "" CONTRACT_ADDRESS = "0x" ``` -### 获取你的合约应用程序二进制接口 {#grab-your-contract-ABI} +### 获取你的合约 ABI {#grab-your-contract-ABI} -我们的合约 [ABI(应用程序二进制接口)](/glossary/#abi)是与我们的智能合约交互的接口。 安全帽自动生成应用程序二进制接口,并将其保存在 `HelloWorld.json` 中。 为了使用该接口,我们需要通过在我们的 `interact.js` 文件中添加以下代码行来解析内容: +我们的合约 [ABI(应用程序二进制接口)](/glossary/#abi)是与我们的智能合约交互的接口。 Hardhat自动生成 ABI,并将其保存在 `HelloWorld.json` 中。 为了使用该接口,我们需要通过在我们的 `interact.js` 文件中添加以下代码行来解析内容: ```javascript // interact.js const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json") ``` -如果你想查看应用程序二进制接口,你可以将其发送到你的控制台: +如果你想查看 ABI,可以将其打印到控制台: ```javascript console.log(JSON.stringify(contract.abi)) ``` -要查看输出到控制台的应用程序二进制接口,请导航至你的终端并运行: +要查看输出到控制台的 ABI,请导航至你的终端并运行: ```bash npx hardhat run scripts/interact.js ``` -### 创建合约的实例 {#create-an-instance-of-your-contract} +### 创建合约实例 {#create-an-instance-of-your-contract} 为了与我们的合约进行交互,我们需要在代码中创建一个合约实例。 要使用 Ethers.js 实现,我们需要使用三个概念: -1. 提供者 - 为你提供区块链读写访问权限的节点提供者。 +1. 提供者 - 为你提供区块链读写访问权限的节点提供者 2. 签名者 - 代表可以给交易签名的以太坊帐户 -3. 合约 - 代表部署在链上的特定合约的 Ethers.js对象 +3. 合约 - 代表部署在链上的特定合约的 Ethers.js 对象 -我们将使用上一步中的合约应用程序二进制接口来创建我们的合约实例: +我们将使用上一步中的合约 ABI 来创建我们的合约实例: ```javascript // interact.js @@ -458,13 +461,13 @@ const helloWorldContract = new ethers.Contract( 在 [ethers.js 文档](https://docs.ethers.io/v5/)获取更多关于提供者、签名者和合约的信息。 -### 阅读 init 消息 {#read-the-init-message} +### 读取初始消息 {#read-the-init-message} 还记得我们用 `initMessage = "Hello world!"` 部署合约时的情况吗? 我们现在要读取存储在智能合约中的消息,并将其输出到控制台。 -在 JavaScript 中,与网络交互时会使用异步函数。 要了解更多关于异步函数的信息,[请阅读这篇 Medium 文章](https://blog.bitsrc.io/understanding-asynchronous-javascript-the-event-loop-74cd408419ff)。 +在 JavaScript 中,与网络交互时会使用异步函数。 要了解有关异步函数的更多信息,请[阅读这篇 Medium 文章](https://blog.bitsrc.io/understanding-asynchronous-javascript-the-event-loop-74cd408419ff)。 -使用下面的代码来调用智能合约中的 `message` 函数,并读取 init 消息: +使用下面的代码来调用智能合约中的 `message` 函数,并读取初始消息: ```javascript // interact.js @@ -481,7 +484,7 @@ main() 在终端使用 `npx hardhat run scripts/interact.js` 运行文件后,我们应该看到如下响应: ``` -The message is: Hello world! +消息是:Hello world! ``` 恭喜! 你刚刚成功从以太坊区块链读取了智能合约数据,好样的! @@ -508,11 +511,11 @@ async function main() { main() ``` -请注意,在第 11 行,我们对返回的交易对象调用了 `.wait()`。 这确保了脚本在退出函数前等待交易在区块链上完成挖掘。 如果不包含 `.wait()` 调用,脚本可能不会看到合约中更新后的 `message` 值。 +请注意,在第 11 行,我们对返回的交易对象调用了 `.wait()`。 这确保了脚本在退出函数前等待交易在区块链上完成出块。 如果不包含 `.wait()` 调用,脚本可能不会看到合约中更新后的 `message` 值。 ### 读取新消息 {#read-the-new-message} -你可以重复[前面的步骤](#read-the-init-message)来读取更新后的 `message` 值。 花点时间,看看是否可以进行必要的更改以输出新值! +你应该能够重复[前面的步骤](#read-the-init-message)来读取更新后的 `message` 值。 花点时间,看看是否可以进行必要的更改以输出新值! 如果你需要提示,你的 `interact.js` 文件现在应如下所示: @@ -561,12 +564,12 @@ main() `npx hardhat run scripts/interact.js --network goerli` ``` -The message is: Hello World! -Updating the message... -The new message is: This is the new message. +消息是:Hello World! +正在更新消息... +新消息是:This is the new message. ``` -当运行那条脚本时,你可能会发现 `Updating the message...` 步骤需要一段时间才能加载完成,然后再加载新消息。 这是由挖矿过程导致的;如果你希望在对交易进行挖矿的同时追踪交易,可以访问 [Alchemy 内存池](https://dashboard.alchemyapi.io/mempool)查看交易的状态。 如果交易被丢弃,可以访问 [Goerli Etherscan](https://goerli.etherscan.io) 并搜索你的交易哈希值。 +当运行该脚本时,你可能会发现“Updating the message...”步骤需要一段时间才能加载完成,然后再加载新消息。 这是由挖矿过程导致的;如果你希望在对交易进行挖矿的同时追踪交易,可以访问 [Alchemy 内存池](https://dashboard.alchemyapi.io/mempool)查看交易的状态。 如果交易被丢弃,可以访问 [Goerli Etherscan](https://goerli.etherscan.io) 并搜索你的交易哈希值。 ## 第三部分:将你的智能合约发布到 Etherscan {#part-3-publish-your-smart-contract-to-etherscan} @@ -574,19 +577,19 @@ The new message is: This is the new message. 通过在 Etherscan 上验证你的智能合约,任何人都可以查看其源代码,并与智能合约进行交互。 让我们开始吧! -### 步骤 1:在你的 Etherscan 帐户上生成应用程序接口密钥 {#step-1-generate-an-api-key-on-your-etherscan-account} +### 第 1 步:在 Etherscan 帐户中生成 API 密钥 {#step-1-generate-an-api-key-on-your-etherscan-account} -需要 Etherscan 应用程序接口密钥来验证你是否拥有你正在尝试发布的智能合约。 +需要 Etherscan API 密钥来验证你是否拥有你正在尝试发布的智能合约。 -如果你还没有 Etherscan 帐户,[请注册一个帐户](https://etherscan.io/register)。 +如果你还没有 Etherscan 帐户,请[注册一个帐户](https://etherscan.io/register)。 -登录后,在导航栏中找到你的用户名,将鼠标悬停在用户名上,然后选择 **My profile** 按钮。 +登录后,在导航栏中找到你的用户名,将鼠标悬停在用户名上,然后选择“**My profile**”按钮。 -在你的个人资料页面上,应该可以看到一个侧边导航栏。 从侧边导航栏中,选择 **API Key**。 接下来,按“Add”按钮创建一个新的应用程序接口密钥,将你的应用程序命名为 **hello-world**,然后按 **Create New API Key** 按钮。 +在你的个人资料页面上,应该可以看到一个侧边导航栏。 从侧边导航栏中,选择“**API Keys**”。 接下来,按“Add”按钮创建一个新的 API 密钥,将你的应用程序命名为 **hello-world**,然后按“**Create New API Key**”按钮。 -你的新应用程序接口密钥应出现在应用程序接口密钥表中。 将应用程序接口复制到剪贴板。 +你的新 API 密钥应出现在 API 密钥表中。 将 API 复制到剪贴板。 -接下来,我们需要将 Etherscan 应用程序接口添加到 `.env` 文件中。 +接下来,我们需要将 Etherscan API 密钥添加到我们的 `.env` 文件中。 添加完成后,你的 `.env` 文件应如下所示: @@ -598,11 +601,11 @@ CONTRACT_ADDRESS = "your-contract-address" ETHERSCAN_API_KEY = "your-etherscan-key" ``` -### 使用安全帽部署智能合约 {#hardhat-deployed-smart-contracts} +### Hardhat部署的智能合约 {#hardhat-deployed-smart-contracts} #### 安装 hardhat-etherscan {#install-hardhat-etherscan} -使用安全帽将你的合约发布到 Etherscan 非常简单。 首先需要安装 `hardhat-etherscan` 插件。 `hardhat-etherscan` 会在 Etherscan 上自动验证智能合约的源代码和应用程序二进制接口。 为了添加此插件,你需要在 `hello-world` 目录中运行: +使用Hardhat将你的合约发布到 Etherscan 非常简单。 首先需要安装 `hardhat-etherscan` 插件。 `hardhat-etherscan` 会在 Etherscan 上自动验证智能合约的源代码和 ABI。 为了添加此插件,你需要在 `hello-world` 目录中运行: ```text npm install --save-dev @nomiclabs/hardhat-etherscan @@ -630,14 +633,14 @@ module.exports = { }, }, etherscan: { - // Your API key for Etherscan - // Obtain one at https://etherscan.io/ + // Etherscan 的 API 密钥 + // 在 https://etherscan.io/ 获取一个 apiKey: ETHERSCAN_API_KEY, }, } ``` -#### 在 Etherscan 验证你的智能合约 {#verify-your-smart-contract-on-etherscan} +#### 在 Etherscan 上验证你的智能合约 {#verify-your-smart-contract-on-etherscan} 确认所有文件都已保存,且所有 `.env` 变量都已正确配置。 @@ -652,34 +655,34 @@ npx hardhat verify --network goerli DEPLOYED_CONTRACT_ADDRESS 'Hello World!' 如果一切正常,你会在终端中看到以下消息: ```text -Successfully submitted source code for contract +成功提交合约源代码 contracts/HelloWorld.sol:HelloWorld at 0xdeployed-contract-address -for verification on Etherscan. Waiting for verification result... +正在 Etherscan 上验证。等待验证结果... -Successfully verified contract HelloWorld on Etherscan. +在 Etherscan 上成功验证合约 HelloWorld。 https://goerli.etherscan.io/address/#contracts ``` -恭喜! 你的智能合约代码已经在 Etherscan 部署! +恭喜! 你的智能合约代码已在 Etherscan 上! -### 在 Etherscan 查看你的智能合约! {#check-out-your-smart-contract-on-etherscan} +### 在 Etherscan 上查看你的智能合约! {#check-out-your-smart-contract-on-etherscan} -当你进入终端中给出的链接时,你应该会看到你的智能合约代码和应用程序二进制接口已在 Etherscan 上发布! +当你进入终端中给出的链接时,你应该会看到你的智能合约代码和 ABI 已在 Etherscan 上发布! -**哇 - 你成功了! 现在所有人都可以调用或写入你的智能合约! 我们已经等不及看你接下来会做什么了!** +**哇哦 - 你成功了! 现在所有人都可以调用或写入你的智能合约! 我们已经等不及看你接下来会做什么了!** -## 第 4 部分 - 将智能合约与前端集成 {#part-4-integrating-your-smart-contract-with-the-frontend} +## 第四部分 - 将你的智能合约与前端集成 {#part-4-integrating-your-smart-contract-with-the-frontend} 本教程结束时,你将知道如何: - 将 MetaMask 钱包连接到你的去中心化应用程序 -- 使用 [Alchemy Web3](https://docs.alchemy.com/alchemy/documentation/alchemy-web3) 应用程序接口从你的智能合约中读取数据 +- 使用 [Alchemy Web3](https://docs.alchemy.com/alchemy/documentation/alchemy-web3) API 从你的智能合约中读取数据 - 使用 MetaMask 对以太坊交易签名 -对于此去中心化应用程序,我们会使用 [React](https://reactjs.org/) 作为前端框架;然而,需要注意的是,我们不会花很多时间来分解其基本内容,而是会聚焦于将 Web3 功能引入我们的项目。 +对于此去中心化应用程序,我们会使用 [React](https://react.dev/) 作为前端框架;然而,需要注意的是,我们不会花很多时间来分解其基本内容,而是会聚焦于将 Web3 功能引入我们的项目。 -作为前提条件,你需要对 React 有基本的了解。 否则,建议你完成官方的 [React 入门教程](https://reactjs.org/tutorial/tutorial.html)。 +作为前提条件,你需要对 React 有基本的了解。 否则,建议你完成官方的 [React 入门教程](https://react.dev/learn)。 ### 克隆启动文件 {#clone-the-starter-files} @@ -692,13 +695,13 @@ https://goerli.etherscan.io/address/#contracts 下面,用你喜欢的代码编辑器打开 `starter-files`,然后进入 `src` 文件夹。 -我们编写的所有代码都将保存在 `src` 文件夹下。 我们将通过编辑 `HelloWorld.js` 组件并编写 `util/interact.js` JavaScript 文件,为我们的项目提供 Web3 功能。 +我们将编写的所有代码都将存放在 `src` 文件夹下。 我们将编辑 `HelloWorld.js` 组件和 `util/interact.js` JavaScript 文件,为我们的项目提供 Web3 功能。 ### 查看初始文件 {#check-out-the-starter-files} 在我们开始编写之前,让我们看看初始文件为我们提供了什么。 -#### 让你的 react 项目运行起来 {#get-your-react-project-running} +#### 运行你的 React 项目 {#get-your-react-project-running} 首先在浏览器中运行 React 项目。 React 的美妙之处在于,一旦我们的项目在浏览器中运行,保存的任何更改都会在浏览器中实时更新。 @@ -709,21 +712,21 @@ cd starter-files npm install ``` -依赖项安装完成后,在终端运行 `npm start`: +安装完成后,在终端中运行 `npm start`: ```bash npm start ``` -这样做应该会在你的浏览器中打开 [http://localhost:3000/](http://localhost:3000/),在这里你会看到我们项目的前端界面。 它应该包含一个字段 \(一个更新存储在智能合约中的消息的地方\),一个“Connect Wallet”按钮,以及一个“Update”按钮。 +这样做应该会在你的浏览器中打开 [http://localhost:3000/](http://localhost:3000/),在这里你会看到我们项目的前端界面。 它应该包含一个字段(一个更新存储在智能合约中的消息的地方),一个“Connect Wallet”按钮,以及一个“Update”按钮。 -如果你试图点击这些按钮,你会发现它们都不起作用—这是因为我们仍然需要对其功能进行编程。 +如果你试图点击这些按钮,你会发现它们都不起作用——这是因为我们仍然需要对其功能进行编程。 #### `HelloWorld.js` 组件 {#the-helloworld-js-component} 让我们在编辑器中返回 `src` 文件夹并打开 `HelloWorld.js` 文件。 理解该文件中的所有内容非常重要,因为它是我们将要处理的主要 React 组件。 -在该文件开头,你会发现我们有几条 import 语句,这些语句是我们项目运行所必须的,它们包括 React 程序库,useEffect 和 useState 钩子,一些来自 `./util/interact.js` 的项(我们之后还会更详细的说明它们!)以及 Alchemy 徽标。 +在该文件开头,你会发现我们有几条 import 语句,这些语句是我们项目运行所必须的,它们包括 React 库,useEffect 和 useState 钩子,一些来自 `./util/interact.js` 的项(我们之后还会更详细的说明它们!),以及 Alchemy 徽标。 ```javascript // HelloWorld.js @@ -755,10 +758,10 @@ const [newMessage, setNewMessage] = useState("") 以下是每个变量的含义: -- `walletAddress` — 存储用户钱包地址的字符串 -- `status` — 用于存储有用消息,指导用户如何与去中心化应用程序交互的字符串 -- `message` — 存储智能合约中当前消息的字符串 -- `newMessage` — 存储将要写入智能合约中的新消息的字符串 +- `walletAddress` - 存储用户钱包地址的字符串 +- `status`- 用于存储有用消息,指导用户如何与去中心化应用程序交互的字符串 +- `message` - 存储智能合约中当前消息的字符串 +- `newMessage` - 存储将要写入智能合约中的新消息的字符串 在状态变量后,你会发现五个还未实现的函数:`useEffect`、`addSmartContractListener`、`addWalletListener`、`connectWalletPressed` 以及 `onUpdatePressed`。 我们会在下面解释它们的作用: @@ -787,11 +790,11 @@ const onUpdatePressed = async () => { } ``` -- [`useEffect`](https://reactjs.org/docs/hooks-effect.html) — 这是会在你的组件被渲染后调用的 React 钩子。 因为向它传入了一个空的数组 `[]` 属性 \(见第 4 行\),它只会在组件的_第一次_渲染时被调用。 在这里我们会加载智能合约中存储的当前消息,调用智能合约和钱包监听器,并更新用户界面来反映钱包是否已连接。 -- `addSmartContractListener` — 这个函数设置了一个监听器,这个监听器会监视 HelloWorld 合约中的 `UpdatedMessages` 事件,并在智能合约中的消息变化时更新用户界面。 -- `addWalletListener` — 这个函数设置了一个监听器,来检测用户的 MetaMask 钱包的状态变化,比如用户断开他们的钱包或切换钱包地址时。 -- `connectWalletPressed` — 这个函数用于将用户的 MetaMask 钱包连接到我们的去中心化应用程序。 -- `onUpdatePressed` — 这个函数会在用户更新智能合约中存储的消息时被调用。 +- [`useEffect`](https://legacy.reactjs.org/docs/hooks-effect.html) - 这是一个在你的组件渲染后被调用的 React 钩子。 因为向它传入了一个空的数组 `[]` 属性(见第 4 行),它只会在组件的_第一次_渲染时被调用。 在这里我们会加载智能合约中存储的当前消息,调用智能合约和钱包监听器,并更新用户界面来反映钱包是否已连接。 +- `addSmartContractListener` - 这个函数设置了一个监听器,这个监听器会监视 HelloWorld 合约中的 `UpdatedMessages` 事件,并在智能合约中的消息变化时更新用户界面。 +- `addWalletListener` - 这个函数设置了一个监听器,来检测用户的 MetaMask 钱包的状态变化,比如用户断开他们的钱包或切换地址时。 +- `connectWalletPressed` - 这个函数用于将用户的 MetaMask 钱包连接到我们的去中心化应用程序。 +- `onUpdatePressed` - 这个函数会在用户更新智能合约中存储的消息时被调用。 在接近该文件末尾处,我们获得我们组件的用户界面。 @@ -830,16 +833,17 @@ return ( - - + + + ) ``` 如果你细致地检查这段代码,就会发现我们在用户界面中的哪里使用了各种状态变量: -- 在第 6-12 行,如果用户的钱包已连接 \(即 `walletAddress.length > 0`\),我们就在 ID 为“walletButton;”的按钮中显示用户 `walletAddress` 的截短版,否则我们就只显示“连接钱包”。 +- 在第 6-12 行,如果用户的钱包已连接(即 `walletAddress.length > 0`),我们就在 ID 为“walletButton”的按钮中显示用户 `walletAddress` 的截短版;否则我们就只显示“Connect Wallet”。 - 在第 17 行,我们显示在 `message` 字符串中获取的智能合约中存储的当前消息。 -- 在第 23-26 行,我们使用一个[受控组件,](https://reactjs.org/docs/forms.html#controlled-components)以用于在文本字段中输入更改时更新 `newMessage` 状态变量。 +- 在第 23-26 行,我们使用一个[受控组件](https://legacy.reactjs.org/docs/forms.html#controlled-components),以用于在文本字段中输入更改时更新我们的 `newMessage` 状态变量。 除了状态变量之外,你还将看到,在分别单击 ID 为 `publishButton` 和 `walletButton` 的按钮时,会调用 `connectWalletPressed` 和 `onUpdatePressed`。 @@ -851,7 +855,7 @@ return ( #### `interact.js` 文件 {#the-interact-js-file} -因为我们建议采用 [M-V-C](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) 规范,我们需要一个单独的文件包含用来管理我们的去中心化应用程序的逻辑、数据和规则的所有函数,然后我们就能将这些函数导出到前端 \(`HelloWorld.js` 组件\)。 +因为我们建议采用 [M-V-C](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) 规范,我们需要一个单独的文件包含用来管理我们的去中心化应用程序的逻辑、数据和规则的所有函数,然后我们就能将这些函数导出到前端(我们的 `HelloWorld.js` 组件)。 👆🏽这就是 `interact.js` 文件的确切目的! @@ -875,45 +879,45 @@ export const updateMessage = async (message) => {} `helloWorldContract` 对象之后的四个未实现函数会发挥以下作用: -- `loadCurrentMessage` — 这个函数处理加载智能合约中存储的信息的逻辑。 它会使用 [Alchemy Web3 API](https://github.com/alchemyplatform/alchemy-web3),向 Hello World 智能合约发起一个_读取_调用。 -- `connectWallet` — 这个函数会将用户的 MetaMask 连接到我们的去中心化应用程序。 -- `getCurrentWalletConnected` — 这个函数会在页面加载时检查是否已经有以太坊帐户连接到我们的去中心化应用程序,并且相应更新我们的用户界面。 -- `updateMessage` — 这个函数会更新智能合约中存储的消息。 它会向 Hello World 智能合约发起一个_写入_调用,所以用户的 MetaMask 钱包需要签名一个以太坊交易来更新此消息。 +- `loadCurrentMessage` - 这个函数处理加载智能合约中存储的消息的逻辑。 它会使用 [Alchemy Web3 API](https://github.com/alchemyplatform/alchemy-web3),向 Hello World 智能合约发起一个_读取_调用。 +- `connectWallet` - 这个函数会将用户的 MetaMask 连接到我们的去中心化应用程序。 +- `getCurrentWalletConnected` - 这个函数会在页面加载时检查是否已经有以太坊帐户连接到我们的去中心化应用程序,并且相应更新我们的用户界面。 +- `updateMessage` - 这个函数会更新智能合约中存储的消息。 它会向 Hello World 智能合约发起一个_写入_调用,所以用户的 MetaMask 钱包需要签署一个以太坊交易来更新此消息。 现在我们已经了解所操作的对象,让我们看看如何从智能合约中读取吧! -### 第三步:从你的智能合约中读取 {#step-3-read-from-your-smart-contract} +### 第 3 步:从你的智能合约中读取 {#step-3-read-from-your-smart-contract} 为了从智能合约中读取,你需要成功设置以下内容: -- 一个到以太坊链的应用程序接口连接 +- 一个到以太坊链的 API 连接 - 一个已加载的智能合约实例 - 一个用来调用智能合约函数的函数 - 一个监听器,用于监听智能合约中你正读取的数据出现变化时的更新 听起来步骤可能很多,但是不要担心! 我们会引导你逐步完成这些步骤! :\) -#### 建立一个到以太坊链的应用程序接口连接 {#establish-an-api-connection-to-the-ethereum-chain} +#### 建立到以太坊链的 API 连接 {#establish-an-api-connection-to-the-ethereum-chain} -还记得我们在教程的第二部分怎么用我们的 [Alchemy Web3 密钥从我们的智能合约中读取](https://docs.alchemy.com/alchemy/tutorials/hello-world-smart-contract/interacting-with-a-smart-contract#step-1-install-web3-library)吗? 你在去中心化应用程序中也需要一个 Alchemy Web3 密钥来从链上读取。 +还记得在本教程的第 2 部分中,我们是如何使用 [Alchemy Web3 密钥从我们的智能合约中读取](https://docs.alchemy.com/alchemy/tutorials/hello-world-smart-contract/interacting-with-a-smart-contract#step-1-install-web3-library)的吗? 你在去中心化应用程序中也需要一个 Alchemy Web3 密钥来从链上读取。 -如果你还没有提前准备好,首先,我们来安装 [Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3),导航到 `starter-files` 的根目录,然后在你的终端运行以下内容: +如果你还没有,首先安装 [Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3),导航到 `starter-files` 的根目录,然后在你的终端运行以下命令: ```text npm install @alch/alchemy-web3 ``` -[Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3) 是 [Web3.js](https://docs.web3js.org/) 的包装器,提供增强的应用程序接口方法和其他重要优势,让 Web3 开发者的工作更轻松。 它设计成只需经过最少的配置即可使用,因此你可以直接在你的应用程序中开始使用它! +[Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3) 是 [Web3.js](https://docs.web3js.org/) 的包装器,提供增强的 API 方法和其他重要优势,让 Web3 开发者的工作更轻松。 它设计成只需经过最少的配置即可使用,因此你可以直接在你的应用程序中开始使用它! -然后,在你的项目目录中安装 [dotenv](https://www.npmjs.com/package/dotenv) 程序包,我们就有了一个在获取我们应用程序接口密钥后安全存储它的地方。 +然后,在你的项目目录中安装 [dotenv](https://www.npmjs.com/package/dotenv) 程序包,这样我们就有了一个在获取我们 API 密钥后安全存储它的地方。 ```text npm install dotenv --save ``` -对于我们的去中心化应用程序,将不再使用 HTTP 应用程序接口密钥,**而是改用 Websockets 应用程序接口密钥**,因为它会允许我们设置一个监测智能合约中消息变化的监听器。 +对于我们的去中心化应用程序,我们将不再使用 HTTP API 密钥,而是改用 **Websockets API 密钥**,因为它会允许我们设置一个监测智能合约中消息变化的监听器。 -在你获得应用程序接口密钥后,在你的根目录中创建 `.env` 文件,并在其中添加你的 Alchemy Websockets URL。 在这之后,你的 `.env` 文件应该如下所示: +在你获得 API 密钥后,在你的根目录中创建 `.env` 文件,并在其中添加你的 Alchemy Websockets URL。 在这之后,你的 `.env` 文件应该如下所示: ```javascript REACT_APP_ALCHEMY_KEY = wss://eth-goerli.ws.alchemyapi.io/v2/ @@ -938,17 +942,17 @@ const web3 = createAlchemyWeb3(alchemyKey) #### 加载你的 Hello World 智能合约 {#loading-your-hello-world-smart-contract} -要加载你的 Hello World 智能合约,将需要其合约地址和应用程序二进制接口,如果你完成了[这个教程的第三部分](/developers/tutorials/hello-world-smart-contract-fullstack/#part-3-publish-your-smart-contract-to-etherscan-part-3-publish-your-smart-contract-to-etherscan),这两者都可以在 Etherscan 上找到。 +要加载你的 Hello World 智能合约,你需要它的合约地址和 ABI,如果你完成了[本教程的第 3 部分](/developers/tutorials/hello-world-smart-contract-fullstack/#part-3-publish-your-smart-contract-to-etherscan-part-3-publish-your-smart-contract-to-etherscan),这两者都可以在 Etherscan 上找到。 -#### 如何从 Etherscan 获取合约的应用程序二进制接口 {#how-to-get-your-contract-abi-from-etherscan} +#### 如何从 Etherscan 获取你的合约 ABI {#how-to-get-your-contract-abi-from-etherscan} -如果你跳过了这个教程的第三部分,你可以使用 HelloWorld 合约,其地址为 [0x6f3f635A9762B47954229Ea479b4541eAF402A6A](https://goerli.etherscan.io/address/0x6f3f635a9762b47954229ea479b4541eaf402a6a#code)。 它的应用程序二进制接口可在[这里](https://goerli.etherscan.io/address/0x6f3f635a9762b47954229ea479b4541eaf402a6a#code)找到。 +如果你跳过了本教程的第 3 部分,你可以使用地址为 [0x6f3f635A9762B47954229Ea479b4541eAF402A6A](https://goerli.etherscan.io/address/0x6f3f635a9762b47954229ea479b4541eaf402a6a#code) 的 HelloWorld 合约。 其 ABI 可以在[这里](https://goerli.etherscan.io/address/0x6f3f635a9762b47954229ea479b4541eaf402a6a#code)找到。 -在指定合约将要调用的函数,以及确保函数以你期望的格式返回数据时,合约的应用程序二进制接口必不可少。 复制合约应用程序二进制接口后,让我们将其保存到 `src` 目录,保存为文件名为 `contract-abi.json` 的 JSON 文件。 +在指定合约将要调用的函数,以及确保函数以你期望的格式返回数据时,合约的 ABI 必不可少。 复制合约 ABI 后,让我们将其保存到 `src` 目录,保存为文件名为 `contract-abi.json` 的 JSON 文件。 你的 contract-abi.json 文件应存储在 src 文件夹。 -有了合约地址、应用程序二进制接口和 Alchemy Web3 端点,我们就可以使用[合约方法](https://docs.web3js.org/api/web3-eth-contract/class/Contract)来加载智能合约的实例。 将你的合约应用程序二进制接口导入 `interact.js` 文件,然后添加你的合约地址。 +有了合约地址、ABI 和 Alchemy Web3 端点,我们就可以使用[合约方法](https://docs.web3js.org/api/web3-eth-contract/class/Contract)来加载智能合约的实例。 将你的合约 ABI 导入 `interact.js` 文件,然后添加你的合约地址。 ```javascript // interact.js @@ -957,7 +961,7 @@ const contractABI = require("../contract-abi.json") const contractAddress = "0x6f3f635A9762B47954229Ea479b4541eAF402A6A" ``` -现在,我们终于可以删除 `helloWorldContract` 变量的注释,并用 AlchemyWeb3 端点加载智能合约了: +现在,我们终于可以取消 `helloWorldContract` 变量的注释,并用 AlchemyWeb3 端点加载智能合约了: ```javascript // interact.js @@ -988,9 +992,9 @@ export const helloWorldContract = new web3.eth.Contract( 我们现在已经加载了合约,可以实现 `loadCurrentMessage` 函数了! -#### 在 `interact.js` 文件中实现 `loadCurrentMessage` {#implementing-loadCurrentMessage-in-your-interact-js-file} +#### 在你的 `interact.js` 文件中实现 `loadCurrentMessage` {#implementing-loadCurrentMessage-in-your-interact-js-file} -这个函数非常简单。 我们将通过一个简单的异步 Web3 调用来从我们的合约中读取信息。 我们的函数会返回智能合约中存储的消息: +这个函数非常简单。 我们将通过一个简单的异步 web3 调用来从我们的合约中读取信息。 我们的函数会返回智能合约中存储的消息: 将 `interact.js` 文件中的 `loadCurrentMessage` 更新为如下: @@ -1017,17 +1021,17 @@ useEffect(async () => { 注意,我们只希望在组件第一次渲染时调用 `loadCurrentMessage` 函数一次。 我们很快会实现 `addSmartContractListener` 以在智能合约中的消息变化后自动更新用户界面。 -在我们深入研究监听器之前,让我们看看现在已经做了什么! 保存你的 `HelloWorld.js` 和 `interact.js` 文件,然后访问 [http://localhost:3000/](http://localhost:3000/)。 +在我们深入研究监听器之前,让我们看看现在已经做了什么! 保存你的 `HelloWorld.js` 和 `interact.js` 文件,然后访问 [http://localhost:3000/](http://localhost:3000/) 你会发现当前的消息不再是“No connection to the network.” 相反,它反映了智能合约中存储的消息。 酷! -#### 你的用户界面现在应该反映了智能合约中存储的消息 {#your-UI-should-now-reflect-the-message-stored-in-the-smart-contract} +#### 你的用户界面现在应反映智能合约中存储的消息 {#your-UI-should-now-reflect-the-message-stored-in-the-smart-contract} 说到监听器…… #### 实现 `addSmartContractListener` {#implement-addsmartcontractlistener} -回想我们在[这个教程的第 1 部分](https://docs.alchemy.com/alchemy/tutorials/hello-world-smart-contract#step-10-write-our-contract)编写的 `HelloWorld.sol`,你会记得有一个名为 `UpdatedMessages` 的智能合约事件,这是在调用我们的智能合约的 `update` 函数后触发的 \(参见第 9 行和第 27 行\): +回想我们在[本系列教程的第 1 部分](https://docs.alchemy.com/alchemy/tutorials/hello-world-smart-contract#step-10-write-our-contract)中编写的 `HelloWorld.sol` 文件,你会记得有一个名为 `UpdatedMessages` 的智能合约事件,这是在调用我们的智能合约的 `update` 函数后触发的(参见第 9 行和第 27 行): ```javascript // HelloWorld.sol @@ -1037,7 +1041,7 @@ useEffect(async () => { pragma solidity ^0.7.3; // Defines a contract named `HelloWorld`. -// 一个合约是函数和数据(其状态)的集合。 Once deployed, a contract resides at a specific address on the Ethereum blockchain. Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html +// A contract is a collection of functions and data (its state). Once deployed, a contract resides at a specific address on the Ethereum blockchain. Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html contract HelloWorld { //Emitted when update function is called @@ -1045,11 +1049,11 @@ contract HelloWorld { event UpdatedMessages(string oldStr, string newStr); // Declares a state variable `message` of type `string`. - // 状态变量是其值永久存储在合约存储中的变量。 The keyword `public` makes variables accessible from outside a contract and creates a function that other contracts or clients can call to access the value. + // State variables are variables whose values are permanently stored in contract storage. The keyword `public` makes variables accessible from outside a contract and creates a function that other contracts or clients can call to access the value. string public message; // Similar to many class-based object-oriented languages, a constructor is a special function that is only executed upon contract creation. - // 构造器用于初始化合约的数据。 Learn more:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors + // Constructors are used to initialize the contract's data. Learn more:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors constructor(string memory initMessage) { // Accepts a string argument `initMessage` and sets the value into the contract's `message` storage variable). @@ -1065,7 +1069,7 @@ contract HelloWorld { } ``` -智能合约事件是你的合约向你的前端应用程序传达区块链上发生的事情 \(即:有一个_事件_\)的一种方式,你的前端应用程序可以“监听”特定事件,并在事件发生时采取行动。 +智能合约事件是你的合约向你的前端应用程序传达区块链上发生的事情(即:有一个_事件_)的一种方式,你的前端应用程序可以“监听”特定事件,并在事件发生时采取行动。 `addSmartContractListener` 函数将专门监听我们 Hello World 智能合约的 `UpdatedMessages` 事件,并更新用户界面来显示新消息。 @@ -1081,7 +1085,7 @@ function addSmartContractListener() { } else { setMessage(data.returnValues[1]) setNewMessage("") - setStatus("🎉 Your message has been updated!") + setStatus("🎉 你的消息已更新!") } }) } @@ -1092,7 +1096,7 @@ function addSmartContractListener() { - 如果事件触发时出现错误,它将通过我们的 `status` 状态变量反映在用户界面中。 - 反之,我们就可以使用返回的 `data` 对象。 `data.returnValues` 是一个以 0 为起始索引的数组,其中数组的第一个元素保存的是之前的消息,而第二个元素则保存了更新后的新消息。 总体来说,在成功触发事件的情况下,我们会将 `message` 字符串设置为更新后的消息,同时清除 `newMessage` 字符串,并且更新 `status` 状态变量以表明已在智能合约上发布一条新的消息。 -最终,我们应在 `useEffect` 钩子函数中调用这个监听器,确保它在 `HelloWorld.js` 组件初次渲染时即被初始化。 综上所述,我们的 `useEffect` 钩子函数应当如下所示: +最终,我们应在 `useEffect` 函数中调用这个监听器,确保它在 `HelloWorld.js` 组件初次渲染时即被初始化。 综上所述,我们的 `useEffect` 函数应当如下所示: ```javascript // HelloWorld.js @@ -1106,35 +1110,35 @@ useEffect(async () => { 现在我们已经掌握了从智能合约读取消息的方法,那么接下来了解如何向智能合约中写入消息那就太棒了! 然而,要向我们的去中心化应用执行写入,我们首先必须有一个连接到该去中心化应用程序的以太坊钱包。 -接下来,我们将着手设置以太坊钱包 \(MetaMask\),然后将其连接到我们的去中心化应用程序! +接下来,我们将着手设置以太坊钱包(MetaMask),然后将其连接到我们的去中心化应用程序! -### 第四步:设置你的以太坊钱包 {#step-4-set-up-your-ethereum-wallet} +### 第 4 步:设置你的以太坊钱包 {#step-4-set-up-your-ethereum-wallet} -为了向以太坊链上写入任何数据,用户必须使用其虚拟钱包的私钥来签署交易。 在本教程中,我们将使用浏览器中的虚拟钱包 [MetaMask](https://metamask.io/) 来管理你的以太坊帐户地址,因为它让终端用户签署交易变得极其简单。 +为了向以太坊链上写入任何数据,用户必须使用其虚拟钱包的私钥来签署交易。 在本教程中,我们将使用 [MetaMask](https://metamask.io/),这是一个浏览器中的虚拟钱包,用于管理你的以太坊帐户地址,因为它让终端用户签署交易变得极其简单。 -如果你想了解更多关于以太坊交易的运作方式,请查看以太坊基金会的[这个页面](/developers/docs/transactions/)。 +如果你想进一步了解以太坊交易的运作方式,请查看以太坊基金会的[这个页面](/developers/docs/transactions/)。 #### 下载 MetaMask {#download-metamask} -你可以[在这里](https://metamask.io/download)免费下载并创建一个 MetaMask 帐户。 在你创建帐户时,或者如果你已经有帐户,请确保切换到右上角的“Goerli 测试网络”(这样我们就不会使用实际货币进行交易)。 +你可以[在此处](https://metamask.io/download)免费下载和创建 MetaMask 帐户。 在你创建帐户时,或者如果你已经有帐户,请确保切换到右上角的“Goerli 测试网络”(这样我们就不会使用实际货币进行交易)。 -#### 通过水龙头中添加以太币 {#add-ether-from-a-faucet} +#### 通过水龙头获取以太币 {#add-ether-from-a-faucet} -为了在以太坊区块链上签署交易,我们需要一些虚拟以太币。 要获取以太币,你可以前往 [FaucETH](https://fauceth.komputing.org) 并输入你的 Goerli 帐户地址,单击“Request funds”,然后在下拉菜单中选择“Ethereum Testnet Goerli”,最后再次单击“Request funds”按钮。 你应该会很快在你的 MetaMask 帐户中看到以太币! +为了在以太坊区块链上签署交易,我们需要一些虚拟 Eth。 要获取 Eth,你可以前往 [FaucETH](https://fauceth.komputing.org) 并输入你的 Goerli 帐户地址,单击“Request funds”,然后在下拉菜单中选择“Ethereum Testnet Goerli”,最后再次单击“Request funds”按钮。 你应该会很快在你的 MetaMask 帐户中看到以太币! -#### 查看你的余额 {#check-your-balance} +#### 检查你的余额 {#check-your-balance} -为了核查我们帐户中有余额,我们使用 [Alchemy composer 工具](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D)发出 [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) 请求。 这将返回我们钱包中的以太币数量。 输入你的 Metamask 帐户地址并单击“发送请求”后,你应该会看到这样的响应: +为了仔细检查我们的余额,让我们使用 [Alchemy 的 composer 工具](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D) 发出一个 [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) 请求。 这将返回我们钱包中的以太币数量。 输入你的 MetaMask 帐户地址并点击“Send Request”后,你应该会看到这样的响应: ```text {"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"} ``` -**注意:**结果以 wei 为单位,而非 ETH。 Wei is used as the smallest denomination of ether. 从 wei 到 eth 的转换是:1 eth = 10¹⁸ wei。 因此,如果我们将 0xde0b6b3a7640000 转换为十进制,我们会得到 1\*10¹⁸,它等于 1 eth。 +\*\*注意:\*\*此结果以 wei 为单位,而不是 eth。 Wei 是以太币的最小计量单位。 从 wei 到 eth 的转换是:1 eth = 10¹⁸ wei。 因此,如果我们将 0xde0b6b3a7640000 转换为十进制,我们会得到 1\*10¹⁸,它等于 1 eth。 -Phew! 我们的虚拟以太币都在那里了! 🤑 +哦! 我们的虚拟以太币都在那里了! 🤑 -### 第五步:将 MetaMask 连接到你的用户界面 {#step-5-connect-metamask-to-your-UI} +### 第 5 步:将 MetaMask 连接到你的 UI {#step-5-connect-metamask-to-your-UI} 既然我们的 MetaMask 钱包已经设置好了,我们将我们的去中心化应用程序与之连接! @@ -1154,7 +1158,7 @@ export const connectWallet = async () => { method: "eth_requestAccounts", }) const obj = { - status: "👆🏽 Write a message in the text-field above.", + status: "👆🏽 在上面的文本字段中写入一条消息。", address: addressArray[0], } return obj @@ -1172,8 +1176,7 @@ export const connectWallet = async () => {

{" "} 🦊 - You must install MetaMask, a virtual Ethereum wallet, in your - browser. + 你必须在浏览器中安装 MetaMask,一个虚拟的以太坊钱包。

@@ -1187,20 +1190,20 @@ export const connectWallet = async () => { 首先,该函数会检查你的浏览器是否启用了 `window.ethereum`。 -`window.ethereum` 是一个由 MetaMask 和其他钱包提供商注入的全局应用程序接口,它允许网站请求用户的以太坊帐户。 如果被批准,它可以读取用户连接的区块链上的数据,并建议用户签署消息和交易。 参阅 [MetaMask 文档](https://docs.metamask.io/guide/ethereum-provider.html#table-of-contents)了解更多信息! +`window.ethereum` 是由 MetaMask 和其他钱包提供商注入的全局 API,允许网站请求用户的以太坊帐户。 如果被批准,它可以读取用户连接的区块链上的数据,并建议用户签署消息和交易。 有关详细信息,请查看 [MetaMask 文档](https://docs.metamask.io/guide/ethereum-provider.html#table-of-contents)! -如果 `window.ethereum` _ 不存在_,则表示未安装 MetaMask。 这会导致返回一个 JSON 对象,其中返回的 `address` 是一个空字符串,而 `status` JSX 对象指示用户必须安装 MetaMask。 +如果 `window.ethereum` _不_存在,则意味着 MetaMask 未安装。 这将导致返回一个 JSON 对象,其中返回的 `address` 是一个空字符串,而 `status` JSX 对象则会提示用户必须安装 MetaMask。 -现在如果 `window.ethereum` _存在_,那么事情就会变得有趣。 +现在,如果 `window.ethereum` _是_存在的,事情就变得有趣了。 -使用 try/catch 循环,我们将尝试通过调用 [`window.ethereum.request({ method: "eth_requestAccounts" });`](https://docs.metamask.io/guide/rpc-api.html#eth-requestaccounts) 连接到 MetaMask。 调用此函数将在浏览器中打开 MetaMask,提示用户将他们的钱包连接到你的去中心化应用程序。 +使用 try/catch 循环,我们将通过调用 [`window.ethereum.request({ method: \"eth_requestAccounts\" });`](https://docs.metamask.io/guide/rpc-api.html#eth-requestaccounts) 来尝试连接到 MetaMask。 调用此函数将在浏览器中打开 MetaMask,提示用户将他们的钱包连接到你的去中心化应用程序。 -- 如果用户选择连接,`method: "eth_requestAccounts"` 将返回一个数组,其中包含连接到去中心化应用程序的用户的所有帐户地址。 总之,我们的 `connectWallet` 函数将返回一个 JSON 对象,其中包含此数组中的_第一个 _ `address` \(见第 9 行\),并返回一条 `status` 信息,提示用户向智能合约写入信息。 -- 如果用户拒绝连接,则 JSON 对象将包含返回的 `address` 的空字符串和反映用户拒绝连接的 `status` 信息。 +- 如果用户选择连接,`method: "eth_requestAccounts"` 将返回一个数组,其中包含连接到去中心化应用程序的用户的所有帐户地址。 总而言之,我们的 `connectWallet` 函数将返回一个 JSON 对象,其中包含此数组中的_第一个_ `address`(见第 9 行)和一条提示用户向智能合约写入消息的 `status` 消息。 +- 如果用户拒绝连接,则 JSON 对象将包含一个空字符串作为返回的 `address`,以及一条反映用户拒绝连接的 `status` 消息。 现在我们已经编写了这个 `connectWallet` 函数,下一步是调用它到我们的 `HelloWorld.js` 组件中。 -#### 将 `connectWallet` 函数添加到你的 `HelloWorld.js` 用户界面组件中 {#add-the-connectWallet-function-to-your-HelloWorld-js-ui-component} +#### 将 `connectWallet` 函数添加到你的 HelloWorld.js 用户界面组件 {#add-the-connectWallet-function-to-your-HelloWorld-js-ui-component} 导航到 `HelloWorld.js` 文件中的 `connectWalletPressed` 函数,并将其更新为以下内容: @@ -1214,21 +1217,21 @@ const connectWalletPressed = async () => { } ``` -注意我们的大部分函数是如何从 `interact.js` 文件中的 `HelloWorld.js` 组件中抽象出来的? 这就是我们遵守 M-V-C 规范的原因! +注意到我们的大部分功能是如何从 `interact.js` 文件中的 `HelloWorld.js` 组件中抽象出来的吗? 这就是我们遵守 M-V-C 规范的原因! -在 `connectWalletPressed` 中,我们只需对导入的 `connectWallet` 函数进行 await 调用,并使用其响应,通过变量的状态挂钩更新我们的 `status` 和 `walletAddress ` 变量。 +在 `connectWalletPressed` 中,我们只需对导入的 `connectWallet` 函数进行 `await` 调用,并使用其响应通过它们的状态钩子来更新 `status` 和 `walletAddress` 变量。 -现在,让我们保存两个文件 \(`HelloWorld.js` 和 `interact.js`\) ,并测试一下我们目前的用户界面。 +现在,让我们保存两个文件(`HelloWorld.js` 和 `interact.js`),并测试一下我们目前的用户界面。 -打开浏览器,在地址栏中输入 [localhost:3000](http://localhost:3000/),然后按页面右上角的“Connect Wallet”按钮。 +打开浏览器,在地址栏中输入 [http://localhost:3000/](http://localhost:3000/),然后按页面右上角的“Connect Wallet”按钮。 如果你安装了 MetaMask,系统会提示你将钱包连接到去中心化应用程序。 接受邀请并连接。 -你会看到钱包按钮现在反映你的地址已连接! 太棒了 🔥 ! +你会看到钱包按钮现在反映你的地址已连接! 太棒了 🔥! -接下来,尝试刷新页面......有点儿奇怪。 我们的钱包按钮提示我们连接 MetaMask,尽管它已经连接...... +接下来,尝试刷新页面…… 这很奇怪。 我们的钱包按钮提示我们连接 MetaMask,尽管它已经连接...... -然而,不要害怕! 我们可以通过实现 `getCurrentWalletConnected` 轻松解决这个问题(明白了吗?),它将检查一个地址是否已经连接到我们的去中心化应用程序,并相应地更新我们的用户界面! +然而,不要害怕! 我们可以轻松解决这个问题(明白了吗?) 通过实现 `getCurrentWalletConnected`,它将检查一个地址是否已经连接到我们的去中心化应用程序,并相应地更新我们的用户界面! #### `getCurrentWalletConnected` 函数 {#the-getcurrentwalletconnected-function} @@ -1246,12 +1249,12 @@ export const getCurrentWalletConnected = async () => { if (addressArray.length > 0) { return { address: addressArray[0], - status: "👆🏽 Write a message in the text-field above.", + status: "👆🏽 在上面的文本字段中写入一条消息。", } } else { return { address: "", - status: "🦊 Connect to MetaMask using the top right button.", + status: "🦊 使用右上角按钮连接到 MetaMask。", } } } catch (err) { @@ -1268,8 +1271,7 @@ export const getCurrentWalletConnected = async () => {

{" "} 🦊 - You must install MetaMask, a virtual Ethereum wallet, in your - browser. + 你必须在浏览器中安装 MetaMask,一个虚拟的以太坊钱包。

@@ -1279,9 +1281,9 @@ export const getCurrentWalletConnected = async () => { } ``` -这段代码与我们刚刚在上一步中编写的 `connectWallet` 函数 _非常相似_ 。 +这段代码与我们刚刚在上一步中编写的 `connectWallet` 函数非常相似。 -主要区别在于,这里我们调用了 `eth_accounts` 方法,它只是返回一个数组,其中包含当前连接到我们的去中心化应用程序的 MetaMask 地址,而不是调用 `eth_requestAccounts` 方法来打开 MetaMask 以供用户连接他们的钱包。 +主要区别在于,我们这里调用的方法是 `eth_accounts`,它只是返回一个包含当前连接到我们去中心化应用程序的 MetaMask 地址的数组,而不是调用会打开 MetaMask 供用户连接钱包的 `eth_requestAccounts` 方法。 为了看看这个函数在实际应用中的效果,让我们在 `HelloWorld.js` 组件的 `useEffect` 函数中调用它: @@ -1319,10 +1321,10 @@ function addWalletListener() { window.ethereum.on("accountsChanged", (accounts) => { if (accounts.length > 0) { setWallet(accounts[0]) - setStatus("👆🏽 Write a message in the text-field above.") + setStatus("👆🏽 在上面的文本字段中写入一条消息。") } else { setWallet("") - setStatus("🦊 Connect to MetaMask using the top right button.") + setStatus("🦊 使用右上角按钮连接到 MetaMask。") } }) } else { @@ -1330,7 +1332,7 @@ function addWalletListener() {

{" "} 🦊 - You must install MetaMask, a virtual Ethereum wallet, in your browser. + 你必须在浏览器中安装 MetaMask,一个虚拟的以太坊钱包。

) @@ -1340,11 +1342,11 @@ function addWalletListener() { 我敢打赌,到了这一步你可能已经无需我们帮助就能理解这里发生的情况了,但为了确保详尽无遗,我们还是快速梳理一下: -- 首先,我们的函数检查是否启用了 `window.ethereum` \(即 MetaMask 已安装\)。 +- 首先,我们的函数会检查 `window.ethereum` 是否已启用(即 MetaMask 是否已安装)。 - 如果未启用,我们只需将 `status` 状态变量设置为提示用户安装 MetaMask 的 JSX 字符串。 - - 如果启用,我们会在第 3 行设置监听器 `window.ethereum.on("accountsChanged")` 监听 MetaMask 钱包中的状态变化,变化包括用户将其他帐户连接到去中心化应用程序、切换帐户或断开帐户。 如果至少连接了一个帐户,`walletAddress` 状态变量将更新为监听器返回的 `accounts` 数组中的第一个帐户。 否则,`walletAddress` 设置为空字符串。 + - 如果启用,我们会在第 3 行设置监听器 `window.ethereum.on("accountsChanged")` 监听 MetaMask 钱包中的状态变化,变化包括用户将其他帐户连接到去中心化应用程序、切换帐户或断开帐户。 如果至少连接了一个帐户,`walletAddress` 状态变量将更新为监听器返回的 `accounts` 数组中的第一个帐户。 否则,`walletAddress` 将设置为空字符串。 -最后,但同样重要的一点是,我们必须在 `useEffect` 函数中调用它: +最后但同样重要的一点是,我们必须在 `useEffect` 函数中调用它: ```javascript // HelloWorld.js @@ -1362,9 +1364,9 @@ useEffect(async () => { }, []) ``` -就是这样! 我们已经成功完成了所有钱包功能的编程! 现在,我们来完成最后一个任务:更新智能合约中存储的消息! +就这些! 我们已经成功完成了所有钱包功能的编程! 现在,我们来完成最后一个任务:更新智能合约中存储的消息! -### 第六步:实现 `updateMessage` 函数 {#step-6-implement-the-updateMessage-function} +### 第 6 步:实现 `updateMessage` 函数 {#step-6-implement-the-updateMessage-function} 好嘞,伙计们,我们已经来到最后阶段了! 在 `interact.js` 文件中的 `updateMessage` 函数中,我们将执行以下操作: @@ -1378,7 +1380,7 @@ useEffect(async () => { 显然,我们在函数开头加入一些输入错误处理代码是有意义的做法。 -如果未安装 MetaMask 扩展,或者钱包尚未连接 \(即传入的 `address` 为空字符串\),亦或是 `message` 为空字符串,我们希望函数能够提前返回。 让我们在 `updateMessage` 函数中添加以下错误处理代码: +如果未安装 MetaMask 扩展,或者钱包尚未连接(即传入的 `address` 为空字符串),亦或是 `message` 为空字符串,我们希望函数能够提前返回。 让我们在 `updateMessage` 函数中添加以下错误处理代码: ```javascript // interact.js @@ -1387,13 +1389,13 @@ export const updateMessage = async (address, message) => { if (!window.ethereum || address === null) { return { status: - "💡 Connect your MetaMask wallet to update the message on the blockchain.", + "💡 连接你的 MetaMask 钱包以更新区块链上的消息。", } } if (message.trim() === "") { return { - status: "❌ Your message cannot be an empty string.", + status: "❌ 你的消息不能为空字符串。", } } } @@ -1401,7 +1403,7 @@ export const updateMessage = async (address, message) => { 现在,我们已经实现了正确的输入错误处理,接下来就是通过 MetaMask 来签署交易的时候了! -#### 签署交易 {#signing-our-transaction} +#### 签署我们的交易 {#signing-our-transaction} 如果你已经对传统的 web3 以太坊交易驾轻就熟,那么接下来我们要编写的代码将会非常熟悉。 在输入错误处理代码下方,向 `updateMessage` 函数添加以下内容: @@ -1426,11 +1428,10 @@ try { ✅{" "} - View the status of your transaction on Etherscan! + 在 Etherscan 上查看您的交易状态!
- ℹ️ Once the transaction is verified by the network, the message will be - updated automatically. + ℹ️ 一旦交易被网络验证,消息将自动更新。
), } @@ -1443,11 +1444,11 @@ try { 让我们来详细解析下这些代码的工作原理。 首先,我们设置了交易参数,具体内容如下: -- `to` 指定接收者地址\(我们的智能合约\) +- `to` 指定接收者地址(我们的智能合约) - `from` 指定交易的签名者,即我们传入函数的 `address` 变量 -- `data` 包含对我们的“Hello World”智能合约中 `update` 方法的调用,其中将 `message` 字符串变量作为输入 +- `data` 包含对我们的 Hello World 智能合约中 `update` 方法的调用,其中将 `message` 字符串变量作为输入 -接下来,我们进行对 `window.ethereum.request` 进行异步调用,请求 MetaMask 对交易进行签名。 请注意,在第 11 和 12 行中,我们指定了以太坊方法 `eth_sendTransaction`,并传入了我们的 `transactionParameters`。 +接下来,我们进行对 `window.ethereum.request` 进行异步调用,请求 MetaMask 对交易进行签名。 请注意,在第 11 和 12 行中,我们指定了以太坊方法 `eth_sendTransaction` 并传入了我们的 `transactionParameters`。 此时,MetaMask 将在浏览器中打开,并提示用户签署或拒绝交易。 @@ -1464,13 +1465,13 @@ export const updateMessage = async (address, message) => { if (!window.ethereum || address === null) { return { status: - "💡 Connect your MetaMask wallet to update the message on the blockchain.", + "💡 连接你的 MetaMask 钱包以更新区块链上的消息。", } } if (message.trim() === "") { return { - status: "❌ Your message cannot be an empty string.", + status: "❌ 你的消息不能为空字符串。", } } @@ -1492,11 +1493,10 @@ export const updateMessage = async (address, message) => { ✅{" "} - View the status of your transaction on Etherscan! + 在 Etherscan 上查看您的交易状态!
- ℹ️ Once the transaction is verified by the network, the message will - be updated automatically. + ℹ️ 一旦交易被网络验证,消息将自动更新。
), } @@ -1510,7 +1510,7 @@ export const updateMessage = async (address, message) => { 最后但同样重要的是,我们需要将 `updateMessage` 函数与我们的 `HelloWorld.js` 组件进行连接。 -#### 将 `updateMessage` 函数连接到 `HelloWorld.js` 前端 {#connect-updatemessage-to-the-helloworld-js-frontend} +#### 将 `updateMessage` 连接到 `HelloWorld.js` 前端 {#connect-updatemessage-to-the-helloworld-js-frontend} 我们的 `onUpdatePressed` 函数应当通过异步调用导入的 `updateMessage` 函数,并根据交易成功或失败的结果来修改 `status` 状态变量: @@ -1527,12 +1527,12 @@ const onUpdatePressed = async () => { 现在就去测试一下 **Update** 按钮吧! -### 开发你的去中心化应用程序 {#make-your-own-custom-dapp} +### 制作你自己的自定义去中心化应用程序 {#make-your-own-custom-dapp} 哇哦,你成功完成了本教程的全部内容! 回顾一下,你已经学习了如何: - 使用 MetaMask 钱包连接你的去中心化应用程序项目 -- 使用 [Alchemy Web3](https://docs.alchemy.com/alchemy/documentation/alchemy-web3) 应用程序接口从你的智能合约中读取数据 +- 使用 [Alchemy Web3](https://docs.alchemy.com/alchemy/documentation/alchemy-web3) API 从你的智能合约中读取数据 - 使用 MetaMask 对以太坊交易签名 现在,你已经完全掌握本教程中的技能,可以着手开发属于自己的个性化去中心化应用程序项目了! 一如既往,如果你有任何问题,欢迎随时在 [Alchemy Discord](https://discord.gg/gWuC7zB) 频道联系我们寻求帮助。 🧙‍♂️ diff --git a/public/content/translations/zh/developers/tutorials/hello-world-smart-contract/index.md b/public/content/translations/zh/developers/tutorials/hello-world-smart-contract/index.md index 636862577c8..8ae7ddedbc5 100644 --- a/public/content/translations/zh/developers/tutorials/hello-world-smart-contract/index.md +++ b/public/content/translations/zh/developers/tutorials/hello-world-smart-contract/index.md @@ -1,88 +1,84 @@ --- -title: 针对初学者的智能合约指南 -description: 关于编写和部署一个基于以太坊的简单智能合约的入门教程。 +title: "面向初学者的 Hello World 智能合约" +description: "关于在以太坊上编写和部署一个简单智能合约的入门教程。" author: "elanh" -tags: - - "solidity" - - "hardhat" - - "alchemy" - - "智能合约" - - "入门指南" - - "部署" +tags: [ "Solidity", "hardhat", "Alchemy", "智能合同", "部署" ] skill: beginner lang: zh published: 2021-03-31 --- -如果您是区块链开发的初学者,还不知道如何开始,或者您只是想了解怎样部署智能合约并与之进行交互,这篇教程就是为您准备的。 通过使用虚拟钱包 ([MetaMask](https://metamask.io/))、[Solidity](https://docs.soliditylang.org/en/v0.8.0/)、[Hardhat](https://hardhat.org/) 和 [Alchemy](https://alchemyapi.io/eth)(如果您不理解这些名词的含义,不用担心,后续我们会进行解释),我们将演示在 Ropsten 测试网络上创建并部署一个简单的智能合约。 +如果你是区块链开发的初学者,还不知道如何开始,或者你只是想了解怎样部署智能合约并与之进行交互,这篇教程就是为你准备的。 我们将逐步演示如何使用虚拟钱包 [MetaMask](https://metamask.io/)、[Solidity](https://docs.soliditylang.org/en/v0.8.0/)、[Hardhat](https://hardhat.org/) 和 [Alchemy](https://www.alchemy.com/eth) 在 Sepolia 测试网上创建和部署一个简单的智能合约(如果你还不了解这些术语的含义,别担心,我们稍后会解释)。 -在本教程的第 2 部分,我们将学习在智能合约部署后如何与之进行交互,第 3 部分将学习如何在 Etherscan 上发布智能合约。 +在本教程的[第 2 部分](https://docs.alchemy.com/docs/interacting-with-a-smart-contract)中,我们将介绍如何在部署智能合约后与其进行交互;在[第 3 部分](https://www.alchemy.com/docs/submitting-your-smart-contract-to-etherscan)中,我们将介绍如何在 Etherscan 上发布它。 -如果您有任何问题,请随时在 [Alchemy Discord](https://discord.gg/gWuC7zB) 中提出! +如果你在任何时候有任何问题,请随时在 [Alchemy Discord](https://discord.gg/gWuC7zB) 中提出! -## 步骤 1:连接到以太坊网络 {#step-1} +## 第 1 步:连接到以太坊网络 {#step-1} -有多种方法可以向以太坊链发起连接请求。 为了简单起见,我们将使用一个 Alchemy 上的免费帐户。 Alchemy 是一个区块链开发者平台和 API,允许我们与以太坊进行通信,而无需运行我们自己的节点。 平台还有用于监测和分析的开发者工具,我们将在本教程中利用这些工具来了解我们智能合约部署中的情况。 如果您还没有 Alchemy 账户,[您可以在这里免费注册](https://dashboard.alchemyapi.io/signup)。 +有很多方法可以向以太坊链发送请求。 为简单起见,我们将使用 Alchemy 上的免费帐户,这是一个区块链开发者平台和应用程序接口 (API),它允许我们与以太坊链通信,而无需运行自己的节点。 该平台还有用于监控和分析的开发者工具,我们将在本教程中利用这些工具来了解智能合约部署的内部工作原理。 如果你还没有 Alchemy 帐户,[可在此处免费注册](https://dashboard.alchemy.com/signup)。 -## 步骤 2:创建应用程序(和应用程序接口密钥) {#step-2} +## 第 2 步:创建你的应用程序(和 API 密钥) {#step-2} -创建 Alchemy 帐户后,您可以通过创建应用程序来生成应用程序接口密钥。 我们可以用它向 Ropsten 测试网发出请求。 如果您不熟悉测试网络,请查看[此页面](/developers/docs/networks/)。 +创建 Alchemy 帐户后,你可以通过创建应用程序来生成应用程序接口密钥。 这将使我们能够向 Sepolia 测试网络发出请求。 如果你不熟悉测试网,请查看[此页面](/developers/docs/networks/)。 -1. 在 Alchemy 仪表板中,将鼠标悬停在导航栏中的“应用程序”上,单击“创建应用程序”并前往此页面。 +1. 在 Alchemy 仪表板中,通过在导航栏中选择“Select an app”,然后点击“Create new app”,导航到“Create new app”页面。 -![创建应用程序 Hello world](./hello-world-create-app.png) +![Hello world 创建应用程序](./hello-world-create-app.png) -2. 将您的应用命名为“Hello World”,提供简短的描述,选择“Staging”作为环境(用于您的应用程序簿记),选择“Ropsten”网络。 +2. 将你的应用程序命名为“Hello World”,提供简短描述,并选择一个用例,例如“Infra & Tooling”。 接下来,搜索“Ethereum”并选择网络。 ![创建应用程序视图 hello world](./create-app-view-hello-world.png) -3. 点击“Create app”,完成! 您的应用程序应该就会出现在下面的表格中。 +3. 点击“Next”继续,然后点击“Create app”,就完成了! 你的应用程序应出现在导航栏下拉菜单中,并提供可供复制的 API 密钥。 -## 步骤 3:创建一个以太坊账户(地址) {#step-3} +## 第 3 步:创建以太坊帐户(地址) {#step-3} -我们需要一个以太坊帐户来发送和接收交易。 在本教程中,我们将使用 MetaMask,它是浏览器中的虚拟钱包,用来管理您的以太坊账户地址。 关于[交易](/developers/docs/transactions/)的详细信息。 +我们需要一个以太坊帐户来发送和接收交易。 在本教程中,我们将使用 MetaMask,它是浏览器中的虚拟钱包,用来管理你的以太坊帐户地址。 更多关于[交易](/developers/docs/transactions/)的信息。 -您可以点击[此处](https://metamask.io/download)免费下载并创建一个 MetaMask 账户。 创建账户时,或者如果您已经有一个账户时,确保切换到右上方的“Ropsten 测试网络”(这样我们就不会用实际货币进行交易)。 +你可以在[此处](https://metamask.io/download)免费下载 MetaMask 并创建以太坊帐户。 创建帐户时,或者如果你已有帐户,请确保使用网络下拉菜单切换到“Sepolia”测试网(这样我们就不会处理真实货币)。 -![metask ropsten 示例](./metamask-ropsten-example.png) +如果你没有看到 Sepolia 列出,请进入菜单,然后进入 Advanced,向下滚动以打开“Show test networks”。 在网络选择菜单中,选择“Custom”选项卡,找到测试网列表并选择“Sepolia”。 -## 步骤 4:从水龙头添加以太币 {#step-4} +![metamask sepolia 示例](./metamask-sepolia-example.png) -为了将我们的智能合约部署到测试网络,我们需要一些虚拟以太币。 要获取以太币,您可以转到 [Ropsten 水龙头](https://faucet.dimensions.network/)并输入您的 Ropsten 帐户地址,然后点击“Send Ropsten Eth”。 由于网络原因,您接收虚拟以太币可能需要一些时间。 您应该会很快在您的 MetaMask 帐户中看到以太币! +## 第 4 步:从水龙头获取以太币 {#step-4} -## 步骤 5:查看账户余额 {#step-5} +为了将我们的智能合约部署到测试网,我们需要一些假的 Eth。 要获取 Sepolia ETH,你可以访问 [Sepolia 网络详情](/developers/docs/networks/#sepolia)页面查看各种水龙头列表。 如果一个不能用,就试试另一个,因为它们有时会枯竭。 由于网络拥堵,收到你的假 ETH 可能需要一些时间。 之后不久,你应该就能在你的 Metamask 帐户中看到 ETH 了! -为了核查我们账户中有余额,我们使用 [Alchemy composer 工具](https://composer.alchemyapi.io?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D)发出 [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) 请求。 这将返回我们钱包中的以太币数量。 输入您的 MetaMask 帐户地址并点击“Send Request”后,您应该会看到这样的响应: +## 第 5 步:检查你的余额 {#step-5} + +为了再次检查我们的余额,让我们使用 [Alchemy 的编辑器工具](https://sandbox.alchemy.com/?network=ETH_SEPOLIA&method=eth_getBalance&body.id=1&body.jsonrpc=2.0&body.method=eth_getBalance&body.params%5B0%5D=&body.params%5B1%5D=latest) 发出 [eth_getBalance](/developers/docs/apis/json-rpc/#eth_getbalance) 请求。 这将返回我们钱包中的以太币数量。 输入你的 MetaMask 帐户地址并点击“Send Request”后,你应该会看到这样的响应: ```json { "jsonrpc": "2.0", "id": 0, "result": "0x2B5E3AF16B1880000" } ``` -> **注意:**结果以 wei 为单位,而非 ETH。 Wei 是以太币的最小计量单位。 将 wei 转换为 ETH 的公式为:1 eth = 1018 wei。 因此,如果我们将 0x2B5E3AF16B1880000 转换为十进制,我们会得到 5\*10¹⁸,即 5 ETH。 +> \*\*注意:\*\*这个结果以 wei 为单位,而不是 ETH。 Wei 是以太币的最小计量单位。 wei 到 ETH 的换算方法是:1 eth = 1018 wei。 所以,如果我们将 0x2B5E3AF16B1880000 转换为十进制,我们会得到 5\*10¹⁸,即 5 ETH。 > -> 哦! 我们的虚拟货币到账了。 +> 哦! 我们的假钱都到账了 。 -## 步骤 6:初始化我们的项目 {#step-6} +## 第 6 步:初始化我们的项目 {#step-6} -首先,需要为我们的项目创建一个文件夹。 导航到您的命令行,然后输入: +首先,需要为我们的项目创建一个文件夹。 导航到你的命令行,然后输入: ``` mkdir hello-world cd hello-world ``` -现在我们进入了项目文件夹,我们将使用 `npm init` 来初始化项目。 如果你尚未安装 npm,请遵循[这些说明](https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm)(我们还需要 Node.js,所以请一并下载!)。 +现在我们进入了项目文件夹,我们将使用 `npm init` 来初始化项目。 如果你还没有安装 npm,请遵循[这些说明](https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm)(我们还需要 Node.js,所以也请下载它!)。 ``` npm init ``` -如何回答安装中的问题并不重要,以下提供一个回答的样例供参考: +如何回答安装问题并不重要,下面是我们的做法,仅供参考: ``` package name: (hello-world) version: (1.0.0) -description: hello world smart contract +description: hello world 智能合约 entry point: (index.js) test command: git repository: @@ -94,21 +90,21 @@ About to write to /Users/.../.../.../hello-world/package.json: { "name": "hello-world", "version": "1.0.0", - "description": "hello world smart contract", + "description": "hello world 智能合约", "main": "index.js", "scripts": { - "test": "echo \\"Error: no test specified\\" && exit 1" + "test": "echo \"Error: no test specified\\" && exit 1" }, "author": "", "license": "ISC" } ``` -批准 package.json,我们就可以进行下一步了! +批准 package.json,我们就可以继续了! -## 步骤 7:[Hardhat](https://hardhat.org/getting-started/#overview){#step-7} +## 第 7 步:下载 [Hardhat](https://hardhat.org/getting-started/#overview) {#step-7} -安全帽是一个用于编译、部署、测试和调试以太坊软件的开发环境。 它帮助开发者在本地构建智能合约和去中心化应用程序并部署到实时链上。 +Hardhat是一个用于编译、部署、测试和调试以太坊软件的开发环境。 它帮助开发者在本地构建智能合约和去中心化应用程序并部署到实时链上。 在我们的 `hello-world` 项目中运行: @@ -116,9 +112,9 @@ About to write to /Users/.../.../.../hello-world/package.json: npm install --save-dev hardhat ``` -查看此页面,了解更多有关[安装说明](https://hardhat.org/getting-started/#overview)的详细信息。 +请查看此页面,详细了解[安装说明](https://hardhat.org/getting-started/#overview)。 -## 步骤 8:创建安全帽项目 {#step-8} +## 第 8 步:创建 Hardhat 项目 {#step-8} 在我们的项目文件夹中运行: @@ -126,7 +122,7 @@ npm install --save-dev hardhat npx hardhat ``` -然后应该能看到一条欢迎消息和选项,用于选择您想要做的事情。 选择“创建一个空的 hardhat.config.js”: +然后应该能看到一条欢迎消息和选项,用于选择你想要做的事情。 选择“创建一个空的 hardhat.config.js”: ``` 888 888 888 888 888 @@ -138,74 +134,74 @@ npx hardhat 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. 888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 -👷 Welcome to Hardhat v2.0.11 👷‍? +👷 欢迎来到 Hardhat v2.0.11 👷‍ -What do you want to do? … -Create a sample project -❯ Create an empty hardhat.config.js -Quit +您想做什么?… +创建一个示例项目 +❯ 创建一个空的 hardhat.config.js +退出 ``` -这将生成一个 `hardhat.config.js` 文件,我们将用以配置项目的所有设置(步骤 13)。 +这会为我们生成一个 `hardhat.config.js` 文件,我们将在其中指定我们项目的所有设置(在第 13 步中)。 -## 步骤 9:添加项目文件夹 {#step-9} +## 第 9 步:添加项目文件夹 {#step-9} -为了使我们的项目有条理,我们将创建两个新的文件夹。 在您的命令行中导航到项目的根目录,然后输入: +为了让我们的项目井井有条,我们将创建两个新文件夹。 在你的命令行中导航到项目的根目录,然后输入: ``` mkdir contracts mkdir scripts ``` -- `contracts/` 是保存我们的 hello world 智能合约代码文件的位置 -- `scripts/` 是我们存放脚本的位置,用于部署我们的合约和与之交互。 +- `contracts/` 是我们存放 hello world 智能合约代码文件的地方 +- `scripts/` 是我们存放部署和交互合约脚本的地方 -## 步骤 10:编写合约 {#step-10} +## 第 10 步:编写我们的合约 {#step-10} -您可能要问自己,天啊,到底什么时候才能写代码?? 答案是,就是现在,步骤 10。 +你可能会问自己,我们到底什么时候才开始写代码? 好了,现在就是第 10 步。 -在您最喜欢的编辑器中打开 hello-world 项目(我们喜欢的是 [VSCode](https://code.visualstudio.com/))。 智能合约是用一种叫 Solidity 的语言编写的,我们将用它来编写我们的 HelloWorld.sol 智能合约。 +在你喜欢的编辑器中打开 hello-world 项目(我们喜欢 [VSCode](https://code.visualstudio.com/))。 智能合约是用一种名为 Solidity 的语言编写的,我们将用它来编写 HelloWorld.sol 智能合约。‌ -1. 导航到“contracts”文件夹并创建一个名为 HelloWorld.sol 的新文件 -2. 下面是我们将用于本教程的来自以太坊基金会的 Hello World 智能合约样例。 复制下面的内容并粘贴到 HelloWorld.sol 文件,并一定要阅读注释以了解该合约的工作内容: +1. 导航到“contracts”文件夹并创建一个名为 HelloWorld.sol 的新文件 +2. 下面是以太坊基金会提供的一个 Hello World 智能合约示例,我们将在本教程中使用它。 将以下内容复制并粘贴到你的 HelloWorld.sol 文件中,并务必阅读注释以了解此合约的作用: ```solidity -// Specifies the version of Solidity, using semantic versioning. -// Learn more: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma +// 指定 Solidity 版本,使用语义化版本。 +// 了解更多:https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma pragma solidity ^0.7.0; -// Defines a contract named `HelloWorld`. -// 一个合约是函数和数据(其状态)的集合。 Once deployed, a contract resides at a specific address on the Ethereum blockchain. Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html +// 定义一个名为 `HelloWorld` 的合约。 +// 合约是函数和数据(其状态)的集合。部署后,合约位于以太坊区块链上的一个特定地址。了解更多:https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html contract HelloWorld { - // Declares a state variable `message` of type `string`. - // 状态变量是其值永久存储在合约存储中的变量。 The keyword `public` makes variables accessible from outside a contract and creates a function that other contracts or clients can call to access the value. + // 声明一个 `string` 类型的状态变量 `message`。 + // 状态变量是其值永久存储在合约存储中的变量。关键字 `public` 使变量可以从合约外部访问,并创建一个其他合约或客户端可以调用以访问该值的函数。 string public message; - // Similar to many class-based object-oriented languages, a constructor is a special function that is only executed upon contract creation. - // 构造器用于初始化合约的数据。 Learn more:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors + // 与许多基于类的面向对象语言类似,构造函数是一个特殊函数,仅在创建合约时执行。 + // 构造函数用于初始化合约的数据。了解更多:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors constructor(string memory initMessage) { - // Accepts a string argument `initMessage` and sets the value into the contract's `message` storage variable). + // 接受一个字符串参数 `initMessage`,并将其值设置到合约的 `message` 存储变量中)。 message = initMessage; } - // A public function that accepts a string argument and updates the `message` storage variable. + // 一个公共函数,接受一个字符串参数并更新 `message` 存储变量。 function update(string memory newMessage) public { message = newMessage; } } ``` -这是一个非常简单的智能合约,创建时存储了一条消息,而且可以通过调用 `update` 功能来更新消息。 +这是一个非常简单的智能合约,它在创建时存储一条消息,并可以通过调用 `update` 函数进行更新。 -## 步骤 11:将 MetaMask 和 Alchemy 连接至您的项目 {#step-11} +## 第 11 步:将 MetaMask 和 Alchemy 连接到你的项目 {#step-11} -我们创建了 MetaMask 钱包、Alchemy 帐户,并且编写了一个智能合约,现在是将这三者连起来的时候了。 +我们已经创建了 MetaMask 钱包、Alchemy 帐户并编写了智能合约,现在是时候将这三者连接起来了。 -从虚拟钱包发送的每笔交易都需要使用您独有的私钥签名。 为了给程序提供此项许可,我们可以安全地将私钥(和 Alchemy 应用程序接口密钥)存储在一个环境文件中。 +从虚拟钱包发送的每笔交易都需要使用你独有的私钥签名。 为了给程序提供此项许可,我们可以安全地将私钥(和 Alchemy 应用程序接口密钥)存储在一个环境文件中。 -> 如需了解更多关于发送交易的信息,请查看关于使用 web3 发送交易的 [本教程](/developers/tutorials/sending-transactions-using-web3-and-alchemy/)。 +> 要了解有关发送交易的更多信息,请查看这篇关于使用 web3 发送交易的[教程](/developers/tutorials/sending-transactions-using-web3-and-alchemy/)。 首先,在项目目录中安装 dotenv 软件包: @@ -213,51 +209,51 @@ contract HelloWorld { npm install dotenv --save ``` -然后在我们的项目根目录中创建 `.env` 文件,并将您的 MetaMask 私钥和超文本传输协议 Alchemy 应用程序接口网址加入其中。 +然后,在项目根目录中创建一个 `.env` 文件,并将你的 MetaMask 私钥和 HTTP Alchemy API URL 添加进去。 -- 遵循[这些说明](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key)导出您的私钥 -- 请从下方获取超文本传输协议 Alchemy 应用程序接口网址 +- 按照[这些说明](https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/)导出你的私钥 +- 请参阅下文以获取 HTTP Alchemy API URL -![获取 alchemy 应用程序接口密钥](./get-alchemy-api-key.gif) +![获取 alchemy api 密钥](./get-alchemy-api-key.png) -复制 Alchemy 应用程序接口网址 +复制 Alchemy API URL -您的 `.env` 文件应该类似: +你的 `.env` 文件应如下所示: ``` -API_URL = "https://eth-ropsten.alchemyapi.io/v2/your-api-key" +API_URL = "https://eth-sepolia.g.alchemy.com/v2/your-api-key" PRIVATE_KEY = "your-metamask-private-key" ``` -为了将这些变量和代码连接,我们将在步骤 13 中调用 `hardhat.config.js` 文件中的这些变量。 +为了真正将它们连接到我们的代码,我们将在第 13 步的 `hardhat.config.js` 文件中引用这些变量。 -不要提交 .env! 请确保永远不要与任何人共享或公开您的 .env 文件,因为这样做会泄露您的私钥。 如果您使用版本控制,请将您的 .env 添加到 gitignore 文件中。 +不要提交 .env! 请确保永远不要与任何人共享或公开你的 .env 文件,因为这样做会泄露你的机密信息。 如果你使用版本控制,请将你的 .env 添加到 gitignore 文件中。 -## 步骤 12:安装 Ethers.js {#step-12-install-ethersjs} +## 第 12 步:安装 Ethers.js {#step-12-install-ethersjs} -Ethers.js 是一个软件库,通过以更加方便用户的方法打包[标准 JSON RPC 方法](/developers/docs/apis/json-rpc/),从而更容易与以太坊互动,并向以太坊提出请求。 +Ethers.js 是一个程序库,它通过将[标准的 JSON-RPC 方法](/developers/docs/apis/json-rpc/)封装成对用户更友好的方法,使得与以太坊交互和发出请求变得更加容易。 -安全帽使我们更容易将[插件](https://hardhat.org/plugins/)集成到工具和扩展功能中。 我们将利用 [Ethers 插件](https://hardhat.org/docs/plugins/official-plugins#hardhat-ethers)完成合约部署([Ethers.js](https://github.com/ethers-io/ethers.js/) 有非常简洁的部署方法)。 +Hardhat可以非常轻松地集成[插件](https://hardhat.org/plugins/),以获得额外的工具和扩展功能。 我们将利用 [Ethers 插件](https://hardhat.org/docs/plugins/official-plugins#hardhat-ethers)进行合约部署([Ethers.js](https://github.com/ethers-io/ethers.js/) 有一些非常简洁的合约部署方法)。 -在您的项目目录中输入: +在你的项目目录中输入: ``` npm install --save-dev @nomiclabs/hardhat-ethers "ethers@^5.0.0" ``` -下一步中,我们还将在 `hardhat.config.js` 中使用 ethers。 +我们还将在下一步的 `hardhat.config.js` 中要求 ethers。 -## 步骤 13:更新 hardhat.config.js {#step-13-update-hardhatconfigjs} +## 第 13 步:更新 hardhat.config.js {#step-13-update-hardhatconfigjs} -到目前为止,我们已经添加了几个依赖库和插件,现在我们需要更新 `hardhat.config.js`,以便项目使用所有这些新的组件。 +到目前为止,我们已经添加了几个依赖项和插件,现在我们需要更新 `hardhat.config.js`,以便我们的项目了解所有这些依赖项和插件。 -按如下所示更新您的 `hardhat.config.js` 代码: +将你的 `hardhat.config.js` 更新为如下所示: ``` require('dotenv').config(); @@ -270,10 +266,10 @@ const { API_URL, PRIVATE_KEY } = process.env; */ module.exports = { solidity: "0.7.3", - defaultNetwork: "ropsten", + defaultNetwork: "sepolia", networks: { hardhat: {}, - ropsten: { + sepolia: { url: API_URL, accounts: [`0x${PRIVATE_KEY}`] } @@ -281,9 +277,9 @@ module.exports = { } ``` -## 步骤 14:编译合约 {#step-14-compile-our-contracts} +## 第 14 步:编译我们的合约 {#step-14-compile-our-contracts} -为了确保一切正常,我们来编译一下合约。 `compile` 任务是安全帽的内部任务之一。 +为了确保一切正常,我们来编译一下合约。 `compile` 任务是内置的 hardhat 任务之一。 在命令行中运行: @@ -291,21 +287,21 @@ module.exports = { npx hardhat compile ``` -您可能会看到关于 `SPDX license identifier not provided in source file` 的警告,但不用担心,希望其它的均看起来正常! 如果遇到问题,您可以随时在 [Alchemy cord](https://discord.gg/u72VCg3) 社区中发消息询问。 +你可能会收到关于 `SPDX license identifier not provided in source file` 的警告,但不必担心——希望其他一切都正常! 如果编译不成功,可以随时在 [Alchemy discord](https://discord.gg/u72VCg3) 中发消息。 -## 步骤 15:编写部署脚本 {#step-15-write-our-deploy-scripts} +## 第 15 步:编写我们的部署脚本 {#step-15-write-our-deploy-scripts} 合约已经写完,配置文件也准备妥当,现在是写合约部署脚本的时候了。 -转到 `scripts/` 文件夹,创建一个名为 `deploy.js` 的新文件,在其中添加以下内容: +导航到 `scripts/` 文件夹并创建一个名为 `deploy.js` 的新文件,向其中添加以下内容: ``` async function main() { const HelloWorld = await ethers.getContractFactory("HelloWorld"); - // Start deployment, returning a promise that resolves to a contract object + // 开始部署,返回一个解析为合约对象的 promise const hello_world = await HelloWorld.deploy("Hello World!"); - console.log("Contract deployed to address:", hello_world.address);} + console.log("合约已部署到地址:", hello_world.address);} main() .then(() => process.exit(0)) @@ -315,48 +311,49 @@ main() }); ``` -安全帽在[合约教程](https://hardhat.org/tutorial/testing-contracts.html#writing-tests)中对这些代码的每一行均提供了很好的解释,我们在这里直接引用他们的解释。 +Hardhat在他们的[合约教程](https://hardhat.org/tutorial/testing-contracts.html#writing-tests)中极好地解释了每一行代码的作用,我们在此处采用了他们的解释。 ``` const HelloWorld = await ethers.getContractFactory("HelloWorld"); ``` -ethers.js 中的 `ContractFactory` 是用于部署新智能合约的抽象对象。因此这里的 `HelloWorld` 是我们 hello world 合约实例的工厂。 使用 `hardhat-ethers` 插件时,`ContractFactory` 和 `Contract` 实例默认与第一个签名账户相连。 +ethers.js 中的 `ContractFactory` 是一个用于部署新智能合约的抽象,所以这里的 `HelloWorld` 是我们的 hello world 合约实例的工厂。 使用 `hardhat-ethers` 插件时,`ContractFactory` 和 `Contract` 实例默认连接到第一个签名者。 ``` const hello_world = await HelloWorld.deploy(); ``` -调用 `ContractFactory` 代码中的 `deploy()` 函数会启动合约部署,然后返回解析为 `Contract` 的 `Promise`。 这个对象包括我们智能合约中每个函数的对应调用方法。 +在 `ContractFactory` 上调用 `deploy()` 将开始部署,并返回一个解析为 `Contract` 的 `Promise`。 这个对象包括我们智能合约中每个函数的对应调用方法。 -## 步骤 16:部署合约 {#step-16-deploy-our-contract} +## 第 16 步:部署我们的合约 {#step-16-deploy-our-contract} -我们终于准备好部署我们的智能合约啦! 导航到命令行后运行: +我们终于准备好部署我们的智能合约啦! 导航到命令行并运行: ``` -npx hardhat run scripts/deploy.js --network ropsten +npx hardhat run scripts/deploy.js --network sepolia ``` -您会看到类似以下所示的信息: +你会看到类似以下所示的信息: ``` -Contract deployed to address: 0x6cd7d44516a20882cEa2DE9f205bF401c0d23570 +合约已部署到地址:0x6cd7d44516a20882cEa2DE9f205bF401c0d23570 ``` -如果我们访问 [Ropsten etherscan](https://ropsten.etherscan.io/) 并搜索我们的合约地址,应该能够看到它已经成功部署。 交易将类似以下: +如果我们访问 [Sepolia etherscan](https://sepolia.etherscan.io/) 并搜索我们的合约地址,我们应该能看到它已成功部署。 交易将类似以下: ![etherscan 合约](./etherscan-contract.png) -`From` 地址应该和您的 MetaMask 账户地址相同,而 To 地址会显示“Contract Creation”,但如果我们点击进入交易,我们会在 `To` 字段看到我们的合约地址: +`From` 地址应与你的 MetaMask 帐户地址匹配,而 To 地址将显示“Contract Creation”,但如果我们点击进入交易,我们将在 `To` 字段中看到我们的合约地址: ![etherscan 交易](./etherscan-transaction.png) -恭喜! 您刚刚在以太坊区块链上部署了一个智能合约 🎉 +恭喜! 你刚刚向以太坊链部署了一个智能合约 🎉 -为了更深入了解到底发生了什么,我们转到 [Alchemy 仪表板](https://dashboard.alchemyapi.io/explorer)中的 Explorer 选项卡。 如果您有多个 Alchemy 应用程序,请确保按应用程序筛选,然后选择“Hello World”。 ![hello world 浏览器](./hello-world-explorer.png) +要了解其内部工作原理,我们导航至 [Alchemy 仪表板](https://dashboard.alchemyapi.io/explorer)中的“浏览器”选项卡。 如果你有多个 Alchemy 应用程序,请确保按应用程序筛选并选择“Hello World”。 +![hello world 浏览器](./hello-world-explorer.png) -在这里您会看到一系列的 JSON-RPC 调用,都是在我们调用 `.deploy()` 函数时,Hardhat/Ethers 替我们在后端完成的。 这里有两项重要调用,一个是 [`eth_sendRawTransaction`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_sendrawtransaction),这是实际将我们的合约写入 Ropsten 链的请求,另一个是 [`eth_getTransactionByHash`](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_gettransactionbyhash),此为读取有关我们交易给定哈希值的请求(即 交易时的典型模式)。 如需了解更多关于发送交易的信息,请查看关于[使用 Web3 发送交易](/developers/tutorials/sending-transactions-using-web3-and-alchemy/)的本教程 +在这里,你会看到当我们调用 `.deploy()` 函数时,Hardhat/Ethers 在后台为我们进行的一些 JSON-RPC 调用。 这里需要指出的两个重要调用是 [`eth_sendRawTransaction`](https://www.alchemy.com/docs/node/abstract/abstract-api-endpoints/eth-send-raw-transaction),这是将我们的合约实际写入 Sepolia 链的请求;以及 [`eth_getTransactionByHash`](https://www.alchemy.com/docs/node/abstract/abstract-api-endpoints/eth-get-transaction-by-hash),这是一个根据哈希读取交易信息的请求(处理交易时的典型模式)。 要了解有关发送交易的更多信息,请查看本教程:[使用 Web3 发送交易](/developers/tutorials/sending-transactions-using-web3-and-alchemy/) -这是本教程第 1 部分的全部内容,在第 2 部分中,我们将更新我们的初始信息,从而[与我们的智能合约交互](https://docs.alchemyapi.io/alchemy/tutorials/hello-world-smart-contract#part-2-interact-with-your-smart-contract);在第 3 部分,我们将[在 Etherscan 上发布我们的智能合约](https://docs.alchemyapi.io/alchemy/tutorials/hello-world-smart-contract#optional-part-3-publish-your-smart-contract-to-etherscan),使得每个人都会知道如何与之交互。 +本教程的第 1 部分到此结束,在第 2 部分中,我们将通过更新初始消息来实际[与我们的智能合约进行交互](https://www.alchemy.com/docs/interacting-with-a-smart-contract);在第 3 部分中,我们将[把我们的智能合约发布到 Etherscan](https://www.alchemy.com/docs/submitting-your-smart-contract-to-etherscan),这样每个人都知道如何与它交互。 -**想了解更多有关 Alchemy 的信息吗? 查看我们的[网站](https://alchemyapi.io/eth)。 不想错过更新? [在这里](https://www.alchemyapi.io/newsletter)订阅我们的新闻通讯! 请务必关注我们的 [Twitter](https://twitter.com/alchemyplatform) 并加入我们的 [Discord](https://discord.com/invite/u72VCg3)**。 +**想了解更多关于 Alchemy 的信息吗? 请访问我们的[网站](https://www.alchemy.com/eth)。 不想错过任何更新? 在此[订阅](https://www.alchemy.com/newsletter)我们的新闻通讯! 也请务必加入我们的 [Discord](https://discord.gg/u72VCg3)。**。 diff --git a/public/content/translations/zh/developers/tutorials/how-to-implement-an-erc721-market/index.md b/public/content/translations/zh/developers/tutorials/how-to-implement-an-erc721-market/index.md index 1e2498d5bfe..788b2cff919 100644 --- a/public/content/translations/zh/developers/tutorials/how-to-implement-an-erc721-market/index.md +++ b/public/content/translations/zh/developers/tutorials/how-to-implement-an-erc721-market/index.md @@ -1,12 +1,8 @@ --- -title: 如何实现ERC-721市场 -description: 如何在一个去中心化的分类信息板上销售代币化的物品。 -author: "Alberto Cuesta Cañada" -tags: - - "智能合约" - - "erc-721" - - "solidity" - - "代币" +title: "如何实现ERC-721市场 " +description: "如何在一个去中心化的分类信息板上销售代币化的物品。" +author: "Alberto Cuesta Cañada " +tags: [ "智能合同", "erc-721", "Solidity", "通证" ] skill: intermediate lang: zh published: 2020-03-19 @@ -26,13 +22,13 @@ sourceUrl: https://hackernoon.com/how-to-implement-an-erc721-market-1e1a32j9 基于公共区块链技术的分类信息板的商业模式和Ebay及普通的公司有显著的不同。 -首先,这种商业模式有[一个去中心化的视角](/developers/docs/web2-vs-web3/)。 目前现存的平台都需要维护自己的服务器。 去中心化的平台是由其用户来维护的,因此其核心平台的成本从平台所有者的角度来讲会降至零。 +首先,要考虑[去中心化角度](/developers/docs/web2-vs-web3/)。 目前现存的平台都需要维护自己的服务器。 去中心化的平台是由其用户来维护的,因此其核心平台的成本从平台所有者的角度来讲会降至零。 -中心化平台有前端界面,后台网站或者可以访问该去中心化平台的接口。 它同时也会有许多其他选择。 平台所有者可以限制客户的访问并强制每个人使用他们的接口,并收取费用。 平台所有者还可以决定是否开放访问权限(这是对普通用户的一种强权!),并让任何人构建与平台的接口。 或者平台所有者可以在这些极端情况中决定任何方法。 +中心化平台有前端界面,后台网站或者可以访问该去中心化平台的接口。 它同时也会有许多其他选择。 平台所有者可以限制客户的访问并强制每个人使用他们的接口,并收取费用。 平台所有者也可以决定开放访问权限(权力归于人民!) 并允许任何人构建该平台的界面。 或者平台所有者可以在这些极端情况中决定任何方法。 _比我更有远见的商业领袖知道如何将其货币化。 我所看到的是,这与现状不同,并且可能是有利可图的。_ -此外,还可以从自动化和支付的角度来看问题。 在分类信息板中,有些东西可以[非常有效地代币化](https://hackernoon.com/tokenization-of-digital-assets-g0ffk3v8s?ref=hackernoon.com) ,并产生交易。 代币化的资产很容易在区块链中转移。 高度复杂的支付方式可以在区块链中被轻松实现。 +此外,还可以从自动化和支付的角度来看问题。 有些东西可以非常[有效地代币化](https://hackernoon.com/tokenization-of-digital-assets-g0ffk3v8s?ref=hackernoon.com)并在分类广告板中交易。 代币化的资产很容易在区块链中转移。 高度复杂的支付方式可以在区块链中被轻松实现。 我在这里嗅到了一个商机。 通过区块链技术,可以轻松实现一个无需运行成本的分类信息板。复杂的支付路径被包含到了每笔交易里。 我相信有人会想出一个关于如何使用它的创意。 @@ -40,9 +36,9 @@ _比我更有远见的商业领袖知道如何将其货币化。 我所看到的 ## 实现 {#implementation} -前段时间我们启动了一个[开源项目](https://github.com/HQ20/contracts?ref=hackernoon.com),其中包含了一些商业案例的示例实现和其他相关的资源,推荐你看一看。 +不久前,我们启动了一个[开源代码库](https://github.com/HQ20/contracts?ref=hackernoon.com),其中包含业务案例示例实现和其他好东西,请看一看。 -这个[以太坊分类信息板](https://github.com/HQ20/contracts/tree/master/contracts/classifieds?ref=hackernoon.com)的代码在那里,请使用并研究它。 请注意,这个项目的代码尚未经过审核,你在把资金投入这个项目之前需要进行代码的尽职审查。 +这个[以太坊分类广告板](https://github.com/HQ20/contracts/tree/master/contracts/classifieds?ref=hackernoon.com)的代码就在那里,请随意使用。 请注意,这个项目的代码尚未经过审核,你在把资金投入这个项目之前需要进行代码的尽职审查。 这个项目的基础并不复杂。 分类信息板中的所有广告是一个包含几个字段的结构体: @@ -67,13 +63,9 @@ mapping(uint256 => Trade) public trades; 接下来的问题是我们需要处理哪些物品,以及用于支付交易的货币是什么。 -对于物品,我们只是要求它们实现[ERC-721](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721.sol?ref=hackernoon.com)的接口。这实际上只是一种在区块链中表示现实世界物品的方式, - -尽管它最适合数字资产。 我们将在构造函数中定制化我们自己的ERC721合约,这意味着我们分类信息板中的任何资产都需要事先被代币化 - -对于付款,我们将做类似的事情。 大多数区块链项目定义了自己的[ERC-20](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol?ref=hackernoon.com)加密货币。 其他一些人更喜欢使用像DAI这样的主流技术。 在这个分类信息板的应用中,你只需要在构造函数里决定你构建的货币是什么。 很容易。 - +对于这些物品,我们只要求它们实现 [ERC-721](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721.sol?ref=hackernoon.com) 接口,这实际上只是在区块链中表示现实世界物品的一种方式,尽管它[最适用于数字资产](https://hackernoon.com/tokenization-of-digital-assets-g0ffk3v8s?ref=hackernoon.com)。 我们将在构造函数中定制化我们自己的ERC721合约,这意味着我们分类信息板中的任何资产都需要事先被代币化。 +对于付款,我们将做类似的事情。 大多数区块链项目都定义了自己的 [ERC-20](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol?ref=hackernoon.com) 加密货币。 其他一些人更喜欢使用像DAI这样的主流技术。 在这个分类信息板的应用中,你只需要在构造函数里决定你构建的货币是什么。 很容易。 ```solidity constructor ( @@ -85,13 +77,10 @@ tradeCounter = 0; } ``` - 目前我们到达这里了。 我们有广告、用于交易的商品和用来付款的货币。 制作一个广告意味着将同一个物品放在托管中,以表明你拥有它并且你没有发布它两次,可能是在不同的分类信息板上。 下面的代码正是这样做的。 将物品放在托管中,制作广告,做一些记账操作。 - - ```solidity function openTrade(uint256 _item, uint256 _price) public @@ -108,11 +97,8 @@ function openTrade(uint256 _item, uint256 _price) } ``` - 接受交易意味着选择某个广告(交易)、支付价格、接收物品。 以下的代码用来获取交易。 检查它是否可用。 支付该物品的费用。 获取物品。 更新广告信息。 - - ```solidity function executeTrade(uint256 _trade) public @@ -126,13 +112,10 @@ function executeTrade(uint256 _trade) } ``` - 最后,我们可以选择让卖家在买家接受之前退出交易。 在某些模型中,广告会在过期前保留一段时间。 你的选择,具体取决于你的市场设计。 该代码与用于执行交易的代码非常相似,只是没有货币交换。同时该物品返回到广告的发行方。 - - ```solidity function cancelTrade(uint256 _trade) public @@ -140,21 +123,18 @@ function cancelTrade(uint256 _trade) Trade memory trade = trades[_trade]; require( msg.sender == trade.poster, - "Trade can be cancelled only by poster." + "交易只能由发布者取消。" ); - require(trade.status == "Open", "Trade is not Open."); + require(trade.status == "Open", "交易未开放。"); itemToken.transferFrom(address(this), trade.poster, trade.item); trades[_trade].status = "Cancelled"; emit TradeStatusChange(_trade, "Cancelled"); } ``` +就是这样。 你已经浏览到了该代码实现的末尾。 令人惊讶的是,一些业务概念在用代码表达时是多么紧凑,这就是其中一个例子。 在我们的[代码库](https://github.com/HQ20/contracts/blob/master/contracts/classifieds/Classifieds.sol)中查看完整的合约。 -就是这样。 你已经浏览到了该代码实现的末尾。 令人惊讶的是,一些业务概念在用代码表达时是多么紧凑,这就是其中一个例子。 请在[我们的代码库中](https://github.com/HQ20/contracts/blob/master/contracts/classifieds/Classifieds.sol)查看完整的合约代码。 - - - -## 总结 {#conclusion} +## 结论 {#conclusion} 分类信息板是一种易于在互联网技术的帮助下大规模扩张的常见市场结构,也是一种容易形成少数垄断赢家的非常流行的商业模式。 @@ -162,4 +142,4 @@ function cancelTrade(uint256 _trade) 在本文中,我尝试将分类信息板的商业业务与技术实现结合起来进行讲解。 如果你拥有合适的技能,这些知识应该可以帮助你创建愿景和实施路线图。 -与往常一样,如果你想构建任何有趣的东西并希望得到一些建议,[请给我留言!](https://albertocuesta.es/) 我总是很乐意为你提供帮助。 +与往常一样,如果你想构建任何有趣的东西并希望得到一些建议,请[给我留言](https://albertocuesta.es/)! 我总是很乐意为你提供帮助。 diff --git a/public/content/translations/zh/developers/tutorials/how-to-mint-an-nft/index.md b/public/content/translations/zh/developers/tutorials/how-to-mint-an-nft/index.md index 2ae13c116a9..d0cce858998 100644 --- a/public/content/translations/zh/developers/tutorials/how-to-mint-an-nft/index.md +++ b/public/content/translations/zh/developers/tutorials/how-to-mint-an-nft/index.md @@ -1,28 +1,24 @@ --- -title: 如何铸造非同质化代币(非同质化代币教程系列 2/3) -description: 本教程描述了如何使用我们的智能合约和 Web3 在以太坊区块链上铸造非同质化代币。 +title: "如何铸造 NFT(NFT 教程系列第 2/3 部分)" +description: "本教程介绍如何使用我们的智能合约和 Web3 在以太坊区块链上铸造 NFT。" author: "苏米-穆德吉尔" -tags: - - "ERC-721" - - "Alchemy" - - "solidity" - - "智能合约" +tags: [ "ERC-721", "Alchemy", "Solidity", "智能合同" ] skill: beginner lang: zh published: 2021-04-22 --- -[Beeple](https://www.nytimes.com/2021/03/11/arts/design/nft-auction-christies-beeple.html):6900 万美元 [3LAU](https://www.forbes.com/sites/abrambrown/2021/03/03/3lau-nft-nonfungible-tokens-justin-blau/?sh=5f72ef64643b):1100 万美元 [Grimes](https://www.theguardian.com/music/2021/mar/02/grimes-sells-digital-art-collection-non-fungible-tokens):600 万美元 +[Beeple](https://www.nytimes.com/2021/03/11/arts/design/nft-auction-christies-beeple.html):6900 万美元\n[3LAU](https://www.forbes.com/sites/abrambrown/2021/03/03/3lau-nft-nonfungible-tokens-justin-blau/?sh=5f72ef64643b):1100 万美元\n[Grimes](https://www.theguardian.com/music/2021/mar/02/grimes-sells-digital-art-collection-non-fungible-tokens):600 万美元 -他们都使用 Alchemy 的强大应用程序接口铸造非同质化代币。 在本教程中,我们将教你如何在 < 10 分钟内做到这一点。 +他们都使用 Alchemy 强大的 API 铸造了各自的 NFT。 在本教程中,我们将在 \<10 分钟内教会你如何做到同样的事情。 -“铸造非同质化代币”是在区块链上发布你的 ERC-721 代币的唯一方式。 使用我们在[非同质化代币教程系列第 1 部分](/developers/tutorials/how-to-write-and-deploy-an-nft/)中获得的智能合约,我们可以运用我们的 Web3 技能并铸造非同质化代币。 在本教程结束时,你将能够按照你的内心(和钱包)的愿望铸造出更多非同质化代币! +“铸造 NFT”是指在区块链上发布你的 ERC-721 代币的唯一实例的行为。 让我们使用 [本 NFT 教程系列第 1 部分](/developers/tutorials/how-to-write-and-deploy-an-nft/)中的智能合约,一展我们的 Web3 技能,铸造一个 NFT 吧。 在本教程结束时,你将能随心所欲(钱包也得跟上!)地铸造任意数量的 NFT! 我们开始吧! ## 第 1 步:安装 Web3 {#install-web3} -如果你跟随第一个教程创建了你的非同质化代币智能合约,那么你在使用 Ethers.js 方面已经有了经验。 Web3 与 Ethers 相似,也是一个库,用于更轻松地创建对以太坊区块链的请求。 在本教程中,我们将使用增强版 Web3 库 [Alchemy Web3](https://docs.alchemyapi.io/alchemy/documentation/alchemy-web3),它提供自动重试和强大的 WebSocket 支持。 +如果你学习了关于创建 NFT 智能合约的第一个教程,那么你应该已经有使用 Ethers.js 的经验了。 Web3 与 Ethers 类似,都是能让你更轻松地向以太坊区块链创建请求的库。 在本教程中,我们将使用 [Alchemy Web3](https://docs.alchemyapi.io/alchemy/documentation/alchemy-web3),这是一个增强的 Web3 库,可提供自动重试和强大的 WebSocket 支持。 在你的项目主目录中运行: @@ -32,298 +28,156 @@ npm install @alch/alchemy-web3 ## 第 2 步:创建 `mint-nft.js` 文件 {#create-mintnftjs} -在你的脚本目录中,创建一个 `mint-nft.js` 文件并添加以下代码行: +在你的 `scripts` 目录中,创建一个 `mint-nft.js` 文件,并添加以下代码行: ```js -require("dotenv").config() -const API_URL = process.env.API_URL -const { createAlchemyWeb3 } = require("@alch/alchemy-web3") -const web3 = createAlchemyWeb3(API_URL) +require("dotenv").config()\nconst API_URL = process.env.API_URL\nconst { createAlchemyWeb3 } = require("@alch/alchemy-web3")\nconst web3 = createAlchemyWeb3(API_URL) ``` -## 第 3 步:获取你的合约应用程序二进制接口 {#contract-abi} +## 第 3 步:获取你的合约 ABI {#contract-abi} -我们的合约 ABI(应用程序二进制接口)是与我们的智能合约交互的接口。 你可以在[此处](https://docs.alchemyapi.io/alchemy/guides/eth_getlogs#what-are-ab-is)了解更多关于合约应用程序二进制接口的信息。 安全帽自动为我们生成应用程序二进制接口,并将其保存在 `MyNFT.json` 文件中。 为了使用该接口,我们需要通过在我们的 `mint-nft.js` 文件中添加以下代码行来解析内容: +我们的合约 ABI(应用程序二进制接口)是用于与我们的智能合约交互的接口。 你可以在[此处](https://docs.alchemyapi.io/alchemy/guides/eth_getlogs#what-are-ab-is)了解更多关于合约 ABI 的信息。 Hardhat 会自动为我们生成一个 ABI 并将其保存在 `MyNFT.json` 文件中。 为了使用它,我们需要将以下代码行添加到我们的 `mint-nft.js` 文件中以解析内容: ```js const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json") ``` -如果你想查看应用程序二进制接口,你可以将其发送到你的控制台: +如果你想查看 ABI,可以将其打印到控制台: ```js console.log(JSON.stringify(contract.abi)) ``` -要运行 `mint-nft.js` 并查看输出到控制台的应用程序二进制接口,请导航至你的终端并运行: +要运行 `mint-nft.js` 并在控制台中查看打印出的 ABI,请导航到你的终端并运行: ```js node scripts/mint-nft.js ``` -## 第 4 步:使用 IPFS 系统为你的非同质化代币配置元数据 {#config-meta} +## 第 4 步:使用 IPFS 为你的 NFT 配置元数据 {#config-meta} -如果你还记得我们第 1 部分的教程,我们的 `mintNFT` 智能合约函数使用 tokenURI 参数,该参数应解析为描述非同质化代币元数据的 JSON 文档,正是它生成非同质化代币并赋予非同质化代币可配置的属性,如名称、描述、图像和其他属性。 +如果你还记得我们第 1 部分教程的内容,我们的 `mintNFT` 智能合约函数接受一个 `tokenURI` 参数,该参数应解析为一个 JSON 文档,用于描述 NFT 的元数据——正是元数据赋予了 NFT 生命,让它拥有可配置的属性,例如名称、描述、图片和其他特性。 -> _星际文件系统 (IPFS) 是一个分散协议和对等网络,用于在分布式文件系统中存储和共享数据。_ +> _星际文件系统 (IPFS) 是一种用于在分布式文件系统中存储和共享数据的去中心化协议和点对点网络。_ -我们将使用 Pinata,一个方便的星际文件系统应用程序接口和工具包,用于存储我们的非同质化代币资产和元数据,以确保我们的非同质化代币真正去中心化。 如果你没有 Pinata 帐户,请在[此处](https://app.pinata.cloud)注册一个免费帐户,并完成电子邮件验证步骤。 +我们将使用 Pinata,一个方便的 IPFS API 和工具包,来存储我们的 NFT 资产和元数据,以确保我们的 NFT 是真正去中心化的。 如果你还没有 Pinata 帐户,请[在此处](https://app.pinata.cloud)注册一个免费帐户,并完成电子邮件验证步骤。 创建帐户后: -- 导航到“文件”页面,点击页面左上方蓝色的“上传”按钮。 +- 导航到“文件”页面,然后单击页面左上角的蓝色“上传”按钮。 -- 将图像上传到 Pinata — 这将是你的非同质化代币的图像资产。 你可以随意为该资产命名。 +- 将图片上传到 Pinata — 这将是你的 NFT 的图片资产。 你可以随意为该资产命名 -- 上传之后,你将在“File”页面的表格中看到文件信息。 你还会看到 CID 列。 你可以通过单击旁边的复制按钮来复制 CID。 你可以通过 `https://gateway.pinata.cloud/ipfs/` 查看你上传的信息。 例如,你可以在[此处](https://gateway.pinata.cloud/ipfs/QmZdd5KYdCFApWn7eTZJ1qgJu18urJrP9Yh1TZcZrZxxB5)找到我们在星际文件系统上使用的图片。 +- 上传后,你将在“文件”页面的表格中看到文件信息。 你还会看到一个 CID 列。 你可以通过单击旁边的复制按钮来复制 CID。 你可以在以下地址查看你上传的内容:`https://gateway.pinata.cloud/ipfs/`。 例如,你可以在[此处](https://gateway.pinata.cloud/ipfs/QmZdd5KYdCFApWn7eTZJ1qgJu18urJrP9Yh1TZcZrZxxB5)找到我们在 IPFS 上使用的图片。 -为了方便更偏向视觉型的学习者理解,上述步骤总结如下: +为方便偏爱视觉学习的学习者,我们将以上步骤总结如下: -![如何将你的图像上传到 Pinata](./instructionsPinata.gif) +![如何将你的图片上传到 Pinata](./instructionsPinata.gif) -现在,我们要再上传一份文件到 Pinata。 但在我们上传之前,需要先创建该文件! +现在,我们还要向 Pinata 上传一份文档。 但在此之前,我们需要先创建它! -在你的根目录中,创建一个名为 `nft-metadata.json` 的新文件,并添加以下 json 代码: +在你的根目录中,新建一个名为 `nft-metadata.json` 的文件,并添加以下 json 代码: ```json -{ - "attributes": [ - { - "trait_type": "Breed", - "value": "Maltipoo" - }, - { - "trait_type": "Eye color", - "value": "Mocha" - } - ], - "description": "The world's most adorable and sensitive pup.", - "image": "ipfs://QmWmvTJmJU3pozR9ZHFmQC2DNDwi2XJtf3QGyYiiagFSWb", - "name": "Ramses" -} +{\n "attributes": [\n {\n "trait_type": "品种",\n "value": "马尔济斯"\n },\n {\n "trait_type": "眼睛颜色",\n "value": "摩卡"\n }\n ],\n "description": "世界上最可爱、最敏感的小狗。",\n "image": "ipfs://QmWmvTJmJU3pozR9ZHFmQC2DNDwi2XJtf3QGyYiiagFSWb",\n "name": "Ramses"\n} ``` -可随意更改 json 中的数据。 你可以删除或添加到属性部分。 最重要的是,确保图像字段指向你的星际文件系统图像的位置——否则,你的非同质化代币将包含一张(非常可爱!)的狗狗照片。 +你可以随意更改 json 中的数据。 你可以删除或添加属性部分。 最重要的是,确保 `image` 字段指向你的 IPFS 图片的位置 — 否则,你的 NFT 将包含一张(非常可爱的!) 狗狗的照片。 -编辑完 JSON 文件后,保存并上传到 Pinata,步骤与上传图像相同。 +编辑完 JSON 文件后,保存并上传到 Pinata,步骤与上传图片时相同。 -![如何将你的 nft-metadata.json 上传至 Pinata](./uploadPinata.gif) +![如何将你的 nft-metadata.json 上传到 Pinata](./uploadPinata.gif) -## 第 5 步:创建你的合约实例 {#instance-contract} +## 第 5 步:创建合约实例 {#instance-contract} -现在,为了与我们的合约进行交互,我们需要在代码中创建一个实例。 为此,我们需要合约地址,可以从部署或 [Etherscan](https://sepolia.etherscan.io/) 中通过查找用来部署合约的地址获得。 +现在,为了与我们的合约交互,我们需要在代码中创建它的一个实例。 为此,我们需要我们的合约地址。我们可以通过在 [Blockscout](https://eth-sepolia.blockscout.com/) 上查找你用于部署合约的地址,从部署中获取合约地址。 -![在 Etherscan 区块浏览器 上查看你的合约地址](./view-contract-etherscan.png) +![在 Etherscan 上查看你的合约地址](./view-contract-etherscan.png) 在上面的示例中,我们的合约地址是 0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778。 -接下来我们将使用 Web3 的[合约方法](https://docs.web3js.org/api/web3-eth-contract/class/Contract),创建使用应用程序二进制接口和地址的合约。 在你的 `mint-nft.js` 文件中,添加以下内容: +接下来,我们将使用 Web3 的 [合约方法](https://docs.web3js.org/api/web3-eth-contract/class/Contract),通过 ABI 和地址来创建我们的合约。 在你的 `mint-nft.js` 文件中,添加以下内容: ```js -const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778" - -const nftContract = new web3.eth.Contract(contract.abi, contractAddress) +const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778"\n\nconst nftContract = new web3.eth.Contract(contract.abi, contractAddress) ``` ## 第 6 步:更新 `.env` 文件 {#update-env} -现在,为了创建并发送交互到以太坊链,我们将使用你的以太坊公共帐户地址来获得帐户随机数(解释如下)。 +现在,为了创建交易并将其发送到以太坊链,我们将使用你的以太坊公共帐户地址来获取帐户 nonce(随机数,下文会解释)。 -将你的公钥添加到你的 `.env` 文件中 — 如果你完成了教程第 1 部分,我们的 `.env` 文件现在应该如下所示: +将你的公钥添加到 `.env` 文件中 — 如果你完成了本教程的第 1 部分,你的 `.env` 文件现在应该如下所示: ```js -API_URL = "https://eth-sepolia.g.alchemy.com/v2/your-api-key" -PRIVATE_KEY = "your-private-account-address" -PUBLIC_KEY = "your-public-account-address" +API_URL = "https://eth-sepolia.g.alchemy.com/v2/你的-api-密钥"\nPRIVATE_KEY = "你的-私有-账户-地址"\nPUBLIC_KEY = "你的-公共-账户-地址" ``` ## 第 7 步:创建你的交易 {#create-txn} -首先,让我们定义一个名为 `mintNFT(tokenData)` 的函数并通过执行以下操作创建我们的交易: +首先,我们来定义一个名为 `mintNFT(tokenData)` 的函数,并通过以下操作创建我们的交易: -1. 获取 _PRIVATE_KEY_ 和 _PUBLIC_KEY_,来源为 `.env` 文件。 +1. 从 `.env` 文件中获取你的 _PRIVATE_KEY_ 和 _PUBLIC_KEY_。 -1. 接下来,我们需要弄清楚帐户的随机数。 随机数规范用于跟踪从你的地址发送的交易数量——我们这样做是出于安全目的,以防止[重放攻击](https://docs.alchemyapi.io/resources/blockchain-glossary#account-nonce)。 要获得从你的地址发送的交易数量,我们要用到 [getTransactionCount](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc#eth_gettransactioncount)。 +2. 接下来,我们需要确定帐户 nonce(随机数)。 nonce 规范用于跟踪从你的地址发送的交易数量 — 出于安全目的和防止[重放攻击](https://docs.alchemyapi.io/resources/blockchain-glossary#account-nonce)的需要,我们必须使用它。 为了获取从你的地址发送的交易数量,我们使用 [getTransactionCount](https://docs.alchemyapi.io/documentation/alchemy-api-reference/json-rpc#eth_gettransactioncount)。 -1. 最后,我们将使用以下信息设置我们的交易: +3. 最后,我们将用以下信息设置我们的交易: -- `'from': PUBLIC_KEY`——我们的交易源于我们的公共地址 +- `'from': PUBLIC_KEY` — 交易的来源,即我们的公共地址 -- `'to': contractAddress`——我们希望与之交互并发送交易的合约 +- `'to': contractAddress` — 我们希望与之交互并向其发送交易的合约 -- `'nonce': nonce` — 帐户随机数和从我们的地址发送的交易数量 +- `'nonce': nonce` — 帐户 nonce(随机数),即从我们的地址发送的交易数量 -- `'gas': estimatedGas`——预估完成交易所需的燃料 +- `'gas': estimatedGas` — 完成交易所需的预估燃料 -- `'data': nftContract.methods.mintNFT(PUBLIC_KEY, md).encodeABI()`——我们希望在这笔交易中进行的计算——铸造一个非同质化代币 +- `'data': nftContract.methods.mintNFT(PUBLIC_KEY, md).encodeABI()` — 我们希望在此交易中执行的计算,在本例中就是铸造一个 NFT 你的 `mint-nft.js` 文件现在应该如下所示: ```js - require('dotenv').config(); - const API_URL = process.env.API_URL; - const PUBLIC_KEY = process.env.PUBLIC_KEY; - const PRIVATE_KEY = process.env.PRIVATE_KEY; - - const { createAlchemyWeb3 } = require("@alch/alchemy-web3"); - const web3 = createAlchemyWeb3(API_URL); - - const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json"); - const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778"; - const nftContract = new web3.eth.Contract(contract.abi, contractAddress); - - async function mintNFT(tokenURI) { - const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, 'latest'); //get latest nonce - - //the transaction - const tx = { - 'from': PUBLIC_KEY, - 'to': contractAddress, - 'nonce': nonce, - 'gas': 500000, - 'data': nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI() - }; - }​ + require('dotenv').config();\n const API_URL = process.env.API_URL;\n const PUBLIC_KEY = process.env.PUBLIC_KEY;\n const PRIVATE_KEY = process.env.PRIVATE_KEY;\n\n const { createAlchemyWeb3 } = require("@alch/alchemy-web3");\n const web3 = createAlchemyWeb3(API_URL);\n\n const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json");\n const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778";\n const nftContract = new web3.eth.Contract(contract.abi, contractAddress);\n\n async function mintNFT(tokenURI) {\n const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, 'latest'); //获取最新的 nonce\n\n //交易\n const tx = {\n 'from': PUBLIC_KEY,\n 'to': contractAddress,\n 'nonce': nonce,\n 'gas': 500000,\n 'data': nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI()\n };\n }​ ``` ## 第 8 步:签署交易 {#sign-txn} -现在我们已经创建了我们的交易,我们需要签署它,以便将其发送出去。 在这里我们将使用到我们的私钥。 +创建好交易后,我们需要对其进行签名才能发送。 在这里,我们将使用我们的私钥。 -`web3.eth.sendSignedTransaction` 会给我们提供交易的哈希值,我们可以用它来确保我们的交易被开采出来,没有被网络丢弃。 你会注意到在交易签署部分,我们已经增加了一些错误检查,以便我们知晓交易是否成功通过。 +`web3.eth.sendSignedTransaction` 将为我们提供交易哈希,我们可以用它来确保我们的交易被挖出,而没有被网络丢弃。 你会注意到,在交易签名部分,我们添加了一些错误检查,以便我们知道交易是否成功。 ```js -require("dotenv").config() -const API_URL = process.env.API_URL -const PUBLIC_KEY = process.env.PUBLIC_KEY -const PRIVATE_KEY = process.env.PRIVATE_KEY - -const { createAlchemyWeb3 } = require("@alch/alchemy-web3") -const web3 = createAlchemyWeb3(API_URL) - -const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json") -const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778" -const nftContract = new web3.eth.Contract(contract.abi, contractAddress) - -async function mintNFT(tokenURI) { - const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, "latest") //get latest nonce - - //the transaction - const tx = { - from: PUBLIC_KEY, - to: contractAddress, - nonce: nonce, - gas: 500000, - data: nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI(), - } - - const signPromise = web3.eth.accounts.signTransaction(tx, PRIVATE_KEY) - signPromise - .then((signedTx) => { - web3.eth.sendSignedTransaction( - signedTx.rawTransaction, - function (err, hash) { - if (!err) { - console.log( - "The hash of your transaction is: ", - hash, - "\nCheck Alchemy's Mempool to view the status of your transaction!" - ) - } else { - console.log( - "Something went wrong when submitting your transaction:", - err - ) - } - } - ) - }) - .catch((err) => { - console.log(" Promise failed:", err) - }) -} +require("dotenv").config()\nconst API_URL = process.env.API_URL\nconst PUBLIC_KEY = process.env.PUBLIC_KEY\nconst PRIVATE_KEY = process.env.PRIVATE_KEY\n\nconst { createAlchemyWeb3 } = require("@alch/alchemy-web3")\nconst web3 = createAlchemyWeb3(API_URL)\n\nconst contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json")\nconst contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778"\nconst nftContract = new web3.eth.Contract(contract.abi, contractAddress)\n\nasync function mintNFT(tokenURI) {\n const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, "latest") //获取最新的 nonce\n\n //交易\n const tx = {\n from: PUBLIC_KEY,\n to: contractAddress,\n nonce: nonce,\n gas: 500000,\n data: nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI(),\n }\n\n const signPromise = web3.eth.accounts.signTransaction(tx, PRIVATE_KEY)\n signPromise\n .then((signedTx) => {\n web3.eth.sendSignedTransaction(\n signedTx.rawTransaction,\n function (err, hash) {\n if (!err) {\n console.log(\n "你的交易哈希是:",\n hash,\n "\n检查 Alchemy 的内存池 (Mempool) 来查看你的交易状态!"\n )\n } else {\n console.log(\n "提交交易时出错了:",\n err\n )\n }\n }\n )\n })\n .catch((err) => {\n console.log(" Promise 失败:", err)\n })\n} ``` -## 第 9 步:调用 `mintNFT` 并运行节点 `mint-nft.js` {#call-mintnft-fn} +## 第 9 步:调用 `mintNFT` 并运行 `node mint-nft.js` {#call-mintnft-fn} -还记得你上传到 Pinata 的 `metadata.json` 吗? 从 Pinata 获取其哈希代码,并将以下内容作为参数传送给函数 `mintNFT` `https://gateway.pinata.cloud/ipfs/` +还记得你上传到 Pinata 的 `metadata.json` 吗? 从 Pinata 获取其哈希码,并将以下内容作为参数传递给 `mintNFT` 函数 `https://gateway.pinata.cloud/ipfs/` -如何获取哈希代码: +获取哈希码的方法如下: -![如何在 Pinata 上获得你的非同质化代币元数据哈希代码](./metadataPinata.gif)_How to get your nft metadata hashcode on Pinata_ +![如何在 Pinata 上获取你的 NFT 元数据哈希码](./metadataPinata.gif)_如何在 Pinata 上获取你的 NFT 元数据哈希码_ -> 仔细检查你复制的哈希代码是否链接到你的 **metadata.json**,方法是将 `https://gateway.pinata.cloud/ipfs/` 加载到独立窗口。 页面看起来应该类似于下面的截图: +> 通过将 `https://gateway.pinata.cloud/ipfs/` 加载到单独的窗口中,仔细检查你复制的哈希码是否链接到你的 **metadata.json**。 该页面应类似于下面的屏幕截图: -![你的页面应该显示 json 元数据](./metadataJSON.png)_Your page should display the json metadata_ +![你的页面应显示 json 元数据](./metadataJSON.png)_你的页面应显示 json 元数据_ -总之,你的代码应该看起来像这样: +总而言之,你的代码应该如下所示: ```js -require("dotenv").config() -const API_URL = process.env.API_URL -const PUBLIC_KEY = process.env.PUBLIC_KEY -const PRIVATE_KEY = process.env.PRIVATE_KEY - -const { createAlchemyWeb3 } = require("@alch/alchemy-web3") -const web3 = createAlchemyWeb3(API_URL) - -const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json") -const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778" -const nftContract = new web3.eth.Contract(contract.abi, contractAddress) - -async function mintNFT(tokenURI) { - const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, "latest") //get latest nonce - - //the transaction - const tx = { - from: PUBLIC_KEY, - to: contractAddress, - nonce: nonce, - gas: 500000, - data: nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI(), - } - - const signPromise = web3.eth.accounts.signTransaction(tx, PRIVATE_KEY) - signPromise - .then((signedTx) => { - web3.eth.sendSignedTransaction( - signedTx.rawTransaction, - function (err, hash) { - if (!err) { - console.log( - "The hash of your transaction is: ", - hash, - "\nCheck Alchemy's Mempool to view the status of your transaction!" - ) - } else { - console.log( - "Something went wrong when submitting your transaction:", - err - ) - } - } - ) - }) - .catch((err) => { - console.log("Promise failed:", err) - }) -} - -mintNFT("ipfs://QmYueiuRNmL4MiA2GwtVMm6ZagknXnSpQnB3z2gWbz36hP") +require("dotenv").config()\nconst API_URL = process.env.API_URL\nconst PUBLIC_KEY = process.env.PUBLIC_KEY\nconst PRIVATE_KEY = process.env.PRIVATE_KEY\n\nconst { createAlchemyWeb3 } = require("@alch/alchemy-web3")\nconst web3 = createAlchemyWeb3(API_URL)\n\nconst contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json")\nconst contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778"\nconst nftContract = new web3.eth.Contract(contract.abi, contractAddress)\n\nasync function mintNFT(tokenURI) {\n const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, "latest") //获取最新的 nonce\n\n //交易\n const tx = {\n from: PUBLIC_KEY,\n to: contractAddress,\n nonce: nonce,\n gas: 500000,\n data: nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI(),\n }\n\n const signPromise = web3.eth.accounts.signTransaction(tx, PRIVATE_KEY)\n signPromise\n .then((signedTx) => {\n web3.eth.sendSignedTransaction(\n signedTx.rawTransaction,\n function (err, hash) {\n if (!err) {\n console.log(\n "你的交易哈希是:",\n hash,\n "\n检查 Alchemy 的内存池 (Mempool) 来查看你的交易状态!"\n )\n } else {\n console.log(\n "提交交易时出错了:",\n err\n )\n }\n }\n )\n })\n .catch((err) => {\n console.log("Promise 失败:", err)\n })\n}\n\nmintNFT("ipfs://QmYueiuRNmL4MiA2GwtVMm6ZagknXnSpQnB3z2gWbz36hP") ``` -现在,运行 `node scripts/mint-nft.js` 来部署你的非同质化代币。 几秒钟后,你应该在终端中看到这样的响应: +现在,运行 `node scripts/mint-nft.js` 来部署你的 NFT。 几秒钟后,你应该会在终端中看到如下响应: - 你的交易哈希值为:0x301791fdf492001fcd9d5e5b12f3aa1bbbea9a88ed24993a8ab2cdae2d06e1e8 - - 检查 Alchem 的内存池以查看你的交易状态! + ``` + 你的交易哈希为:0x301791fdf492001fcd9d5e5b12f3aa1bbbea9a88ed24993a8ab2cdae2d06e1e8\n\n请检查 Alchemy 的内存池 (Mempool),查看你的交易状态! + ``` -接下来,访问你的 [Alchemy 内存池](https://dashboard.alchemyapi.io/mempool),查看你的交易状态(待定、已开采还是被网络放弃)。 如果你的交易被丢弃,还可以访问 [Goerli Etherscan](https://sepolia.etherscan.io/) 并搜索你的交易哈希值。 +接下来,访问你的 [Alchemy 内存池](https://dashboard.alchemyapi.io/mempool),查看你的交易状态(待处理、已挖出或已被网络丢弃)。 如果你的交易被丢弃,检查 [Blockscout](https://eth-sepolia.blockscout.com/) 并搜索你的交易哈希也会有所帮助。 -![在 Etherscan 区块浏览器 上查看你的非同质化代币交易哈希值](./view-nft-etherscan.png)_View your NFT transaction hash on Etherscan_ +![在 Etherscan 上查看你的 NFT 交易哈希](./view-nft-etherscan.png)_在 Etherscan 上查看你的 NFT 交易哈希_ -就是这样! 你现在已经在以太坊区块链上部署和铸造了一个非同质化代币 +就这么简单! 你现在已经成功在以太坊区块链上部署并铸造了一个 NFT -通过使用 `mint-nft.js`,你可以按需铸造任意数量的非同质化代币! 只要确保输入一个新的 tokenURI 来描述非同质化代币的元数据(否则,你将最终生成一堆相同但具有不同 ID 的 tokenURI)。 +使用 `mint-nft.js`,你可以随心所欲(钱包也得跟上!)地铸造任意数量的 NFT! 只需确保传入一个新的、用于描述 NFT 元数据的 tokenURI(否则,你最终只会制作出一堆 ID 不同但内容相同的 NFT)。 -大概,你会想要展示一下你钱包中的非同质化代币——所以请务必查看[第 3 部分:如何在你的钱包中查看你的非同质化代币](/developers/tutorials/how-to-view-nft-in-metamask/)! +想必你一定想在钱包里展示你的 NFT 吧 — 那就一定要看看[第 3 部分:如何在你的钱包中查看 NFT](/developers/tutorials/how-to-view-nft-in-metamask/)! diff --git a/public/content/translations/zh/developers/tutorials/how-to-mock-solidity-contracts-for-testing/index.md b/public/content/translations/zh/developers/tutorials/how-to-mock-solidity-contracts-for-testing/index.md index 80ad005d282..6c13eeee639 100644 --- a/public/content/translations/zh/developers/tutorials/how-to-mock-solidity-contracts-for-testing/index.md +++ b/public/content/translations/zh/developers/tutorials/how-to-mock-solidity-contracts-for-testing/index.md @@ -1,13 +1,9 @@ --- -title: 如何在测试中模拟 Solidity 智能合约 -description: 为什么应该在测试时模拟合约 +title: "如何在测试中模拟 Solidity 智能合约" +description: "为什么应该在测试时模拟合约" author: Markus Waas lang: zh -tags: - - "solidity" - - "智能合约" - - "测试" - - "模拟" +tags: [ "Solidity", "智能合同", "测试", "模拟" ] skill: intermediate published: 2020-05-02 source: soliditydeveloper.com @@ -16,15 +12,15 @@ sourceUrl: https://soliditydeveloper.com/mocking-contracts [模拟对象](https://wikipedia.org/wiki/Mock_object)是面向对象编程中的一种常见设计模式。 Mock 一词来源于古法语词“mocquer”,意为“嘲笑,取笑”,但它渐渐拥有了“模拟真实事物”的含义,这实际上也是我们在编程时所做的事情。 不要随意拿你的智能合约开玩笑,但一定要尽可能多地模拟它们。 这将使你的工作更轻松。 -## 使用模拟合约对合约进行单元测试 {#unit-testing-contracts-with-mocks} +## 用模拟对象进行合约单元测试 {#unit-testing-contracts-with-mocks} -对合约进行模拟,本质上是创建一个与该合约行为类似的副本,但开发者可以轻易控制这个副本。 通常你会拥有复杂的合约,而[你只想对合约其中一小部分进行单元测试](/developers/docs/smart-contracts/testing/)。 问题在于,如果测试这一小部分需要合约进入一个非常特别但又难以进入的状态,会怎样? +对合约进行模拟,本质上是创建一个与该合约行为类似的副本,但开发者可以轻易控制这个副本。 通常你会遇到复杂的合约,而你只想[对合约的一小部分进行单元测试](/developers/docs/smart-contracts/testing/)。 问题在于,如果测试这一小部分需要合约进入一个非常特别但又难以进入的状态,会怎样? 可以每次都编写将合约带入所需状态的复杂测试设置逻辑,也可以写一个模拟合约。 利用继承,对合约进行模拟比较容易。 只需创建继承原始合约的另一个模拟合约即可。 这时,你就可以重写模拟合约中的函数。 让我们通过一个例子来理解它。 -## 示例:私密 ERC20 合约 {#example-private-erc20} +## 示例:私有 ERC20 {#example-private-erc20} -本文使用一个在开始时提供私密时间的示例 ERC-20 合约。 合约所有者可以管理私密用户,而且只有这些用户才能在开始时接收代币。 经过特定一段时间后,所有人就都可以使用代币了。 如果你感到好奇,我们使用新 OpenZeppelin 合约(第三版)中的 [`_beforeTokenTransfer`](https://docs.openzeppelin.com/contracts/5.x/extending-contracts#using-hooks) 钩子进一步阐释。 +本文使用一个在开始时提供私密时间的示例 ERC-20 合约。 合约所有者可以管理私密用户,而且只有这些用户才能在开始时接收代币。 经过特定一段时间后,所有人就都可以使用代币了。 如果你好奇,我们使用的是新的 OpenZeppelin 合约 v3 中的 [`_beforeTokenTransfer`](https://docs.openzeppelin.com/contracts/5.x/extending-contracts#using-hooks) 钩子。 ```solidity pragma solidity ^0.6.0; @@ -51,7 +47,7 @@ contract PrivateERC20 is ERC20, Ownable { function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override { super._beforeTokenTransfer(from, to, amount); - require(_validRecipient(to), "PrivateERC20: invalid recipient"); + require(_validRecipient(to), "PrivateERC20:无效的接收者"); } function _validRecipient(address to) private view returns (bool) { @@ -87,18 +83,18 @@ contract PrivateERC20Mock is PrivateERC20 { 你将得到以下错误消息之一: -- `PrivateERC20Mock.sol: TypeError: Overriding function is missing "override" specifier.` -- `PrivateERC20.sol: TypeError: Trying to override non-virtual function. Did you forget to add "virtual"?.` +- `PrivateERC20Mock.sol:类型错误:重写函数缺少“override”说明符。` +- `PrivateERC20.sol:类型错误:试图重写非虚函数。 您是否忘记添加“virtual”?` 由于使用的是新的 Solidity 0.6 版本,所以必须为可被重写的函数添加 `virtual` 关键字,为执行重写的函数添加 override。 因此,我们为两个 `isPublic` 函数添加这些关键字。 -现在,在单元测试中,你就可以使用 `PrivateERC20Mock` 了。 想要在私密使用期间测试合约的行为时,请使用 `setIsPublic(false)`;同样,可以使用 `setIsPublic(true)` 在公共使用期间测试。 当然,在本例中,我们也可以只使用[时间帮助器](https://docs.openzeppelin.com/test-helpers/0.5/api#increase)相应地修改时间。 但至此,模拟合约的概念应该已经清楚了,并且你也可以想象一下不仅仅需要修改时间的复杂场景。 +现在,在单元测试中,你就可以使用 `PrivateERC20Mock` 了。 想要在私密使用期间测试合约的行为时,请使用 `setIsPublic(false)`;同样,可以使用 `setIsPublic(true)` 在公共使用期间测试。 当然,在我们的示例中,我们也可以使用[时间帮助器](https://docs.openzeppelin.com/test-helpers/0.5/api#increase)来相应地更改时间。 但至此,模拟合约的概念应该已经清楚了,并且你也可以想象一下不仅仅需要修改时间的复杂场景。 -## 对多个合约进行模拟 {#mocking-many-contracts} +## 模拟多个合约 {#mocking-many-contracts} -如果每进行一次模拟都要创建另一个合约,那将是一件很麻烦的事。 如果你被这种情况困扰,可以考虑 [MockContract](https://github.com/gnosis/mock-contract) 库。 它允许用户实时重写和更改合约的行为。 但是,该库只能用来模拟对另一个合约的调用,因此对于上面的示例并不适用。 +如果每进行一次模拟都要创建另一个合约,那将是一件很麻烦的事。 如果这困扰到你,可以看看 [MockContract](https://github.com/gnosis/mock-contract) 程序库。 它允许你实时重写和更改合约的行为。 但是,该库只能用来模拟对另一个合约的调用,因此对于上面的示例并不适用。 -## 模拟技术还可以更强大 {#mocking-can-be-even-more-powerful} +## 模拟可以更强大 {#mocking-can-be-even-more-powerful} 模拟技术的强大之处远不仅于此。 diff --git a/public/content/translations/zh/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/index.md b/public/content/translations/zh/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/index.md index 23171c2d1c0..ec6034ee369 100644 --- a/public/content/translations/zh/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/index.md +++ b/public/content/translations/zh/developers/tutorials/how-to-use-echidna-to-test-smart-contracts/index.md @@ -1,23 +1,18 @@ --- -title: 如何使用 Echidna 测试智能合约 -description: 如何使用 Echidna 自动测试智能合约 +title: "如何使用 Echidna 测试智能合约" +description: "如何使用 Echidna 自动测试智能合约" author: "Trailofbits" lang: zh -tags: - - "solidity" - - "智能合约" - - "安全性" - - "测试" - - "模糊测试" +tags: [ "Solidity", "智能合同", "安全性。", "测试", "模糊测试" ] skill: advanced published: 2020-04-10 -source: 构建安全的合约 +source: "构建安全的合约" sourceUrl: https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/echidna --- ## 安装 {#installation} -Echidna 可以通过 docker 或使用预编译的二进制程序安装。 +Echidna 可以通过 docker 安装,或使用预编译的二进制文件安装。 ### 通过 docker 安装 Echidna {#echidna-through-docker} @@ -26,46 +21,46 @@ docker pull trailofbits/eth-security-toolbox docker run -it -v "$PWD":/home/training trailofbits/eth-security-toolbox ``` -_最后一个命令在有权访问当前目录的 docker 中运行 eth-security-toolbox。 你可以从主机更改文件,并在 docker 中对文件运行工具_ +_最后一个命令在一个可访问你当前目录的 docker 中运行 eth-security-toolbox。 你可以从主机更改文件,并在 docker 中对文件运行工具_ -在 docker 中,运行: +在 docker 中运行: ```bash solc-select 0.5.11 cd /home/training ``` -### 通过二进制程序安装 {#binary} +### 二进制文件 {#binary} [https://github.com/crytic/echidna/releases/tag/v1.4.0.0](https://github.com/crytic/echidna/releases/tag/v1.4.0.0) ## 基于属性的模糊测试简介 {#introduction-to-property-based-fuzzing} -Echidna 是一个模糊测试工具,我们在之前的博客中描述过([1](https://blog.trailofbits.com/2018/03/09/echidna-a-smart-fuzzer-for-ethereum/)、[2](https://blog.trailofbits.com/2018/05/03/state-machine-testing-with-echidna/)、[3](https://blog.trailofbits.com/2020/03/30/an-echidna-for-all-seasons/))。 +Echidna 是一款基于属性的模糊测试工具,我们在之前的博文([1](https://blog.trailofbits.com/2018/03/09/echidna-a-smart-fuzzer-for-ethereum/)、[2](https://blog.trailofbits.com/2018/05/03/state-machine-testing-with-echidna/)、[3](https://blog.trailofbits.com/2020/03/30/an-echidna-for-all-seasons/))中介绍过它。 ### 模糊测试 {#fuzzing} -[模糊测试](https://wikipedia.org/wiki/Fuzzing)是一项在安全技术领域广为人知的技术。 它包括生成或多或少随机的算法输入,以查找程序中的漏洞。 传统软件中的模糊测试工具(例如 [AFL](http://lcamtuf.coredump.cx/afl/) 或 [LibFuzzer](https://llvm.org/docs/LibFuzzer.html))是发现错误的有效工具。 +[模糊测试](https://wikipedia.org/wiki/Fuzzing)是安全领域众所周知的一项技术。 它通过生成或多或少随机的输入来查找程序中的漏洞。 用于传统软件的模糊测试工具(例如 [AFL](http://lcamtuf.coredump.cx/afl/) 或 [LibFuzzer](https://llvm.org/docs/LibFuzzer.html))是公认的高效查漏洞工具。 -除了完全随机生成输入值外,还有很多其他的技巧和策略来生成足够好的输入,包括: +除了纯粹随机地生成输入外,还有许多技术和策略可用于生成优质输入,其中包括: -- 从每次执行中获取反馈,并使用反馈来指导输入的生成。 例如,如果新生成的输入导致发现一条新的路径,那么,生成接近该路径的新输入是有意义的。 -- 根据结构限制生成输入。 例如,如果你的输入包含一个带有校验和的报文头,则让模糊测试工具生成能够验证校验和的输入将会是很有意义的。 -- 使用已知输入生成新输入:如果你有权访问一个有效输入的大型数据集, 则模糊测试工具可以从中生成新的输入,而不是从头开始生成。 这些通常称为 _种子_。 +- 从每次执行中获取反馈,并用其指导生成。 例如,如果新生成的输入导致发现一条新路径,那么生成与其相近的新输入就是有意义的。 +- 根据结构化约束生成输入。 例如,如果你的输入包含一个带校验和的标头,那么让模糊测试工具生成能够验证该校验和的输入就是有意义的。 +- 使用已知输入生成新输入:如果你有权访问一个有效输入的大型数据集,你的模糊测试工具可以从中生成新的输入,而不是从头开始生成。 这些通常称为_种子_。 ### 基于属性的模糊测试 {#property-based-fuzzing} -Echidna 属于一种特定的模糊测试工具系列:基于属性的模糊测试,很大程度上受到了 [QuickCheck](https://wikipedia.org/wiki/QuickCheck) 的启发。 与尝试查找崩溃的经典模糊测试工具不同,Echedna 会试图去改变用户定义的不变量。 +Echidna 属于一种特定的模糊测试工具:基于属性的模糊测试,其深受 [QuickCheck](https://wikipedia.org/wiki/QuickCheck) 的启发。 与试图查找程序崩溃的传统模糊测试工具不同,Echidna 试图破坏用户定义的不变量。 -在智能合约中,不变量是 Solidity 函数,可以表示合约可能达到的任何错误或无效状态,包括: +在智能合约中,不变量是 Solidity 函数,可以表示合约可能达到的任何不正确或无效状态,包括: -- 不正确的访问控制:攻击者变成了合约的所有者。 -- 不正确的状态机:合约暂停时代币仍然可以传输。 -- 不正确的算法:用户可以余额不足的情况下获得无限的免费代币。 +- 访问控制不正确:攻击者成为合约的所有者。 +- 状态机不正确:合约暂停时仍可转移代币。 +- 算法不正确:用户可以下溢其余额并获得无限的免费代币。 -### 使用 Echidna 测试属性 {#testing-a-property-with-echidna} +### 用 Echidna 测试属性 {#testing-a-property-with-echidna} -我们来看看如何使用 Echidna 测试智能合约。 目标是以下智能合约 [`token.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/example/token.sol): +我们将了解如何使用 Echidna 测试智能合约。 目标是以下智能合约 [`token.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/example/token.sol): ```solidity contract Token{ @@ -83,26 +78,26 @@ contract Token{ } ``` -我们假定此代币必须具有以下属性: +我们假设此代币必须具有以下属性: -- 任何人最多可以持有 1000 代币 -- 代币不能转移(它不是 ERC20 代币) +- 任何人最多可以持有 1000 个代币 +- 该代币不能转移(它不是 ERC20 代币) -### 写入属性 {#write-a-property} +### 编写属性 {#write-a-property} -Echidna 的属性是 Solidity 函数。 一个属性必须: +Echidna 属性是 Solidity 函数。 一个属性必须: -- 没有任何参数 -- 如果成功就返回 `true` -- 其名字以 `echidna` 开头 +- 没有参数 +- 如果成功,返回 `true` +- 名称以 `echidna` 开头 Echidna 将: - 自动生成任意交易来测试属性。 -- 报告导致属性返回 `false` 或引发错误的任何交易。 -- 调用属性时丢弃负面影响(即,如果属性改变了一个状态变量,则在测试后会被丢弃) +- 报告导致属性返回 `false` 或抛出错误的任何交易。 +- 调用属性时放弃副作用(即,如果该属性更改了状态变量,该更改将在测试后被放弃) -以下属性会检查调用者持有的代币是否不超过 1000 个: +以下属性检查调用者持有的代币不超过 1000 个: ```solidity function echidna_balance_under_1000() public view returns(bool){ @@ -120,28 +115,28 @@ contract TestToken is Token{ } ``` -[`token.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/example/token.sol) 实现了这个属性并继承了代币。 +[`token.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/example/token.sol) 实现了该属性并继承自该代币。 ### 初始化合约 {#initiate-a-contract} -Echidna 需要一个无参 [构造函数](/developers/docs/smart-contracts/anatomy/#constructor-functions)。 如果你的合约需要特定的初始化,则需要相应地改变构造函数。 +Echidna 需要一个没有参数的[构造函数](/developers/docs/smart-contracts/anatomy/#constructor-functions)。 如果你的合约需要特定初始化,你需要在构造函数中完成。 -Echidna 中有一些特定的地址: +Echidna 中有一些特定地址: -- `0x00a329c0648769A73afAc7F9381E08FB43dBEA72` 用于调用构造函数。 -- `0x10000`、`0x20000` 和 `0x00a329C0648769a73afAC7F9381e08fb43DBEA70` 用于随机调用其他函数。 +- 调用构造函数的地址是 `0x00a329c0648769A73afAc7F9381E08FB43dBEA72`。 +- 随机调用其他函数的地址是 `0x10000`、`0x20000` 和 `0x00a329C0648769a73afAC7F9381e08fb43DBEA70`。 -在当前的示例中,我们不需要进行任何特定的初始化,因为我们的构造函数是空的。 +在我们当前的示例中,我们不需要任何特定的初始化,因此我们的构造函数是空的。 ### 运行 Echidna {#run-echidna} -用此命令启动 Echidna: +启动 Echidna 的命令是: ```bash echidna-test contract.sol ``` -如果 contract.sol 包含多个合约,你可以指定目标合约: +如果 contract.sol 包含多个合约,你可以指定目标: ```bash echidna-test contract.sol --contract MyContract @@ -172,11 +167,12 @@ echidna_balance_under_1000: failed!💥 ... ``` -如果 `backdoor` 被调用,Echidna 会发现与该属性发生冲突。 +Echidna 发现如果调用 `backdoor`,就会违反该属性。 -## 过滤在模糊测试期间要调用的函数 {#filtering-functions-to-call-during-a-fuzzing-campaign} +## 在模糊测试活动期间筛选要调用的函数 {#filtering-functions-to-call-during-a-fuzzing-campaign} -我们来了解如何过滤要进行模糊测试的函数。 目标是以下智能合约: +我们将了解如何筛选要进行模糊测试的函数。 +目标是以下智能合约: ```solidity contract C { @@ -227,7 +223,9 @@ contract C { } ``` -这个小例子迫使 Echidna 找到特定的交易序列来改变一个状态变量。 这对一个模糊测试工具来说很困难(建议使用符号执行工具,比如 [Manticore](https://github.com/trailofbits/manticore))。 我们可以运行 Echidna 对此进行验证: +这个小例子迫使 Echidna 找到一个特定的交易序列来改变状态变量。 +这对模糊测试工具来说很困难(建议使用符号执行工具,例如 [Manticore](https://github.com/trailofbits/manticore))。 +我们可以运行 Echidna 来验证这一点: ```bash echidna-test multi.sol @@ -236,18 +234,20 @@ echidna_state4: passed! 🎉 Seed: -3684648582249875403 ``` -### 过滤函数 {#filtering-functions} +### 筛选函数 {#filtering-functions} -Echidna 很难找到测试此合约的正确序列,因为两个重置函数(`reset1` 和 `reset2`)会将所有状态变量设置为 `false`。 但是,我们可以使用特殊的 Echidna 功能将重置函数列入黑名单,或者仅将 `f`、`g`、`h` 和 `i` 列入白名单。 +Echidna 难以找到测试此合约的正确序列,因为两个重置函数(`reset1` 和 `reset2`)会将所有状态变量设置为 `false`。 +但是,我们可以使用一项特殊的 Echidna 功能,将重置函数列入黑名单,或者只将 `f`、`g`、 +`h` 和 `i` 函数列入白名单。 -要将函数列入黑名单,我们可以使用下面这个配置文件: +要将函数列入黑名单,我们可以使用此配置文件: ```yaml filterBlacklist: true filterFunctions: ["reset1", "reset2"] ``` -过滤函数的另一个方法是列出白名单里的函数。 为此,我们可以使用下面这个配置文件: +筛选函数的另一种方法是列出白名单中的函数。 为此,我们可以使用此配置文件: ```yaml filterBlacklist: false @@ -255,7 +255,7 @@ filterFunctions: ["f", "g", "h", "i"] ``` - 默认情况下,`filterBlacklist` 为 `true`。 -- 只能通过名字进行过滤(不带参数)。 如果你有 `f()` 和 `f(uint256)` 两个函数,则过滤器 `"f"` 会匹配出这两个函数。 +- 筛选将仅按名称执行(不带参数)。 如果你有 `f()` 和 `f(uint256)`,过滤器 `"f"` 将同时匹配这两个函数。 ### 运行 Echidna {#run-echidna-1} @@ -272,11 +272,11 @@ echidna_state4: failed!💥 i() ``` -Echidna 几乎立刻就可以找到伪造属性的交易序列。 +Echidna 几乎会立即找到可证伪该属性的交易序列。 -### 总结:过滤函数 {#summary-filtering-functions} +### 总结:筛选函数 {#summary-filtering-functions} -在模糊测试期间,Echidna 可以将要调用的黑名单或白名单函数列入黑名单或白名单,方法是: +在模糊测试活动期间,Echidna 可以使用以下命令将函数列入黑名单或白名单: ```yaml filterBlacklist: true @@ -288,11 +288,11 @@ echidna-test contract.sol --config config.yaml ... ``` -根据 `filterBlacklist` 布尔值的不同,Echidna 开始进行模糊测试时,要么将 `f1`、`f2` 和 `f3` 列入黑名单,要么只调用它们。 +Echidna 开始模糊测试活动,根据 `filterBlacklist` 布尔值,它要么将 `f1`、`f2` 和 `f3` 列入黑名单,要么只调用这些函数。 -## 如何使用 Echidna 测试 Solidity 的断言 {#how-to-test-soliditys-assert-with-echidna} +## 如何用 Echidna 测试 Solidity 的 assert {#how-to-test-soliditys-assert-with-echidna} -在这个简短的教程中,我们将演示如何使用 Echidna 测试合约中的断言检查。 假设我们有这样一个合约: +在这个简短教程中,我们将演示如何使用 Echidna 测试合约中的断言检查。 假设我们有这样一个合约: ```solidity contract Incrementor { @@ -307,9 +307,10 @@ contract Incrementor { } ``` -### 写一个断言: {#write-an-assertion} +### 编写断言 {#write-an-assertion} -我们要确保 `tmp` 返回其差值之后,小于或等于 `counter`。 我们可以写一个 Echidna 属性,但我们需要将 `tmp` 值保存某处。 相反,我们可以使用如下断言: +我们希望确保在 `tmp` 返回其差值之后,它小于或等于 `counter`。 我们可以编写一个 +Echidna 属性,但需要将 `tmp` 值存储在某个地方。 相反,我们可以使用如下断言: ```solidity contract Incrementor { @@ -332,7 +333,7 @@ contract Incrementor { checkAsserts: true ``` -当我们在 Echidna 上运行这个合约时,我们会获得预期的结果: +当我们在 Echidna 中运行此合约时,会获得预期结果: ```bash echidna-test assert.sol --config config.yaml @@ -346,11 +347,11 @@ assertion in inc: failed!💥 Seed: 1806480648350826486 ``` -正如你所见,Echidna 在 `inc` 函数中报告了一些断言失败。 每个函数可以添加多个断言,但 Echidna 无法判断哪个断言失败了。 +如你所见,Echidna 在 `inc` 函数中报告了一些断言失败。 每个函数可以添加多个断言,但 Echidna 无法判断哪个断言失败了。 -### 使用断言的时机和方式 {#when-and-how-use-assertions} +### 何时以及如何使用断言 {#when-and-how-use-assertions} -断言可以用作显示属性的替代项,特别是如果要检查的条件与某些操作 `f` 的正确使用直接相关。 在某些代码之后添加断言将强制在代码执行后立即进行检查: +断言可以用作显式属性的替代方法,尤其是在待检查条件与某个操作 `f` 的正确使用直接相关时。 在某些代码之后添加断言将强制在该代码执行后立即进行检查: ```solidity function f(..) public { @@ -362,7 +363,7 @@ function f(..) public { ``` -相反, 使用显式的 Echidna 属性将随机执行交易,无法轻松地强制要求何时对其进行检查。 但还是可以做以下变通的: +相反,使用显式的 Echidna 属性将随机执行交易,并且无法轻松地强制在何时检查。 但还是可以做以下变通的: ```solidity function echidna_assert_after_f() public returns (bool) { @@ -373,16 +374,16 @@ function echidna_assert_after_f() public returns (bool) { 但是,也存在一些问题: -- 如果 `f` 被声明为 `internal` 或 `external` 则失败. +- 如果 `f` 声明为 `internal` 或 `external`,则会失败。 - 不清楚应该使用哪些参数来调用 `f`。 -- 如果 `f` 回滚,属性将会失败。 +- 如果 `f` 回滚,该属性将会失败。 -一般来说,我们建议遵循 [John Regehr 关于如何使用断言的建议](https://blog.regehr.org/archives/1091): +通常,我们建议遵循 [John Regehr 的建议](https://blog.regehr.org/archives/1091) 来使用断言: -- 在进行断言检查时不要强制任何负面影响。 例如: `assert(ChangeStateAndReturn() == 1)` -- 不要断言明显的语句。 例如, 在 `assert(var >= 0)` 中,`var` 被声明为 `uint`。 +- 在进行断言检查时不要强制任何副作用。 例如: `assert(ChangeStateAndReturn() == 1)` +- 不要断言明显的语句。 例如 `assert(var >= 0)`,其中 `var` 声明为 `uint`。 -最后,请**不要使用** `require` 代替 `assert`,因为 Echidna 将无法检测到它(但合约仍将回滚)。 +最后,请**不要用** `require` 代替 `assert`,因为 Echidna 无法检测到它(但合约仍会回滚)。 ### 总结:断言检查 {#summary-assertion-checking} @@ -415,9 +416,9 @@ Seed: 1806480648350826486 Echidna 发现,如果使用大参数多次调用此函数,`inc` 中的断言可能会失败。 -## 收集和修改 Echidna 预料库 {#collecting-and-modifying-an-echidna-corpus} +## 收集和修改 Echidna 语料库 {#collecting-and-modifying-an-echidna-corpus} -我们来了解如何用 Echidna 收集和使用交易语料库。 目标是以下智能合约 [`magic.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/example/magic.sol): +我们将了解如何用 Echidna 收集和使用交易语料库。 目标是以下智能合约 [`magic.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/example/magic.sol): ```solidity contract C { @@ -437,7 +438,9 @@ contract C { } ``` -这个小例子迫使 Echidna 找到一系列交易来改变一个状态变量。 这对一个模糊测试工具来说很困难(建议使用符号执行工具,比如 [Manticore](https://github.com/trailofbits/manticore))。 我们可以运行 Echidna 对此进行验证: +这个小例子迫使 Echidna 找到特定值来改变状态变量。 这对模糊测试工具来说很困难 +(建议使用符号执行工具,例如 [Manticore](https://github.com/trailofbits/manticore))。 +我们可以运行 Echidna 来验证这一点: ```bash echidna-test magic.sol @@ -448,17 +451,17 @@ echidna_magic_values: passed! 🎉 Seed: 2221503356319272685 ``` -然而,当我们运行该模糊测试活动时,我们仍然可以使用 Echidna 来收集语料库。 +但是,在运行此模糊测试活动时,我们仍然可以使用 Echidna 来收集语料库。 ### 收集语料库 {#collecting-a-corpus} -为了启用语料库的收集,请创建一个语料目录: +要启用语料库收集,请创建一个语料库目录: ```bash mkdir corpus-magic ``` -和一个 [Echidna 配置文件](https://github.com/crytic/echidna/wiki/Config) `config.yaml`: +以及一个 [Echidna 配置文件](https://github.com/crytic/echidna/wiki/Config) `config.yaml`: ```yaml coverage: true @@ -471,7 +474,8 @@ corpusDir: "corpus-magic" echidna-test magic.sol --config config.yaml ``` -Echidna 仍然找不到正确的 magic 值,但我们可以看一看它收集到的语料库。 例如,其中一个文件是: +Echidna 仍然找不到正确的 magic 值,但我们可以查看它收集的语料库。 +例如,其中一个文件是: ```json [ @@ -516,11 +520,12 @@ Echidna 仍然找不到正确的 magic 值,但我们可以看一看它收集 ] ``` -显然,此输入不会触发我们属性中的故障。 但是,在下一步,我们将看到如何对此进行修改。 +显然,此输入不会触发我们属性中的失败。 但是,在下一步中,我们将了解如何为此修改它。 -### 为语料库生成种子 {#seeding-a-corpus} +### 为语料库提供种子 {#seeding-a-corpus} -Echidna 需要一些帮助才能处理 `magic` 函数。 我们将复制和修改输入以使用其合适的参数: +Echidna 需要一些帮助才能处理 `magic` 函数。 我们将复制并修改输入以使用其 +合适的参数: ```bash cp corpus/2712688662897926208.txt corpus/new.txt @@ -542,11 +547,11 @@ Seed: -7293830866560616537 ``` -这一次,它立即发现与该属性发生了冲突。 +这一次,它立即发现违反了该属性。 -## 查找消耗大量燃料的交易 {#finding-transactions-with-high-gas-consumption} +## 查找高燃料消耗的交易 {#finding-transactions-with-high-gas-consumption} -我们来看看如何使用 Echidna 查找燃料消耗大的交易。 目标是以下智能合约: +我们将了解如何使用 Echidna 查找高燃料消耗的交易。 目标是以下智能合约: ```solidity contract C { @@ -571,9 +576,10 @@ contract C { } ``` -这里的 `expensive` 可能会消耗大量 gas。 +这里的 `expensive` 可能有很大的燃料消耗。 -目前,Echidna 总是需要一个属性来测试:这里 `echidna_test` 始终返回 `true`。 我们可以运行 Echidna 对此进行验证: +目前,Echidna 总是需要一个属性来测试:这里 `echidna_test` 总是返回 `true`。 +我们可以运行 Echidna 来验证这一点: ``` echidna-test gas.sol @@ -617,12 +623,13 @@ Seed: -325611019680165325 ``` -- 显示的燃料是由 [HEVM](https://github.com/dapphub/dapptools/tree/master/src/hevm#hevm-) 提供的估值。 +- 所示燃料是由 [HEVM](https://github.com/dapphub/dapptools/tree/master/src/hevm#hevm-) 提供的估算值。 -### 过滤掉燃料消耗减少的调用 {#filtering-out-gas-reducing-calls} +### 筛选出减少燃料的调用 {#filtering-out-gas-reducing-calls} -以上关于**在模糊测试活动期间过滤要调用的函数**的教程展示了如何从测试中删除一些函数。 -这对于获得准确的燃料消耗至关重要。 请考虑下面的示例: +上面关于**在模糊测试活动中筛选要调用的函数**的教程介绍了如何从测试中移除某些函数。 +这对于获得准确的燃料估算至关重要。 +请考虑下面的示例: ```solidity contract C { @@ -653,16 +660,17 @@ contract C { ``` echidna-test pushpop.sol --config config.yaml ... -pop used a maximum of 10746 gas +pop 最多使用 10746 燃料 ... -check used a maximum of 23730 gas +check 最多使用 23730 燃料 ... -clear used a maximum of 35916 gas +clear 最多使用 35916 燃料 ... -push used a maximum of 40839 gas +push 最多使用 40839 燃料 ``` -这是因为成本取决于 `addrs` 的大小,而随机调用往往会使数组几乎为空。 将 `pop` 和 `clear` 加入黑名单却给我们带来了更好的结果: +这是因为成本取决于 `addrs` 的大小,而随机调用往往会使数组几乎为空。 +将 `pop` 和 `clear` 加入黑名单却给我们带来了更好的结果: ```yaml filterBlacklist: true @@ -672,12 +680,12 @@ filterFunctions: ["pop", "clear"] ``` echidna-test pushpop.sol --config config.yaml ... -push used a maximum of 40839 gas +push 最多使用 40839 燃料 ... -check used a maximum of 1484472 gas +check 最多使用 1484472 燃料 ``` -### 总结:查找消耗大量燃料的交易 {#summary-finding-transactions-with-high-gas-consumption} +### 总结:查找高燃料消耗的交易 {#summary-finding-transactions-with-high-gas-consumption} Echidna 可以使用 `estimateGas` 配置选项找到消耗大量燃料的交易: diff --git a/public/content/translations/zh/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/index.md b/public/content/translations/zh/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/index.md index c2d60116876..dac9c9f5e07 100644 --- a/public/content/translations/zh/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/index.md +++ b/public/content/translations/zh/developers/tutorials/how-to-use-manticore-to-find-smart-contract-bugs/index.md @@ -1,120 +1,115 @@ --- -title: 如何使用Manticore来发现智能合约漏洞 -description: 如何使用Manticore来自动发现智能合约漏洞 +title: "如何使用 Manticore 发现智能合约中的漏洞" +description: "如何使用 Manticore 自动发现智能合约中的漏洞" author: Trailofbits lang: zh -tags: - - "solidity" - - "智能合约" - - "安全性" - - "测试" - - "形式化验证" +tags: [ "Solidity", "智能合同", "安全性。", "测试", "形式化验证" ] skill: advanced published: 2020-01-13 -source: 构建安全的合约 +source: "构建安全的合约" sourceUrl: https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/manticore --- -本教程的目的是展示如何使用Manticore自动发现智能合约中的漏洞。 +本教程的目的是展示如何使用 Manticore 自动发现智能合约中的漏洞。 ## 安装 {#installation} -Manticore需要使用python 3.6。 它可以通过pip或使用docker来安装。 +Manticore 需要 Python 3.6 或更高版本。 它可以通过 pip 或使用 docker 来安装。 -### 使用docker的Manticore {#manticore-through-docker} +### 通过 docker 使用 Manticore {#manticore-through-docker} ```bash docker pull trailofbits/eth-security-toolbox docker run -it -v "$PWD":/home/training trailofbits/eth-security-toolbox ``` -_最后一个命令在一个可访问你当前目录的docker中运行eth-security工具箱。 你可以更改你主机中的文件,并从docker中运行文件上的工具_ +_最后一个命令在一个可访问你当前目录的 docker 中运行 eth-security-toolbox。 你可以从主机更改文件,并在 docker 中对文件运行工具_ -在docker中,运行: +在 docker 中,运行: ```bash solc-select 0.5.11 cd /home/trufflecon/ ``` -### 使用pip的Manticore {#manticore-through-pip} +### 通过 pip 使用 Manticore {#manticore-through-pip} ```bash pip3 install --user manticore ``` -建议采用solc 0.5.11。 +建议使用 solc 0.5.11。 ### 运行脚本 {#running-a-script} -使用python 3运行一个python脚本: +使用 python 3 运行 python 脚本: ```bash python3 script.py ``` -## 动态符号化执行简介 {#introduction-to-dynamic-symbolic-execution} +## 动态符号执行简介 {#introduction-to-dynamic-symbolic-execution} -### Nutshell中的动态符号化执行 {#dynamic-symbolic-execution-in-a-nutshell} +### 动态符号执行简述 {#dynamic-symbolic-execution-in-a-nutshell} -动态符号化执行(DSE)是一种程序分析技术,用于探究具有高度语义意识的状态空间。 这项技术是基于 "程序路径"的发现 ,以一种称为`path predicates`的数学公式表示。 就概念来说,这种技术对路径预测的操作分为两步: +动态符号执行 (DSE) 是一种程序分析技术,可利用高度的语义感知来探索状态空间。 这项技术基于对“程序路径”的发现,这些路径表示为称为`路径谓词`的数学公式。 从概念上讲,此技术分两步对路径谓词进行操作: 1. 它们是利用对程序输入的约束来构建的。 2. 它们被用来生成程序输入,从而导致相关路径的执行。 -这种方法不会产生误报,因为所有被识别的程序状态都可以在具体执行过程中被触发。 例如,如果分析发现了一个整数溢出,就可以保证它是可重现的 +这种方法不会产生误报,因为所有被识别的程序状态都可以在具体执行过程中被触发。 例如,如果分析发现了一个整数溢出,就可以保证它是可重现的。 -### 路径预测示例 {#path-predicate-example} +### 路径谓词示例 {#path-predicate-example} -为了了解DSE如何工作,请考虑以下示例: +为了了解 DSE 如何工作,请考虑以下示例: ```solidity -f(uint a). - - if (aa== 65) } - // bug 存在 +function f(uint a){ + if (a == 65) { + // 存在一个漏洞 + } } ``` -因为f()包含两个路径,DSE将构建两个不同的路径预测: +由于 `f()` 包含两条路径,DSE 将构建两个不同的路径谓词: -- 路径1: `a == 65` -- 路径 2: `Not (a == 65)` +- 路径 1:`a == 65` +- 路径 2:`Not (a == 65)` -每个路径预测都是一个数学公式,可以传递给所谓的 [SMT 求解器](https://wikipedia.org/wiki/Satisfiability_modulo_theories),求解器将尝试解方程式。 对于`路径1`,求解器会说,可以用`a=65`探索路径。 对于`路径2`,求解器可以给`a`指定一个65以外的任何值,例如`a=0`。 +每个路径谓词都是一个数学公式,可以将其提供给所谓的 [SMT 求解器](https://wikipedia.org/wiki/Satisfiability_modulo_theories),求解器会尝试求解该方程式。 对于“路径 1”,求解器会指出可以使用 `a = 65` 探索该路径。 对于“路径 2”,求解器可以为 `a` 指定一个 65 以外的任何值,例如 `a = 0`。 ### 验证属性 {#verifying-properties} -Manticore允许完全控制每个路径的所有执行情况。 因此,它允许你在几乎任何东西上添加任意限制。 这种控制允许在合约上创建财产。 +Manticore 允许完全控制每个路径的所有执行情况。 因此,它允许你为几乎任何东西添加任意约束。 这种控制允许在合约上创建属性。 请考虑下面的示例: ```solidity -function unsafe_add(uint a, uint b) returns(uint c)。 - c = a + b;// no overflow protection - return c; +function unsafe_add(uint a, uint b) returns(uint c){ + c = a + b; // 没有溢出保护 + return c; } ``` 函数中只有一个要探索的路径: -- 路径1: `c = a + b` +- 路径 1:`c = a + b` -使用Manticore,你可以对溢出进行检查,并对路径预测加以限制: +使用 Manticore,你可以检查溢出,并向路径谓词添加约束: - `c = a + b AND (c < a OR c < b)` -如果有可能找到一个`a`和`b`的估值,对于这个估值,上面的路径预测是可行的,这意味着你发现了一个溢出。 例如,求解器可以生成输入`a = 10 , b = MAXUINT256`。 +如果可以为 `a` 和 `b` 找到一个使上述路径谓词可行的赋值,则意味着你发现了一个溢出。 例如,求解器可以生成输入 `a = 10, b = MAXUINT256`。 -如果你考虑一个固定版本: +如果你考虑一个修复后的版本: ```solidity function safe_add(uint a, uint b) returns(uint c){ c = a + b; - require(c->=a); - require(c)>=b); + require(c>=a); + require(c>=b); return c; } ``` @@ -123,13 +118,13 @@ function safe_add(uint a, uint b) returns(uint c){ - `c = a + b AND (c >= a) AND (c=>b) AND (c < a OR c < b)` -这个公式无法得以解决;在其他领域,这是一个在`safe_add`中,`c`总会增加的**证明**。 +这个公式无法求解;换句话说,这**证明**了在 `safe_add` 中,`c` 的值总是会增加。 -因此,DSE是一个强大的工具,可以验证你代码的任意限制。 +因此,DSE 是一个强大的工具,可以验证你代码中的任意约束。 -## 在Manticore下运行 {#running-under-manticore} +## 在 Manticore 下运行 {#running-under-manticore} -我们将看到如何探索使用Manticore API的智能合约。 目标是以下智能合约[`example.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example.sol): +我们将了解如何使用 Manticore 应用程序接口来探索智能合约。 目标是以下智能合约 [`example.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example.sol): ```solidity pragma solidity >=0.4.24 <0.6.0; @@ -143,15 +138,15 @@ contract Simple { } ``` -### 运行一个独立的探索方式 {#run-a-standalone-exploration} +### 运行独立探索 {#run-a-standalone-exploration} -你可以通过以下命令直接在智能合约上运行Manticore(`project`可以是一个Solidity文件,或者是项目目录): +你可以通过以下命令直接在智能合约上运行 Manticore(`project` 可以是一个 Solidity 文件,或者是项目目录): ```bash $ manticore project ``` -你将会获得像这个一样的测试案例输出(顺序可能有变): +你将会获得像下面这样的测试用例输出(顺序可能有变): ``` ... @@ -166,37 +161,37 @@ $ manticore project ... ``` -在没有额外信息的情况下,Manticore将利用新的符号交易探索智能合约,直到它不再探索合约上的新途径为止。 Manticore不会在失败后执行新的交易(如恢复原状后)。 +在没有额外信息的情况下,Manticore 将利用新的符号交易探索合约,直到它不再探索合约上的新路径为止。 Manticore 不会在失败后(例如:回滚后)执行新的交易。 -Manticore将在一个`mcore_*`目录中输出信息。 除其他外,你将在这个目录中找到: +Manticore 将在一个 `mcore_*` 目录中输出信息。 除其他外,你将在这个目录中找到: -- `global.summary`:覆盖面和编译器警告 -- `test_XXXXX.summary`:覆盖面、前一次的说明、每次测试案例的帐户余额 -- `test_XXXXX.tx`:每个测试案例的交易详细列表 +- `global.summary`:覆盖率和编译器警告 +- `test_XXXXX.summary`:每个测试用例的覆盖率、最后一条指令、账户余额 +- `test_XXXXX.tx`:每个测试用例的交易详细列表 -在这里,Manticore发现了7个测试案例,它们对应于(文件名顺序可能会改变): +在这里,Manticore 发现了 7 个测试用例,它们对应于(文件名顺序可能会改变): -| | 交易0 | 交易1 | 交易2 | 结果 | -|:--------------------:|:----:|:-------:| ------- |:--:| -| **test_00000000.tx** | 合约创建 | f(!=65) | f(!=65) | 停止 | -| **test_00000001.tx** | 合约创建 | 回退函数 | | 撤销 | -| **test_00000002.tx** | 合约创建 | | | 返回 | -| **test_00000003.tx** | 合约创建 | f(65) | | 撤销 | -| **test_00000004.tx** | 合约创建 | f(!=65) | | 停止 | -| **test_00000005.tx** | 合约创建 | f(!=65) | f(65) | 撤销 | -| **test_00000006.tx** | 合约创建 | f(!=65) | 回退函数 | 撤销 | +| | 交易 0 | 交易 1 | 交易 2 | 结果 | +| :-------------------------------------------------------: | :--: | :------------------------: | -------------------------- | :----: | +| **test_00000000.tx** | 合约创建 | f(!=65) | f(!=65) | STOP | +| **test_00000001.tx** | 合约创建 | 回退函数 | | REVERT | +| **test_00000002.tx** | 合约创建 | | | RETURN | +| **test_00000003.tx** | 合约创建 | f(65) | | REVERT | +| **test_00000004.tx** | 合约创建 | f(!=65) | | STOP | +| **test_00000005.tx** | 合约创建 | f(!=65) | f(65) | REVERT | +| **test_00000006.tx** | 合约创建 | f(!=65) | 回退函数 | REVERT | -_检索摘要f(!=65)表示使用不同于65的任何值调用的调用的f。_ +_探索摘要 f(!=65) 表示 f 是以任何非 65 的值调用的。_ -正如你可以注意到的那样,Manticore为每个成功或撤销的交易生成一个独特的测试案例。 +正如你可以注意到的那样,Manticore 为每个成功或回滚的交易生成一个独特的测试用例。 -如果你想要快速的代码检查,请使用`--quick-mode`标志(它禁用bug检测器、gas计算...) +如果你想要快速的代码探索,请使用 `--quick-mode` 标志(它会禁用漏洞检测器、燃料计算...) -### 通过API操纵智能合约 {#manipulate-a-smart-contract-through-the-api} +### 通过应用程序接口操纵智能合约 {#manipulate-a-smart-contract-through-the-api} -本节介绍如何通过Manticore Python API操纵智能合约的细节。 你可以使用python 扩展名`*.py`创建新文件,并通过将API命令(下面将介绍其基础内容)添加到这个文件中来写入必要的代码,然后使用`$ python3 *.py`命令运行它。 你也可以直接在python控制台中执行下面的指令,使用`$python3`命令来运行控制台。 +本节详细介绍如何通过 Manticore Python 应用程序接口操纵智能合约。 你可以创建扩展名为 `*.py` 的新 Python 文件,通过将应用程序接口命令(下文会介绍其基础知识)添加到此文件中来编写必要的代码,然后使用 `$ python3 *.py` 命令运行它。 你也可以直接在 python 控制台中执行下面的命令,使用 `$ python3` 命令来运行控制台。 -### 创建帐户 {#creating-accounts} +### 创建账户 {#creating-accounts} 首先,你要通过以下命令启动一个新的区块链: @@ -206,13 +201,13 @@ from manticore.ethereum import ManticoreEVM m = ManticoreEVM() ``` -使用 [m.create_account](https://manticore.readthedocs.io/en/latest/evm.html?highlight=create_account#manticore.ethereum.ManticoreEVM.create_account) 创建一个非合约账号: +使用 [m.create_account](https://manticore.readthedocs.io/en/latest/evm.html?highlight=create_account#manticore.ethereum.ManticoreEVM.create_account) 创建一个非合约账户: ```python user_account = m.create_account(balance=1000) ``` -可以使用 [m.solidity_create_contract](https://manticore.readthedocs.io/en/latest/evm.html?highlight=solidity_create#manticore.ethereum.ManticoreEVM.create_contract) 部署一个 Solidity 合约: +可以使用 [m.solidity_create_contract](https://manticore.readthedocs.io/en/latest/evm.html?highlight=solidity_create#manticore.ethereum.ManticoreEVM.create_contract) 部署 Solidity 合约: ```solidity source_code = ''' @@ -225,19 +220,19 @@ contract Simple { } } ''' -# Initiate the contract +# 初始化合约 contract_account = m.solidity_create_contract(source_code, owner=user_account) ``` -#### 概览 {#summary} +#### 总结 {#summary} -- 可以使用 [m.create_account](https://manticore.readthedocs.io/en/latest/evm.html?highlight=create_account#manticore.ethereum.ManticoreEVM.create_account) 和 [m.solidity_create_contract](https://manticore.readthedocs.io/en/latest/evm.html?highlight=solidity_create#manticore.ethereum.ManticoreEVM.create_contract) 创建用户帐户和合约帐户。 +- 你可以使用 [m.create_account](https://manticore.readthedocs.io/en/latest/evm.html?highlight=create_account#manticore.ethereum.ManticoreEVM.create_account) 和 [m.solidity_create_contract](https://manticore.readthedocs.io/en/latest/evm.html?highlight=solidity_create#manticore.ethereum.ManticoreEVM.create_contract) 来创建用户账户和合约账户。 ### 执行交易 {#executing-transactions} -Manticore支持两种类型的交易: +Manticore 支持两种类型的交易: -- 原始交易:已探索所有函数 +- 原始交易:探索所有函数 - 命名交易:只探索一个函数 #### 原始交易 {#raw-transaction} @@ -251,10 +246,10 @@ m.transaction(caller=user_account, value=value) ``` -调用者、地址、数据或交易的值可以是具体的或抽象的: +交易的调用者、地址、数据或值,既可以是具体的,也可以是符号的: - [m.make_symbolic_value](https://manticore.readthedocs.io/en/latest/evm.html?highlight=make_symbolic_value#manticore.ethereum.ManticoreEVM.make_symbolic_value) 创建一个符号值。 -- [mmmake_symbolic_buffer(size)](https://manticore.readthedocs.io/en/latest/evm.html?highlight=make_symbolic_buffer#manticore.ethereum.ManticoreEVM.make_symbolic_buffer) 创建一个符号字节数组。 +- [m.make_symbolic_buffer(size)](https://manticore.readthedocs.io/en/latest/evm.html?highlight=make_symbolic_buffer#manticore.ethereum.ManticoreEVM.make_symbolic_buffer) 创建一个符号字节数组。 例如: @@ -267,28 +262,29 @@ m.transaction(caller=user_account, value=symbolic_value) ``` -如果数据是象征性的,Manticore将在交易执行期间探索合约中的所有函数。 查看[Hands on the Ethernaut CTF](https://blog.trailofbits.com/2017/11/06/hands-on-the-ethernaut-ctf/)文章中的回退函数解释,对于理解函数选择的工作原理会有所帮助。 +如果数据是符号的,Manticore 将在交易执行期间探索合约的所有函数。 查看[“Ethernaut CTF 实战”](https://blog.trailofbits.com/2017/11/06/hands-on-the-ethernaut-ctf/)文章中的回退函数解释,对于理解函数选择的工作原理会有所帮助。 #### 命名交易 {#named-transaction} -函数可以通过其的名称执行。 要使用user_account中的符号值以及0 ether执行`f(uint var)`,请使用: +函数可以通过其的名称执行。 +要使用 `user_account` 中的符号值以及 0 ETH 执行 `f(uint var)`,请使用: ```python symbolic_var = m.make_symbolic_value() contract_account.f(symbolic_var, caller=user_account, value=0) ``` -如果没有指定交易的`value`,则默认为0。 +如果没有指定交易的 `value`,则默认为 0。 -#### 概览 {#summary-1} +#### 总结 {#summary-1} -- 交易的参数可以是具体的或抽象的 +- 交易的参数可以是具体的或符号的 - 原始交易将探索所有函数 - 函数可以通过其名称来调用 ### 工作区 {#workspace} -`m.workspace`目录用作所有生成的文件的输出目录: +`m.workspace` 目录用作所有生成的文件的输出目录: ```python print("Results are in {}".format(m.workspace)) @@ -296,9 +292,9 @@ print("Results are in {}".format(m.workspace)) ### 终止探索 {#terminate-the-exploration} -要停止探索,请使用 [m.finalize()](https://manticore.readthedocs.io/en/latest/evm.html?highlight=finalize#manticore.ethereum.ManticoreEVM.finalize)。 一旦这个方法被调用,就不应该再发送任何交易,而且Manticore会针对所探索的每一条路径生成测试案例。 +使用 [m.finalize()](https://manticore.readthedocs.io/en/latest/evm.html?highlight=finalize#manticore.ethereum.ManticoreEVM.finalize) 停止探索。 一旦这个方法被调用,就不应该再发送任何交易,而且 Manticore 会针对所探索的每一条路径生成测试用例。 -### 总结:在Manticore下运行 {#summary-running-under-manticore} +### 总结:在 Manticore 下运行 {#summary-running-under-manticore} 将所有先前的步骤放在一起,我们就会得到: @@ -317,14 +313,14 @@ symbolic_var = m.make_symbolic_value() contract_account.f(symbolic_var) print("Results are in {}".format(m.workspace)) -m.finalize() # stop the exploration +m.finalize() # 停止探索 ``` -以上所有代码都可以在[`example_run.py`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example_run.py)中找到。 +以上所有代码都可以在 [`example_run.py`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example_run.py) 中找到 -## 获取投掷路径 {#getting-throwing-paths} +## 获取抛出路径 {#getting-throwing-paths} -我们现在将为路径生成特定的输入,以在`f()`中引发异常。 目标仍为以下智能合约 [`example.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example.sol)。 +我们现在将为路径生成特定的输入,以在 `f()` 中引发异常。 目标仍然是以下智能合约 [`example.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example.sol): ```solidity pragma solidity >=0.4.24 <0.6.0; @@ -339,45 +335,45 @@ contract Simple { ### 使用状态信息 {#using-state-information} -执行的每个路径都有其区块链的状态。 此状态要么是准备就绪,要么是被终止了,也就是说,它达到了THROW或REVERT指令状态。 +执行的每个路径都有其区块链的状态。 此状态要么是准备就绪,要么是被终止了,也就是说,它达到了 THROW 或 REVERT 指令状态。 -- [m.ready_states](https://manticore.readthedocs.io/en/latest/states.html#accessing): 已准备就绪状态列表(他们没有执行REVERT/INVALID) -- [m.killed_states](https://manticore.readthedocs.io/en/latest/states.html#accessings):终止状态列表 +- [m.ready_states](https://manticore.readthedocs.io/en/latest/states.html#accessing):准备就绪(它们没有执行 REVERT/INVALID)的状态列表 +- [m.killed_states](https://manticore.readthedocs.io/en/latest/states.html#accessings):已终止状态的列表 - [m.all_states](https://manticore.readthedocs.io/en/latest/states.html#accessings):所有状态 ```python for state in m.all_states: - # do something with state + # 对状态执行某些操作 ``` 你可以访问状态信息。 例如: -- `state.platform.get_balance(account.address)`:帐户余额 +- `state.platform.get_balance(account.address)`:账户的余额 - `state.platform.transactions`:交易列表 - `state.platform.transactions[-1].return_data`:最后一笔交易返回的数据 -最后一笔交易返回的数据是一个数组,可以用ABI.deserialize转换为一个值,例如: +最后一笔交易返回的数据是一个数组,可以用 ABI.deserialize 转换为一个值,例如: ```python data = state.platform.transactions[0].return_data data = ABI.deserialize("uint", data) ``` -### 如何生成测试案例 {#how-to-generate-testcase} +### 如何生成测试用例 {#how-to-generate-testcase} -使用 [m.generate_testcase(state, name)](https://manticore.readthedocs.io/en/latest/evm.html?highlight=generate_testcase#manticore.ethereum.ManticoreEVM.generate_testcase) 生成测试案例: +使用 [m.generate_testcase(state, name)](https://manticore.readthedocs.io/en/latest/evm.html?highlight=generate_testcase#manticore.ethereum.ManticoreEVM.generate_testcase) 生成测试用例: ```python -m. generate_testcase(state, 'BugFound') +m.generate_testcase(state, 'BugFound') ``` -### 概览 {#summary-2} +### 总结 {#summary-2} -- 你可以使用m.all_states对状态进行迭代 -- `state.platform.get_balance(account.adds)`返回帐户余额 -- `state.platform.transactions`返回交易列表 -- `transaction.return_data`是返回的数据 -- `m.generate_testcase(state, name)`为状态生成输入 +- 你可以使用 m.all_states 迭代状态 +- `state.platform.get_balance(account.address)` 返回账户的余额 +- `state.platform.transactions` 返回交易列表 +- `transaction.return_data` 是返回的数据 +- `m.generate_testcase(state, name)` 为状态生成输入 ### 总结:获取抛出路径 {#summary-getting-throwing-path} @@ -395,7 +391,7 @@ contract_account = m.solidity_create_contract(source_code, owner=user_account) symbolic_var = m.make_symbolic_value() contract_account.f(symbolic_var) -## Check if an execution ends with a REVERT or INVALID +## 检查执行是否以 REVERT 或 INVALID 结束 for state in m.terminated_states: last_tx = state.platform.transactions[-1] if last_tx.result in ['REVERT', 'INVALID']: @@ -403,13 +399,13 @@ for state in m.terminated_states: m.generate_testcase(state, 'ThrowFound') ``` -以上所有代码都可以在[`example_run.py`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example_run.py)中找到。 +以上所有代码都可以在 [`example_run.py`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example_run.py) 中找到 -_注意我们可以生成一个更简单的脚本,因为所有由terminated_state返回的状态在其结果中都有REVERT或INVALID:这个例子只是为了演示如何操作API。_ +_请注意,我们本可以生成一个更简单的脚本,因为 terminated_state 返回的所有状态在其结果中都有 REVERT 或 INVALID:本示例仅用于演示如何操纵应用程序接口。_ -## 添加限制 {#adding-constraints} +## 添加约束 {#adding-constraints} -我们将看到如何对探索加以约束。 我们将作出这样的假设:`f()`的文档指出,该函数从未在`a == 65`的情况下被调用,因此任何`a == 65`的错误都不是真正的错误。 目标仍为以下智能合约[`example.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example.sol): +我们将看到如何对探索加以约束。 我们将作出这样的假设:`f()` 的文档指出,该函数从未在 `a == 65` 的情况下被调用,因此任何 `a == 65` 的错误都不是真正的错误。 目标仍然是以下智能合约 [`example.sol`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example.sol): ```solidity pragma solidity >=0.4.24 <0.6.0; @@ -422,16 +418,16 @@ contract Simple { } ``` -### 运算符 {#operators} +### 操作符 {#operators} -[运算符](https://github.com/trailofbits/manticore/blob/master/manticore/core/smtlib/operators.py)模块使约束操作变得简便,除此之外,它还提供了其他功能: +[Operators](https://github.com/trailofbits/manticore/blob/master/manticore/core/smtlib/operators.py) 模块有助于操纵约束,它提供了以下操作符: -- Operators.AND, -- Operators.OR, -- Operators.UGT(无符号大小), -- Operators.UGE(无符号大于或等于), +- Operators.AND, +- Operators.OR, +- Operators.UGT(无符号大于), +- Operators.UGE(无符号大于等于), - Operators.ULT(无符号小于), -- Operators.ULE(无符号小于或等于)。 +- Operators.ULE(无符号小于等于)。 请使用以下代码导入模块: @@ -439,10 +435,10 @@ contract Simple { from manticore.core.smtlib import Operators ``` -`Operators.CONCAT`用于将一个数组与一个值级联。 例如,一个交易的return_data需要转变为一个值,以便与另一个值进行检查对比: +`Operators.CONCAT` 用于将一个数组与一个值级联。 例如,一个交易的 return_data 需要转变为一个值,以便与另一个值进行检查对比: ```python -last_return = operators.CONCAT(256,*last_return) +last_return = Operators.CONCAT(256, *last_return) ``` ### 约束 {#state-constraint} @@ -451,7 +447,8 @@ last_return = operators.CONCAT(256,*last_return) #### 全局约束 {#state-constraint} -使用 `m.constrain(constraint)` 添加全局约束。 例如,你可以从一个符号地址调用合约,并将这个地址约束为特定的值: +使用 `m.constrain(constraint)` 添加全局约束。 +例如,你可以从一个符号地址调用合约,并将这个地址约束为特定的值: ```python symbolic_address = m.make_symbolic_value() @@ -464,19 +461,21 @@ m.transaction(caller=user_account, #### 状态约束 {#state-constraint} -使用 [state.constrain(constraint)](https://manticore.readthedocs.io/en/latest/states.html?highlight=StateBase#manticore.core.state.StateBase.constrain) 为一个特定状态添加约束。 该约束可用来在探索状态后对其进行约束,以检查状态上的某些属性。 +使用 [state.constrain(constraint)](https://manticore.readthedocs.io/en/latest/states.html?highlight=StateBase#manticore.core.state.StateBase.constrain) 为特定状态添加约束。 +它可用于在探索状态后对其进行约束,以检查状态上的某些属性。 ### 检查约束 {#checking-constraint} -使用`solver.check(state.constracts)`来了解约束是否仍然可行。 例如,以下代码将symbolic_value限定为不等于65 ,并检查状态是否仍然可行。 +使用 `solver.check(state.constraints)` 来了解约束是否仍然可行。 +例如,以下代码将 `symbolic_value` 限定为不等于 65,并检查状态是否仍然可行: ```python state.constrain(symbolic_var != 65) if solver.check(state.constraints): - # state is feasible + # 状态可行 ``` -### 摘要:添加限制因素 {#summary-adding-constraints} +### 总结:添加约束 {#summary-adding-constraints} 通过在前面的代码中添加约束,我们获得: @@ -499,11 +498,11 @@ contract_account.f(symbolic_var) no_bug_found = True -## Check if an execution ends with a REVERT or INVALID +## 检查执行是否以 REVERT 或 INVALID 结束 for state in m.terminated_states: last_tx = state.platform.transactions[-1] if last_tx.result in ['REVERT', 'INVALID']: - # we do not consider the path were a == 65 + # 我们不考虑 a == 65 的路径 condition = symbolic_var != 65 if m.generate_testcase(state, name="BugFound", only_if=condition): print(f'Bug found, results are in {m.workspace}') @@ -513,4 +512,4 @@ if no_bug_found: print(f'No bug found') ``` -以上所有代码都可以在[`example_run.py`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example_run.py)中找到。 +以上所有代码都可以在 [`example_run.py`](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/manticore/examples/example_run.py) 中找到 diff --git a/public/content/translations/zh/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/index.md b/public/content/translations/zh/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/index.md index c571adc1914..8c0ca2757b9 100644 --- a/public/content/translations/zh/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/index.md +++ b/public/content/translations/zh/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/index.md @@ -1,58 +1,53 @@ --- -title: 如何使用Slither发现智能合约漏洞 -description: 如何使用Slither自动发现智能合约中的漏洞 +title: "如何使用 Slither 查找智能合约漏洞" +description: "如何使用 Slither 自动发现智能合约中的漏洞" author: Trailofbits lang: zh -tags: - - "solidity" - - "智能合约" - - "安全性" - - "测试" - - "静态分析" +tags: [ "Solidity", "智能合同", "安全性。", "测试" ] skill: advanced published: 2020-06-09 -source: 构建安全的合约 +source: "构建安全的合约" sourceUrl: https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/slither --- -## 如何使用Slither {#how-to-use-slither} +## 如何使用 Slither {#how-to-use-slither} -本教程的目的是演示如何使用Slither自动查找智能合约中的漏洞。 +本教程的目的是演示如何使用 Slither 自动查找智能合约中的漏洞。 - [安装](#installation) -- [命令行使用方法](#command-line) +- [命令行用法](#command-line) - [静态分析简介](#static-analysis):静态分析简介 -- [API](#api-basics):Python API说明 +- [API](#api-basics):Python API 说明 ## 安装 {#installation} -Slither需要Python3.6及以上版本。 它可以通过pip安装或使用docker。 +Slither 需要 Python >= 3.6。 它可以通过 pip 或使用 docker 来安装。 -通过pip安装Slither: +通过 pip 安装 Slither: ```bash pip3 install --user slither-analyzer ``` -通过docker安装Slither: +通过 docker 安装 Slither: ```bash -docker pull trailofbits/eth-securitytoolbox -docker run-it -v "$PWD":/home/trufflecon trailofbits/eth-securitytoolbox +docker pull trailofbits/eth-security-toolbox +docker run -it -v "$PWD":/home/trufflecon trailofbits/eth-security-toolbox ``` -_上文中最后一个命令在docker中运行eth-security-toolbox命令。该eth-security-toolbox命令需要能访问你的当前目录。 你可以从自己的主机更改文件,并在docker中运行针对文件这些工具。_ +_最后一个命令在一个可访问你当前目录的 docker 中运行 eth-security-toolbox。 你可以从主机更改文件,并在 docker 中对文件运行工具_ -在docker中,运行如下命令: +在 docker 中,运行: ```bash -sol-select 0.5.11 +solc-select 0.5.11 cd /home/trufflecon/ ``` ### 运行脚本 {#running-a-script} -使用python 3运行如下python脚本: +使用 python 3 运行 python 脚本: ```bash python3 script.py @@ -60,37 +55,37 @@ python3 script.py ### 命令行 {#command-line} -**命令行与用户定义的脚本。**Slither带有一组预定义的探测器,可以找到许多常见的漏洞。 从命令行调用Slither将运行所有的检测器,不需要使用者具有详细的静态分析知识。 +**命令行与用户定义的脚本。** Slither 带有一组预定义的探测器,可以找到许多常见的漏洞。 从命令行调用 Slither 将运行所有的检测器,不需要使用者具有详细的静态分析知识: ```bash slither project_paths ``` -除了检测器之外,Slither还通过其[打印机](https://github.com/crytic/slither#printers)和[工具](https://github.com/crytic/slither#tools)提供代码审查功能。 +除了探测器,Slither 还通过其[打印器](https://github.com/crytic/slither#printers)和[工具](https://github.com/crytic/slither#tools)提供代码审查功能。 使用 [crytic.io](https://github.com/crytic) 以获得对私有探测器和 GitHub 集成功能的访问权限。 ## 静态分析 {#static-analysis} -Slither静态分析框架的功能和设计已在博客文章([1](https://blog.trailofbits.com/2018/10/19/slither-a-solidity-static-analysis-framework/),[2](https://blog.trailofbits.com/2019/05/27/slither-the-leading-static-analyzer-for-smart-contracts/))和一篇[学术论文](https://github.com/trailofbits/publications/blob/master/papers/wetseb19.pdf)中进行了描述。 +Slither 静态分析框架的功能和设计已在博客文章([1](https://blog.trailofbits.com/2018/10/19/slither-a-solidity-static-analysis-framework/)、[2](https://blog.trailofbits.com/2019/05/27/slither-the-leading-static-analyzer-for-smart-contracts/))和一篇[学术论文](https://github.com/trailofbits/publications/blob/master/papers/wetseb19.pdf)中进行了描述。 -静态分析有不同的风格。 你很可能意识到,像[clang](https://clang-analyzer.llvm.org/)和[gcc](https://lwn.net/Articles/806099/)这样的编译器依赖于上述这些研究技术,但它也是([Infer](https://fbinfer.com/)、[CodeClimate](https://codeclimate.com/)、[FindBugs](http://findbugs.sourceforge.net/)和基于形式化方法的一些工具,比如[Frama-C](https://frama-c.com/)和[Polyspace](https://www.mathworks.com/products/polyspace.html)。 +静态分析有多种形式。 您很可能意识到,像 [clang](https://clang-analyzer.llvm.org/) 和 [gcc](https://lwn.net/Articles/806099/) 这样的编译器依赖于这些研究技术,但它也是([Infer](https://fbinfer.com/)、[CodeClimate](https://codeclimate.com/)、[FindBugs](http://findbugs.sourceforge.net/))以及像 [Frama-C](https://frama-c.com/) 和 [Polyspace](https://www.mathworks.com/products/polyspace.html) 这类基于形式化方法的工具的基础。 -我们不会在这里详尽地回顾静态分析技术和研究人员。 相反,我们将专注于了解Slither是如何工作的,以便你能更有效地利用它来发现漏洞和理解代码。 +我们不会在这里详尽地回顾静态分析技术和研究人员。 相反,我们将专注于了解 Slither 是如何工作的,以便你能更有效地利用它来发现漏洞和理解代码。 - [代码表示](#code-representation) - [代码分析](#analysis) -- [代码的中间表示](#intermediate-representation) +- [中间表示](#intermediate-representation) ### 代码表示 {#code-representation} -与对单一的执行路径进行推理的动态分析相比,静态分析会对所有的执行路径进行一次性的推理。 为此,它依赖于一个不同的代码表示方式。 最常见的两个是抽象语法树(AST)和控制流图(CFG)。 +与对单一执行路径进行推理的动态分析相反,静态分析会同时对所有路径进行推理。 为此,它依赖于不同的代码表示。 最常见的两种是抽象语法树 (AST) 和控制流图 (CFG)。 -### 抽象语法树(AST) {#abstract-syntax-trees-ast} +### 抽象语法树 (AST) {#abstract-syntax-trees-ast} -每次编译器解析代码时都会用到AST技术。 它可能是进行静态分析的最基本结构。 +每当编译器解析代码时,都会使用 AST。 它可能是可以执行静态分析的最基本结构。 -简而言之,AST是一棵结构化的树,通常每片叶子包含一个变量或一个常量,而树的内部节点是操作符或控制流操作。 考虑以下代码: +简而言之,AST 是一棵结构化树,通常每个叶子节点包含一个变量或一个常量,而内部节点是操作数或控制流操作。 请看以下代码: ```solidity function safeAdd(uint a, uint b) pure internal returns(uint){ @@ -101,15 +96,15 @@ function safeAdd(uint a, uint b) pure internal returns(uint){ } ``` -相应的AST如图所示: +相应的 AST 如下所示: -![抽象语法树(AST)](./ast.png) +![AST](./ast.png) -Slither使用由solc工具导出的AST。 +Slither 使用由 solc 导出的 AST。 -虽然构建简单,但AST是一个嵌套结构。 有时,这并不是最直观的代码分析方法。 例如,为了确定表达式`a + b <= a`所使用的运算,你必须首先分析`<=`,然后分析`+`。 一个常见的方法是使用所谓的访问者模式,它以递归方式在树上进行遍历。 Slither在[`ExpressionVisitor`](https://github.com/crytic/slither/blob/master/slither/visitors/expression/expression.py)中包含一个通用的访问者程序。 +虽然构建简单,但 AST 是一个嵌套结构。 有时,这并不是最直接的分析方法。 例如,要识别表达式 `a + b <= a` 使用的操作,您必须先分析 `<=`,然后再分析 `+`。 一种常见的方法是使用所谓的访问者模式,该模式以递归方式遍历树。 Slither 在 [`ExpressionVisitor`](https://github.com/crytic/slither/blob/master/slither/visitors/expression/expression.py) 中包含一个通用访问器。 -下面的代码使用`ExpressionVisitor`来检测一个表达式是否包含加法。 +以下代码使用 `ExpressionVisitor` 来检测表达式是否包含加法: ```python from slither.visitors.expression.expression import ExpressionVisitor @@ -124,58 +119,58 @@ class HasAddition(ExpressionVisitor): if expression.type == BinaryOperationType.ADDITION: self._result = True -visitor = HasAddition(expression) # expression is the expression to be tested +visitor = HasAddition(expression) # expression 是要测试的表达式 print(f'The expression {expression} has a addition: {visitor.result()}') ``` -### 控制流图(CFG) {#control-flow-graph-cfg} +### 控制流图 (CFG) {#control-flow-graph-cfg} -第二种最常见的代码表示是控制流图(CFG)。 顾名思义,它是一种基于图的表示方法,展现了所有的代码执行路径。 每个节点包含一条或多条指令。 图中的边代表控制流操作(if/then/else,循环,等等)。 我们上一个例子的CFG是: +第二种最常见的代码表示是控制流图 (CFG)。 顾名思义,它是一种基于图的表示方法,可以揭示所有执行路径。 每个节点包含一条或多条指令。 图中的边代表控制流操作(if/then/else、循环等)。 我们上一个例子的 CFG 是: -![控制流图(CFG)](./cfg.png) +![CFG](./cfg.png) -大多数的代码分析技术都是建立在CFG的基础表示之上。 +CFG 是大多数分析所基于的表示形式。 -也存在许多其他的代码表示方法。 根据你想进行的代码分析的不同场景,每种代码表示方法都有其优点和缺点。 +还存在许多其他的代码表示形式。 根据您要执行的分析,每种表示形式都有其优缺点。 ### 分析 {#analysis} -你可以在Slither工具中进行的最简单类型的分析是语法分析。 +您可以用 Slither 执行的最简单的分析类型是语法分析。 ### 语法分析 {#syntax-analysis} -Slither可以浏览代码的不同组成部分及其表示方法,使用类似模式匹配的方法找到代码内部不一致的地方和代码缺陷。 +Slither 可以遍历代码的不同组件及其表示,使用类似模式匹配的方法来查找不一致和缺陷。 -例如,以下检测器可以寻找与语法有关的问题。 +例如,以下检测器会查找与语法相关的问题: -- [状态变量映射](https://github.com/crytic/slither/wiki/Detector-Documentation#state-variable-shadowing):遍历所有的状态变量,并检查是否有任何变量映射来自于继承的合约([state.py#L51-L62](https://github.com/crytic/slither/blob/0441338e055ab7151b30ca69258561a5a793f8ba/slither/detectors/shadowing/state.py#L51-L62))的变量。 +- [状态变量遮蔽](https://github.com/crytic/slither/wiki/Detector-Documentation#state-variable-shadowing):迭代所有状态变量,并检查是否有变量遮蔽了继承合约中的变量 ([state.py#L51-L62](https://github.com/crytic/slither/blob/0441338e055ab7151b30ca69258561a5a793f8ba/slither/detectors/shadowing/state.py#L51-L62)) -- [不正确的ERC20接口](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface):寻找不正确的ERC20函数签名([incorrect_erc20_interface.py#L34-L55](https://github.com/crytic/slither/blob/0441338e055ab7151b30ca69258561a5a793f8ba/slither/detectors/erc/incorrect_erc20_interface.py#L34-L55))。 +- [不正确的 ERC20 接口](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface):查找不正确的 ERC20 函数签名 ([incorrect_erc20_interface.py#L34-L55](https://github.com/crytic/slither/blob/0441338e055ab7151b30ca69258561a5a793f8ba/slither/detectors/erc/incorrect_erc20_interface.py#L34-L55)) ### 语义分析 {#semantic-analysis} -与语法分析相比,语义分析将更深入地分析代码的 "含义"。 这个系列包括一些宽泛的分析类型。 这些分析会产生更强大和有用的分析结果,但编写起来也更复杂。 +与语法分析相比,语义分析将更深入地分析代码的“含义”。 该系列包括一些宽泛的分析类型。 它们可以带来更强大、更有用的结果,但编写起来也更复杂。 -语义分析常常被用于最先进的代码漏洞检测。 +语义分析用于最先进的漏洞检测。 #### 数据依赖性分析 {#fixed-point-computation} -如果变量`variable_a`的值受到变量`variable_b`的影响,那么就说变量`variable_a`是数据依赖于变量`variable_b`的。 +如果存在一条路径,使得变量 `variable_a` 的值受 `variable_b` 影响,则称变量 `variable_a` 数据依赖于 `variable_b`。 -在下面的代码中,变量`variable_a`是依赖于变量`variable_b`的。 +在下面的代码中,`variable_a` 依赖于 `variable_b`: ```solidity // ... variable_a = variable_b + 1; ``` -Slither内置了[数据依赖](https://github.com/crytic/slither/wiki/data-dependency)分析功能,这要归功于它的中间表示法(在后面的部分讨论)。 +Slither 具有内置的[数据依赖性](https://github.com/crytic/slither/wiki/data-dependency)功能,这要归功于它的中间表示(将在后面的章节中讨论)。 -在[严格平等危险的检测器](https://github.com/crytic/slither/wiki/Detector-Documentation#dangerous-strict-equalities)中可以找到一个数据依赖的使用例子。 这里Slither将对危险值进行严格平等比较([incorrect_strict_equality.py#L86-L87](https://github.com/crytic/slither/blob/6d86220a53603476f9567c3358524ea4db07fb25/slither/detectors/statements/incorrect_strict_equality.py#L86-L87)),同时,将通知用户应该使用`>=`或`<=`(而不是 `==`)去阻止攻击者使合约进入代码陷阱。 另外,这个检测器会认为`balanceOf(address)` 的调用结果值是一个潜在的危险([incorrect_strict_equality.py#L63-L64](https://github.com/crytic/slither/blob/6d86220a53603476f9567c3358524ea4db07fb25/slither/detectors/statements/incorrect_strict_equality.py#L63-L64)),同时,会使用数据依赖引擎来跟踪其使用情况。 +数据依赖性用法的一个示例可以在[危险严格相等检测器](https://github.com/crytic/slither/wiki/Detector-Documentation#dangerous-strict-equalities)中找到。 这里 Slither 将查找与危险值的严格相等比较 ([incorrect_strict_equality.py#L86-L87](https://github.com/crytic/slither/blob/6d86220a53603476f9567c3358524ea4db07fb25/slither/detectors/statements/incorrect_strict_equality.py#L86-L87)),并通知用户应使用 `>=` 或 `<=` 而不是 `==`,以防止攻击者给合约设下陷阱。 此外,检测器会将对 `balanceOf(address)` 的调用的返回值视为危险值 ([incorrect_strict_equality.py#L63-L64](https://github.com/crytic/slither/blob/6d86220a53603476f9567c3358524ea4db07fb25/slither/detectors/statements/incorrect_strict_equality.py#L63-L64)),并使用数据依赖性引擎跟踪其用法。 -#### 定点计算 {#fixed-point-computation} +#### 不动点计算 {#fixed-point-computation} -如果你的分析在CFG的节点中遍历并沿着CFG的边进行,你可能会看到一些已经访问过的节点。 例如,出现如下所示的循环代码: +如果您的分析遍历 CFG 并沿边进行,您可能会看到已经访问过的节点。 例如,如果循环如下所示: ```solidity for(uint i; i < range; ++){ @@ -183,21 +178,21 @@ for(uint i; i < range; ++){ } ``` -你的分析将需要知道何时停止。 这里有两种主要策略:1)在每个节点上迭代有限次数,2)通过计算所谓的_定点_。 一个定点基本上意味着分析此节点不会提供任何有意义的信息。 +您的分析将需要知道何时停止。 这里有两种主要策略:(1) 在每个节点上迭代有限次数,(2) 计算所谓的_不动点_。 不动点基本上意味着分析此节点不会提供任何有意义的信息。 -在代码可重入检测器中可以找到使用的定点的示例:Slither探索这些节点,寻找外部调用、写入和读取存储。 一旦到达某个定点 ([reentrancy.py#L125-L131](https://github.com/crytic/slither/blob/master/slither/detectors/reentrancy/reentrancy.py#L125-L131)),分析器就会停止代码遍历,并通过不同的重入模式来分析结果,了解是否存在代码重入现象。([reentrancy_benign.py](https://github.com/crytic/slither/blob/b275bcc824b1b932310cf03b6bfb1a1fef0ebae1/slither/detectors/reentrancy/reentrancy_benign.py)、[reentrancy_read_before_write.py](https://github.com/crytic/slither/blob/b275bcc824b1b932310cf03b6bfb1a1fef0ebae1/slither/detectors/reentrancy/reentrancy_read_before_write.py)、[reentrancy_eth.py](https://github.com/crytic/slither/blob/b275bcc824b1b932310cf03b6bfb1a1fef0ebae1/slither/detectors/reentrancy/reentrancy_eth.py))。 +在可重入检测器中可以找到使用不动点的示例:Slither 探索节点,并查找外部调用、存储写入和读取。 一旦达到不动点 ([reentrancy.py#L125-L131](https://github.com/crytic/slither/blob/master/slither/detectors/reentrancy/reentrancy.py#L125-L131)),它就会停止探索,并通过不同的可重入模式([reentrancy_benign.py](https://github.com/crytic/slither/blob/b275bcc824b1b932310cf03b6bfb1a1fef0ebae1/slither/detectors/reentrancy/reentrancy_benign.py)、[reentrancy_read_before_write.py](https://github.com/crytic/slither/blob/b275bcc824b1b932310cf03b6bfb1a1fef0ebae1/slither/detectors/reentrancy/reentrancy_read_before_write.py)、[reentrancy_eth.py](https://github.com/crytic/slither/blob/b275bcc824b1b932310cf03b6bfb1a1fef0ebae1/slither/detectors/reentrancy/reentrancy_eth.py))分析结果,以查看是否存在可重入。 -使用高效的定点计算方法编写分析,需要很好地理解分析是如何传播其信息的。 +使用高效的不动点计算编写分析需要很好地理解分析如何传播其信息。 -### 代码的中间表示 {#intermediate-representation} +### 中间表示 {#intermediate-representation} -中间表示(IR)是一种比原始语言更适合进行静态分析的语言。 Slither将Solidity转换为它自己的IR:[SlithIR](https://github.com/crytic/slither/wiki/SlithIR)。 +中间表示 (IR) 是一种比原始语言更适合静态分析的语言。 Slither 将 Solidity 转换为其自己的 IR:[SlithIR](https://github.com/crytic/slither/wiki/SlithIR)。 -如果你只是想编写基本的代码检查,那么理解SlithIR不是必须的。 但是,如果你打算编写更高级的语义分析,对SlithIR的理解将派上用场。 [SlithIR](https://github.com/crytic/slither/wiki/Printer-documentation#slithir)和[SSA](https://github.com/crytic/slither/wiki/Printer-documentation#slithir-ssa)打印器工具将帮助你理解代码是如何被翻译的。 +如果您只想编写基本的检查,则无需了解 SlithIR。 但是,如果您计划编写高级语义分析,它会派上用场。 [SlithIR](https://github.com/crytic/slither/wiki/Printer-documentation#slithir) 和 [SSA](https://github.com/crytic/slither/wiki/Printer-documentation#slithir-ssa) 打印器将帮助您了解代码是如何被翻译的。 -## API基础知识 {#api-basics} +## API 基础 {#api-basics} -Slither有一套API,可让你探索合约的基本属性及其功能。 +Slither 有一个 API,可让您探索合约及其函数的基本属性。 加载代码库: @@ -207,32 +202,32 @@ slither = Slither('/path/to/project') ``` -### 探索合约和相关的函数 {#exploring-contracts-and-functions} +### 探索合约和函数 {#exploring-contracts-and-functions} -一个`Slither`对象具有: +一个 `Slither` 对象具有: -- `contracts (list(Contract)`:合约列表 -- `contracts_derived (list(Contract)`:未被其他合约继承的合约列表(合约的子集) -- `get_contract_from_name (str)`:从合约名称返回一个合约实例 +- `contracts (list(Contract)`: 合约列表 +- `contracts_derived (list(Contract)`: 不被其他合约继承的合约列表(合约的子集) +- `get_contract_from_name (str)`: 根据名称返回合约 -一个`Contract`对象具有: +一个 `Contract` 对象具有: -- `name (str)`:合约名称 -- `functions (list(Function))`:函数列表 -- `modifiers (list(Modifier))`:函数列表 -- `all_functions_called (list(Function/Modifier))`:合约可访问的所有内部函数列表 -- `inheritance (list(Contract))`:继承的合约的列表 -- `get_function_from_signature (str)`:通过函数签名返回一个函数 -- `get_modifier_from_signature (str)`:从函数签名返回一个修改器 -- `get_state_variable_from_name (str)`:从其名称返回一个状态变量 +- `name (str)`: 合约名称 +- `functions (list(Function))`: 函数列表 +- `modifiers (list(Modifier))`: 修饰符列表 +- `all_functions_called (list(Function/Modifier))`: 合约可达的所有内部函数列表 +- `inheritance (list(Contract))`: 继承的合约列表 +- `get_function_from_signature (str)`: 根据签名返回一个函数 +- `get_modifier_from_signature (str)`: 根据签名返回一个修饰符 +- `get_state_variable_from_name (str)`: 根据名称返回一个状态变量 -一个`Function`或`Modifier`对象具有: +一个 `Function` 或 `Modifier` 对象具有: -- `name (str)`:函数的名称 -- `contract (contract)`:声明该函数的合约 -- `nodes (list(Node))`:组成该函数/修改器的CFG的节点列表 -- `entry_point (Node)`:CFG的入口点 -- `variables_read (list(Variable))`:所读取变量的列表 -- `variables_written (list(Variable))`:所写入变量的列表 -- `state_variables_read (list(StateVariable))`:所读取状态变量的列表(所读取变量的子集) -- `state_variables_written (list(StateVariable))`:所写入状态变量的列表(所写入变量的子集) +- `name (str)`: 函数名称 +- `contract (contract)`: 声明该函数的合约 +- `nodes (list(Node))`: 组成函数/修饰符的 CFG 的节点列表 +- `entry_point (Node)`: CFG 的入口点 +- `variables_read (list(Variable))`: 读取的变量列表 +- `variables_written (list(Variable))`: 写入的变量列表 +- `state_variables_read (list(StateVariable))`: 读取的状态变量列表(`variables_read` 的子集) +- `state_variables_written (list(StateVariable))`: 写入的状态变量列表(`variables_written` 的子集) diff --git a/public/content/translations/zh/developers/tutorials/how-to-use-tellor-as-your-oracle/index.md b/public/content/translations/zh/developers/tutorials/how-to-use-tellor-as-your-oracle/index.md index b96fd8531e6..4dd251fa9ea 100644 --- a/public/content/translations/zh/developers/tutorials/how-to-use-tellor-as-your-oracle/index.md +++ b/public/content/translations/zh/developers/tutorials/how-to-use-tellor-as-your-oracle/index.md @@ -1,12 +1,9 @@ --- -title: 如何将 Tellor 设置为你的预言机 -description: 将 Tellor 预言机集成到协议中的指南 +title: "如何将 Tellor 设置为你的预言机" +description: "将 Tellor 预言机集成到协议中的指南" author: "Tellor" lang: zh -tags: - - "solidity" - - "智能合约" - - "预言机" +tags: [ "Solidity", "智能合同", "预言机" ] skill: beginner published: 2021-06-29 source: Tellor Docs @@ -15,7 +12,7 @@ sourceUrl: https://docs.tellor.io/tellor/ 小测验:你的协议即将完成,但它需要一个预言机来访问链下数据......你该怎么做? -## (软)前提条件 {#soft-prerequisites} +## (软)先决条件 {#soft-prerequisites} 这篇文章旨在解释如何让访问预言机数据馈送变得简单易行。 这就是说,我们假定你具备一定的编码技能水平,下文侧重于讲述预言机方面。 @@ -29,7 +26,7 @@ Tellor 是一种可供直接实现的开源预言机。 本初学者教程旨在 ## 概述 {#overview} -Tellor 是一种预言机系统,参与者可以在该系统中请求链下数据点(例如 BTC/USD)的值,提供者相互竞争将该值添加到链上数据库中,使得所有以太坊智能合约都可以访问该值。 该数据库的输入由质押提供者网络提供保护。 Tellor 利用加密经济激励机制,奖励提供者诚实的数据提交行为,并通过发行 Tellor 的代币、Tribute (TRB) 和争议机制来惩罚不良行为者。 +Tellor 是一种预言机系统,参与者可以在该系统中请求链下数据点(例如 BTC/USD)的值,提供者相互竞争将该值添加到链上数据库中,使得所有以太坊智能合约都可以访问该值。 该数据库的输入由质押提供者网络提供保护。 Tellor 利用加密经济激励机制,奖励提供者诚实的数据提交行为,并通过发行 Tellor 的代币 Tributes (TRB) 和争议机制来惩罚不良行为者。 在本教程中,我们将介绍: @@ -37,19 +34,19 @@ Tellor 是一种预言机系统,参与者可以在该系统中请求链下数 - 讲解一个简单示例。 - 列出目前可以测试 Tellor 的网络的测试网地址。 -## 使用 Tellor {#usingtellor} +## UsingTellor {#usingtellor} -首先安装一些基本工具,以便将 Tellor 作为预言机。 使用[此软件包](https://github.com/tellor-io/usingtellor)安装 Tellor 用户合约: +首先安装一些基本工具,以便将 Tellor 作为预言机。 使用[此软件包](https://github.com/tellor-io/usingtellor)来安装 Tellor 用户合约: `npm install usingtellor` -安装完成后,将允许你的合约继承“UsingTellor”合约的函数。 +安装完成后,将允许你的合约继承 'UsingTellor' 合约的函数。 很好! 既然你已经准备好工具了,我们来完成一个简单的练习来获取比特币价格: ### BTC/USD 示例 {#btcusd-example} -继承 UsingTellor 合约,将 Tellor 的地址作为构造函数的参数: +继承 UsingTellor 合约,并将 Tellor 地址作为构造函数参数传入: 下面是一个示例: @@ -59,7 +56,7 @@ import "usingtellor/contracts/UsingTellor.sol"; contract PriceContract is UsingTellor { uint256 public btcPrice; - //This Contract now has access to all functions in UsingTellor + //此合约现在可以访问 UsingTellor 中的所有函数 constructor(address payable _tellorAddress) UsingTellor(_tellorAddress) public {} @@ -77,8 +74,8 @@ function setBtcPrice() public { } ``` -完整的合约地址列表参见 [这里](https://docs.tellor.io/tellor/the-basics/contracts-reference)。 +如需完整的合约地址列表,请参阅[此处](https://docs.tellor.io/tellor/the-basics/contracts-reference)。 -为了便于使用,UsingTellor 合约库带有一个[Tellor Playground](https://github.com/tellor-io/TellorPlayground) 合约的版本以便于集成。 请参阅[此处](https://github.com/tellor-io/sampleUsingTellor#tellor-playground)获取实用函数的列表。 +为方便使用,UsingTellor 代码库附带了 [Tellor Playground](https://github.com/tellor-io/TellorPlayground) 合约的一个版本,以便于集成。 有关实用函数列表,请参阅[此处](https://github.com/tellor-io/sampleUsingTellor#tellor-playground)。 -要更加可靠地实现 Tellor 预言机,请点击[此处](https://github.com/tellor-io/usingtellor/blob/master/README.md)查看可用函数的完整列表。 +要更稳健地实现 Tellor 预言机,请查看[此处](https://github.com/tellor-io/usingtellor/blob/master/README.md)的可用函数完整列表。 diff --git a/public/content/translations/zh/developers/tutorials/how-to-view-nft-in-metamask/index.md b/public/content/translations/zh/developers/tutorials/how-to-view-nft-in-metamask/index.md index 60157ad2f8e..560ab42d76d 100644 --- a/public/content/translations/zh/developers/tutorials/how-to-view-nft-in-metamask/index.md +++ b/public/content/translations/zh/developers/tutorials/how-to-view-nft-in-metamask/index.md @@ -1,36 +1,33 @@ --- -title: 如何在钱包中查看你的非同质化代币(非同质化代币系列教程第 3/3 部分) -description: 本教程介绍了如何在 MetaMask 钱包上查看所持有的非同质化代币! +title: "如何在钱包中查看你的 NFT(NFT 教程系列第 3/3 部分)" +description: "本教程将介绍如何在 MetaMask 上查看已有的 NFT!" author: "苏米-穆德吉尔" -tags: - - "ERC-721" - - "Alchemy" - - "Solidity" +tags: [ "ERC-721", "Alchemy", "Solidity" ] skill: beginner lang: zh published: 2021-04-22 --- -本教程是非同质化代币教程系列的第 3/3 部分,在这里将教你查看我们新铸造的非同质化代币。 然而,你也可以把它当做在 MetaMask 上使用任何 ERC-721 代币的通用教程,无论是主网还是测试网。 如果你想学习如何在 Ethereum 上发行自己的非同质化代币,你可以查看[第 1 部分:如何编写和部署非同质化代币智能合约](/developers/tutorials/how-to-write-and-deploy-an-nft)! +本教程是 NFT 教程系列的第 3/3 部分,我们将在这里查看我们新铸造的 NFT。 然而,你也可以把它当做在 MetaMask 上使用任何 ERC-721 代币的通用教程,无论是主网还是测试网。 如果你想学习如何在以太坊上铸造自己的 NFT,请查阅[第 1 部分:如何编写和部署 NFT 智能合约](/developers/tutorials/how-to-write-and-deploy-an-nft)! -恭喜! 你已经来到我们非同质化代币系列教程中最短和最简单的部分——如何在虚拟钱包中查看你刚刚铸造的非同质化代币。 本示例中,我们将继续使用前两部分用过的 MetaMask。 +恭喜! 你已经来到了我们 NFT 教程系列中最短、最简单的部分——如何在虚拟钱包中查看你刚刚铸造的 NFT。 本示例中,我们将继续使用前两部分用过的 MetaMask。 -作为一个前提条件,你应该已经在移动设备上安装了 MetaMask, 并且它应该包含你铸造非同质化代币的帐户——你可以在 [iOS](https://apps.apple.com/us/app/metamask-blockchain-wallet/id1438144202) 或 [Android](https://play.google.com/store/apps/details?id=io.metamask&hl=en_US&gl=US) 免费获得该应用程序。 +前提条件是,你应该已在移动设备上安装 MetaMask,并且其中应包含你铸造 NFT 时所用的帐户 — 你可以在 [iOS](https://apps.apple.com/us/app/metamask-blockchain-wallet/id1438144202) 或 [Android](https://play.google.com/store/apps/details?id=io.metamask&hl=en_US&gl=US) 上免费获取该应用程序。 ## 第 1 步:将你的网络设置为 Sepolia {#set-network-to-sepolia} -在应用程序顶端,按“钱包”按钮,然后会提示你选择网络。 由于我们的非同质化代币是在 Sepolia 网络上铸造的,因此需要选择 Sepolia 作为你的网络。 +在应用程序顶部,按“钱包”按钮,之后系统会提示你选择一个网络。 由于我们的 NFT 是在 Sepolia 网络上铸造的,你需要选择 Sepolia 作为你的网络。 ![如何在 MetaMask Mobile 上将 Sepolia 设置为你的网络](./goerliMetamask.gif) -## 第 2 步:将你的收藏添加到 MetaMask {#add-nft-to-metamask} +## 第 2 步:将你的收藏品添加到 MetaMask {#add-nft-to-metamask} -进入 Sepolia 网络后,选择右侧的“Collectibles”选项卡,并添加非同质化代币智能合约的地址和你的非同质化代币的 ERC-721 代币 ID(应该可以在教程第二部分中部署的非同质化代币的交易哈希值在 Etherscan 上找到)。 +进入 Sepolia 网络后,在右侧选择“收藏品”选项卡,并添加 NFT 智能合约地址和你的 NFT 的 ERC-721 代币 ID——你应该能根据我们教程第二部分部署 NFT 的交易哈希在 Etherscan 上找到。 -![如何查找你的交易哈希值和 ERC-721 代币 ID](./findNFTEtherscan.png) +![如何找到你的交易哈希和 ERC-721 代币 ID](./findNFTEtherscan.png) -你可能需要刷新几次才能查看你的非同质化代币——但一定会出现! +你可能需要刷新几次才能看到你的 NFT — 但它一定会出现的 ! -![如何将你的非同质化代币上传到 MetaMask](./findNFTMetamask.gif) +![如何将你的 NFT 上传到 MetaMask](./findNFTMetamask.gif) -恭喜! 你已成功铸造了一个非同质化代币,现在可以查看了! 我们迫不及待地想看看你将如何席卷非同质化代币世界! +恭喜! 你已成功铸造一个 NFT,现在可以查看了! 我们迫不及待地想看看你将如何席卷 NFT 世界! diff --git a/public/content/translations/zh/developers/tutorials/how-to-write-and-deploy-an-nft/index.md b/public/content/translations/zh/developers/tutorials/how-to-write-and-deploy-an-nft/index.md index 690e6d7aa64..76caaffdbba 100644 --- a/public/content/translations/zh/developers/tutorials/how-to-write-and-deploy-an-nft/index.md +++ b/public/content/translations/zh/developers/tutorials/how-to-write-and-deploy-an-nft/index.md @@ -1,12 +1,8 @@ --- -title: 如何撰写和部署非同质化代币(非同质化代币教程系列 1/3) -description: 本教程是关于非同质化代币的系列教程的第一部分,将带你逐步了解如何使用以太坊和星际文件系统 (IPFS) 编写和部署非同质化代币(ERC-721 代币)智能合约。 -author: "Sumi Mudgil" -tags: - - "ERC-721" - - "Alchemy" - - "Solidity" - - "智能合约" +title: "如何编写和部署 NFT(NFT 教程系列 1/3)" +description: "本教程是关于非同质化代币的系列教程的第一部分,将带你逐步了解如何使用以太坊和星际文件系统 (IPFS) 编写和部署非同质化代币(ERC-721 代币)智能合约。" +author: "苏米-穆德吉尔" +tags: [ "ERC-721", "Alchemy", "Solidity", "智能合同" ] skill: beginner lang: zh published: 2021-04-22 @@ -14,23 +10,23 @@ published: 2021-04-22 随着非同质化代币将区块链带入公众视野,现在正是通过在以太坊区链上发布自己的非同质化代币合约(ERC-721 代币)来了解这一宣传的绝佳机会! -Alchemy 非常自豪能够推动非同质化代币领域的一些巨头,包括 Makersplace(最近在克利斯蒂拍卖行创造了 6900 万美元的数字艺术品销售记录)、Dapper Labs(NBA Top Shot & Crypto Kitties 的创作者)、OpenSea(世界上最大的非同质化代币市场)、Zora、Super Rare、NFTfi、Foundation、Enjin、Origin Protocol、Immutable 等。 +Alchemy 非常自豪能为 NFT 领域的一些知名品牌提供支持,包括 Makersplace(最近在佳士得拍卖行以 6900 万美元的价格创下数字艺术品销售记录)、Dapper Labs(NBA Top Shot 和 Crypto Kitties 的创建者)、OpenSea(全球最大的 NFT 市场)、Zora、Super Rare、NFTfi、Foundation、Enjin、Origin Protocol、Immutable 等。 -在本教程中,我们将使用 [MetaMask](https://metamask.io/)、[Solidity](https://docs.soliditylang.org/en/v0.8.0/)、[安全帽](https://hardhat.org/)、[Pinata](https://pinata.cloud/) 和 [Alchemy](https://alchemy.com/signup/eth) 演示如何在 Sepolia 测试网络上创建和部署 ERC-721 智能合约(如果还不明白其中的含义,请不要着急,我们会为你解释!)。 +在本教程中,我们将使用 [MetaMask](https://metamask.io/)、[Solidity](https://docs.soliditylang.org/en/v0.8.0/)、[Hardhat](https://hardhat.org/)、[Pinata](https://pinata.cloud/) 和 [Alchemy](https://alchemy.com/signup/eth) 演示如何在 Sepolia 测试网络上创建和部署 ERC-721 智能合约(如果还不明白其中的含义,请不要着急,我们会为你解释!)。 在本教程的第二部分,我们将了解如何使用我们的智能合约来铸造非同质化代币;在第三部分,我们将说明如何在 MetaMask 上查看你的非同质化代币。 -当然,如果你有任何问题,请随时通过 [Alchemy Discord](https://discord.gg/gWuC7zB) 联系我们或阅读 [Alchemy 的非同质化代币应用程序接口相关文档](https://docs.alchemy.com/alchemy/enhanced-apis/nft-api)! +当然,如果你在任何时候有任何问题,请随时在 [Alchemy Discord](https://discord.gg/gWuC7zB) 中联系我们或访问 [Alchemy 的 NFT 应用程序接口文档](https://docs.alchemy.com/alchemy/enhanced-apis/nft-api)! ## 步骤 1:连接到以太坊网络 {#connect-to-ethereum} -有很多方法可以向以太坊区块链发出请求,但为了方便起见,我们将使用 [Alchemy](https://alchemy.com/signup/eth) 上的免费帐户。Alchemy 是一个区块链开发平台,能够提供应用程序接口,让我们无需运行自己的节点,即可与以太坊区块链进行通信。 +有很多方法可以向以太坊区块链发出请求,但为了方便起见,我们将使用 [Alchemy](https://alchemy.com/signup/eth) 上的免费帐户。Alchemy 是一个区块链开发平台和应用程序接口,让我们无需运行自己的节点,即可与以太坊链进行通信。 -在本教程中,我们将利用 Alchemy 平台的开发者工具进行监测和分析,以便了解智能合约部署的底层逻辑。 如果你还没有 Alchemy 帐户,你可以在[此处](https://alchemy.com/signup/eth)免费注册。 +在本教程中,我们将利用 Alchemy 平台的开发者工具进行监测和分析,以便了解智能合约部署的底层逻辑。 如果你还没有 Alchemy 帐户,可以在[此处](https://alchemy.com/signup/eth)免费注册。 -## 步骤 2:创建应用程序(和应用程序接口密钥) {#make-api-key} +## 步骤 2:创建你的应用程序(和应用程序接口密钥) {#make-api-key} -创建了 Alchemy 帐户后,你可以通过创建应用程序来生成应用程序接口密钥。 这将使我们能够向 Sepolia 测试网络发出请求。 如果你想了解更多关于测试网络的信息,请查看[本指南](https://docs.alchemyapi.io/guides/choosing-a-network)。 +创建 Alchemy 帐户后,你可以通过创建应用程序来生成应用程序接口密钥。 这将使我们能够向 Sepolia 测试网络发出请求。 如果你想详细了解测试网,请查阅[本指南](https://docs.alchemyapi.io/guides/choosing-a-network)。 1. 将鼠标悬停在Alchemy网页导航栏中的「App」,单击「Create App」并前往此页面。 @@ -40,27 +36,29 @@ Alchemy 非常自豪能够推动非同质化代币领域的一些巨头,包括 ![配置并发布你的应用程序](./alchemy-explorer-sepolia.png) -3. 点击"创建应用程序",完成! 你的应用程序应该会出现在下面的表格中。 +3. 点击“Create app”,完成! 你的应用程序应该就会出现在下面的表格中。 -## 步骤 3:创建一个以太坊帐户(地址) {#create-eth-address} +## 步骤 3:创建以太坊帐户(地址) {#create-eth-address} -我们需要一个以太坊帐户来发送和接收交易。 在本教程中,我们将使用 MetaMask——浏览器中的虚拟钱包,用来管理你的以太坊帐户地址。 如果你想了解更多关于以太坊交易的运作方式,请查看以太坊基金会的[这个页面](/developers/docs/transactions/)。 +我们需要一个以太坊帐户来发送和接收交易。 在本教程中,我们将使用 MetaMask,它是浏览器中的虚拟钱包,用来管理你的以太坊帐户地址。 如果你想进一步了解以太坊交易的运作方式,请查看以太坊基金会的[这个页面](/developers/docs/transactions/)。 -你可以[在这里](https://metamask.io/download)免费下载并创建一个 MetaMask 帐户。 在你创建帐户时,或者如果你已有一个帐户,请确保切换到右上角的“Sepolia Test Network”(这样我们就不会使用实际货币进行交易)。 +你可以[在此处](https://metamask.io/download)免费下载和创建 MetaMask 帐户。 在你创建帐户时,或者如果你已有一个帐户,请确保切换到右上角的“Sepolia Test Network”(这样我们就不会使用实际货币进行交易)。 ![将 Sepolia 设置为你的网络](./metamask-goerli.png) -## 步骤 4:从水龙头添加以太币 {#step-4-add-ether-from-a-faucet} +## 步骤 4:从水龙头获取以太币 {#step-4-add-ether-from-a-faucet} -为了将我们的智能合约部署到测试网络,我们需要一些虚拟以太币。 想要获取以太币,可以访问由 Alchemy 托管的 [Sepolia Faucet](https://sepoliafaucet.com/),登录并输入你的帐户地址,点击“Send Me ETH”。 你应该会很快在你的 MetaMask 帐户中看到以太币! +为了将我们的智能合约部署到测试网络,我们需要一些虚拟以太币。 要获取 ETH,你可以访问由 Alchemy 托管的 [Sepolia 水龙头](https://sepoliafaucet.com/),登录并输入你的帐户地址,然后点击“Send Me ETH”。 你应该会很快在你的 MetaMask 帐户中看到以太币! -## 步骤 5:查看帐户余额 {#check-balance} +## 步骤 5:检查余额 {#check-balance} -为了核实我们的余额,可以使用 [Alchemy 的创作者工具](https://composer.alchemyapi.io?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D)发出 [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) 请求。 这将返回我们钱包中的以太币金额。 输入你的 Metamask 帐户地址并单击“发送请求”后,你应该会看到这样的响应: +为了再次确认我们的余额,让我们使用 [Alchemy 的编辑器工具](https://composer.alchemyapi.io?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D)发出 [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) 请求。 这将返回我们钱包中的以太币数量。 输入你的 MetaMask 帐户地址并点击“Send Request”后,你应该会看到这样的响应: + ``` `{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}` + ``` -> **注:**此结果以 wei 为单位,而非 ETH。 Wei 是以太币的最小计量单位。 wei 与 ETH 之间的转换为 1 eth = 1018 wei。 因此,如果我们将 0xde0b6b3a7640000 转换为十进制,我们得到 1\*1018 wei,即 1 ETH。 +> **注意**:这个结果是以 wei 为单位,而不是 ETH。 Wei 是以太币的最小计量单位。 wei 与 ETH 之间的转换为 1 eth = 1018 wei。 因此,如果我们将 0xde0b6b3a7640000 转换为十进制,我们得到 1\*1018 wei,即 1 ETH。 哦! 这里显示了我们所有的虚拟货币。 @@ -68,14 +66,19 @@ Alchemy 非常自豪能够推动非同质化代币领域的一些巨头,包括 首先,需要为我们的项目创建一个文件夹。 导航到你的命令行,然后输入: + ``` mkdir my-nft cd my-nft + ``` -现在我们进入了项目文件夹,我们将使用 npm init 来初始化项目。 如果还没有安装 npm,请遵循[此处的说明](https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm)(我们还需要 [Node.js](https://nodejs.org/en/download/),所以请下载此工具!)。 +现在我们进入了项目文件夹,我们将使用 npm init 来初始化项目。 如果你尚未安装 npm,请遵循[这些说明](https://docs.alchemyapi.io/alchemy/guides/alchemy-for-macs#1-install-nodejs-and-npm)(我们还需要 [Node.js](https://nodejs.org/en/download/),所以也请下载它!)。 + ``` npm init + ``` 其实如何回答安装问题并不重要,以下提供一个回答的样例供参考: + ```json package name: (my-nft) version: (1.0.0) @@ -100,26 +103,32 @@ Alchemy 非常自豪能够推动非同质化代币领域的一些巨头,包括 "license": "ISC" } ``` + 批准 package.json,我们就可以开始了! -## 步骤 7:安装[安全帽 (Hardhat)](https://hardhat.org/getting-started/#overview) {#install-hardhat} +## 步骤 7:安装[Hardhat](https://hardhat.org/getting-started/#overview) {#install-hardhat} -安全帽是一个用于编译、部署、测试和调试以太坊软件的开发环境。 它帮助开发者在本地构建智能合约和去中心化应用程序并部署到实时链上。 +Hardhat是一个用于编译、部署、测试和调试以太坊软件的开发环境。 它帮助开发者在本地构建智能合约和去中心化应用程序并部署到实时链上。 在我们的 my-nft 项目内运行: + ``` npm install --save-dev hardhat + ``` -查看此页面,了解更多有关[安装说明](https://hardhat.org/getting-started/#overview)的详细信息。 +请查看此页面,详细了解[安装说明](https://hardhat.org/getting-started/#overview)。 -## 步骤 8:创建安全帽项目 {#create-hardhat-project} +## 步骤 8:创建Hardhat项目 {#create-hardhat-project} 在我们的项目文件夹中运行: + ``` npx hardhat + ``` 然后应该能看到一条欢迎消息和选项,用于选择你想要做的事情。 选择“创建一个空的 hardhat.config.js”: + ``` 888 888 888 888 888 888 888 888 888 888 888 888 888 888 888 @@ -129,10 +138,11 @@ Alchemy 非常自豪能够推动非同质化代币领域的一些巨头,包括 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. 888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 👷 Welcome to Hardhat v2.0.11 👷‍ - ? 你想做什么? … + ? What do you want to do? … Create a sample project ❯ Create an empty hardhat.config.js Quit + ``` 这将生成一个 hardhat.config.js 文件,我们将在其中指定项目的所有设置(步骤 13)。 @@ -140,25 +150,27 @@ Alchemy 非常自豪能够推动非同质化代币领域的一些巨头,包括 为了使我们的项目有条理,我们将创建两个新的文件夹。 在你的命令行中导航到项目的根目录,然后输入: + ``` mkdir contracts mkdir scripts + ``` - contracts/ 是我们保存非同质化代币智能合约代码的位置。 - scripts/ 是我们存放脚本的位置,用于部署我们的智能合约和与之交互。 -## 步骤 10:编写合约 {#write-contract} +## 步骤 10:编写我们的合约 {#write-contract} -现在我们的环境已经配置完成,接下来将是更令人兴奋的内容:_编写我们的智能合约代码!_ +现在我们的环境已经设置好,接下来是更令人兴奋的事情:_编写我们的智能合约代码!_ -在你喜欢的编辑器中打开 my-nft 项目(我们喜欢用 [VSCode](https://code.visualstudio.com/))。 智能合约用一种名为 Solidity 的语言编写,我们将用它来编写我们的 MyNFT.sol 智能合约。 +在你喜欢的编辑器(我们推荐 [VSCode](https://code.visualstudio.com/))中打开 my-nft 项目。 智能合约用一种名为 Solidity 的语言编写,我们将用它来编写我们的 MyNFT.sol 智能合约。 1. 导航到 `contracts` 文件夹并创建一个名为 MyNFT.sol 的新文件 -2. 下面是我们的非同质化代币智能合约代码,基于 [OpenZeppelin](https://docs.openzeppelin.com/contracts/3.x/erc721) 库的 ERC-721 实现。 复制并粘贴以下内容到你的 MyNFT.sol 文件。 +2. 下面是我们的 NFT 智能合约代码,该代码基于 [OpenZeppelin](https://docs.openzeppelin.com/contracts/3.x/erc721) 程序库的 ERC-721 实现。 复制并粘贴以下内容到你的 MyNFT.sol 文件。 ```solidity - //Contract based on [https://docs.openzeppelin.com/contracts/3.x/erc721](https://docs.openzeppelin.com/contracts/3.x/erc721) + //合约基于 [https://docs.openzeppelin.com/contracts/3.x/erc721](https://docs.openzeppelin.com/contracts/3.x/erc721) // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; @@ -188,54 +200,58 @@ Alchemy 非常自豪能够推动非同质化代币领域的一些巨头,包括 } ``` -3. 因为我们要从 OpenZeppelin 合约库继承类,请在你的命令行中运行 `npm install @openzeppelin/contracts`,将该库安装到我们的文件夹中。 +3. 因为我们正在从 OpenZeppelin 合约程序库继承类,所以在你的命令行中运行 `npm install @openzeppelin/contracts^4.0.0`,将该程序库安装到我们的文件夹中。 -那么,这段代码究竟_做_了什么? 让我们把它逐行分解。 +那么,这段代码究竟是_做什么_的? 让我们把它逐行分解。 在我们的智能合约的顶部,我们导入了三个 [OpenZeppelin](https://openzeppelin.com/) 智能合约类: -- @openzeppelin/contracts/token/ERC721/ERC721.sol 包含 ERC-721 标准的实现,我们的非同质化代币智能合约将继承此标准。 (要成为有效的非同质化代币,你的智能合约必须实现 ERC-721 标准的所有方法。) 要更加详细地了解继承的 ERC-721 功能,请在[这里](https://eips.ethereum.org/EIPS/eip-721)查看接口定义。 +- @openzeppelin/contracts/token/ERC721/ERC721.sol 包含 ERC-721 标准的实现,我们的非同质化代币智能合约将继承此标准。 (要成为有效的非同质化代币,你的智能合约必须实现 ERC-721 标准的所有方法。) 要详细了解继承的 ERC-721 函数,请查阅[此处](https://eips.ethereum.org/EIPS/eip-721)的接口定义。 - @openzeppelin/contracts/utils/Counters.sol 提供了只能以 1 为增量或减量的计数器。 我们的智能合约使用一个计数器来跟踪非同质化代币总铸币量,并在我们的新非同质化代币上设置唯一 ID。 (每个使用智能合约铸造的非同质化代币必须分配一个唯一 ID——在这里,我们的唯一 ID 仅由存在的非同质化代币总量决定。 例如,我们用智能合约铸造的第一个非同质化代币的 ID 是“1”,第二个非同质化代币的 ID 是“2”,以此类推) -- @openzeppelin/contracts/access/Ownable.sol在我们的智能合约上设置了[访问控制](https://docs.openzeppelin.com/contracts/3.x/access-control),因此只有智能合约的所有者(你)可以铸造非同质化代币。 (注意:包含访问控制完全是一种偏好。 如果你希望任何人都能使用你的智能合约铸造非同质化代币,请删除第 10 行的 Ownable 和第 17 行的 onlyOwner)。 +- @openzeppelin/contracts/access/Ownable.sol 在我们的智能合约上设置了[访问控制](https://docs.openzeppelin.com/contracts/3.x/access-control),因此只有智能合约的所有者(你)可以铸币 NFT。 (注意:包含访问控制完全是一种偏好。 如果你希望任何人都能使用你的智能合约铸造非同质化代币,请删除第 10 行的 Ownable 和第 17 行的 onlyOwner)。 -导入语句后面,是我们自定义的非同质化代币智能合约。合约非常短,只包含一个计数器、一个构造函数和独立函数! 这要归功于我们继承的 OpenZepelin 合约,它们实现了我们创建非同质化代币所需的大多数方法。例如 `owerOf` 函数,其作用是返回非同质化代币所有者,以及 `transferFrom` 函数,其作用是将非同质化代币的所有权从一个帐户转移到另一个帐户。 +导入语句后面,是我们自定义的非同质化代币智能合约。合约非常短,只包含一个计数器、一个构造函数和独立函数! 这要归功于我们继承的 OpenZeppelin 合约,其中实现了我们创建 NFT 所需的大多数方法,例如返回 NFT 所有者的 `ownerOf`,以及将 NFT 的所有权从一个帐户转移到另一个帐户的 `transferFrom`。 在我们的 ERC-721 构造函数中,你会注意到我们传递 2 个字符串,“MyNFT”和“NFT”。 第一个变量是智能合约的名称,第二个变量是其符号。 你可以随意命名这些变量! -最后,我们得到了函数 `mintNFT(address recipient, string memory tokenURI)`,它让我们能够铸造非同质化代币! 你将注意到,这个函数包含两个变量: +最后,我们的函数 `mintNFT(address recipient, string memory tokenURI)` 允许我们铸币 NFT! 你将注意到,这个函数包含两个变量: -- `address recipient` 指定了接收新铸造非同质化代币的地址 +- `address recipient` 指定将接收你新铸币的 NFT 的地址 -- `string memory tokenURI` 是一个可以解析为 JSON 文档的字符串,该文档用于描述非同质化代币的元数据。 非同质化代币的元数据是它的核心所在,使它拥有可配置的属性,例如名称、描述、图像和其他属性。 在本教程第二部分,我们将描述如何配置元数据。 +- `string memory tokenURI` 是一个字符串,它应该解析为一个描述此 NFT 元数据的 JSON 文档。 非同质化代币的元数据是它的核心所在,使它拥有可配置的属性,例如名称、描述、图像和其他属性。 在本教程第二部分,我们将描述如何配置元数据。 -`mintNFT` 调用了继承的 ERC-721 库中的一些方法,最终返回一个数字,代表新铸造非同质化代币的 ID。 +`mintNFT` 从继承的 ERC-721 程序库中调用一些方法,并最终返回一个数字,代表新铸币的 NFT 的 ID。 -## 步骤 11:将 Metamask 和 Alchemy 连接至你的项目 {#connect-metamask-and-alchemy} +## 步骤 11:将 MetaMask 和 Alchemy 连接到你的项目 {#connect-metamask-and-alchemy} 我们已经创建了 Metamask 钱包、Alchemy 帐户,并且编写了一个智能合约,现在是将这三者连接起来的时候了。 从虚拟钱包发送的每笔交易都需要使用你独有的私钥签名。 为了给程序提供此项许可,我们可以安全地将私钥(和 Alchemy 应用程序接口密钥)存储在一个环境文件中。 -如需了解更多关于发送交易的信息,请查看关于使用 web3 发送交易的 [本教程](/developers/tutorials/sending-transactions-using-web3-and-alchemy/)。 +要了解有关发送交易的更多信息,请查看这篇关于使用 web3 发送交易的[教程](/developers/tutorials/sending-transactions-using-web3-and-alchemy/)。 首先,在项目目录中安装 dotenv 软件包: + ``` npm install dotenv --save + ``` -然后在我们的项目根目录中创建 `.env` 文件,并将你的 MetaMask 私钥和超文本传输协议 Alchemy 应用程序接口网址加入其中。 +然后,在项目根目录中创建一个 `.env` 文件,并将你的 MetaMask 私钥和 HTTP Alchemy API URL 添加进去。 -- 遵循[这些说明](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key),从 MetaMask 导出你的私钥 +- 请按照[这些说明](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key)从 MetaMask 导出你的私钥。 - 请从下方获取超文本传输协议 Alchemy 应用程序接口网址并将其复制到剪贴板 -![复制你的 Alchemy 应用程序接口网址](./copy-alchemy-api-url.gif) +![复制你的 Alchemy API URL](./copy-alchemy-api-url.gif) -你的 `.env` 现在应该如下所示: +你的 `.env` 文件现在应该如下所示: + ``` API_URL="https://eth-sepolia.g.alchemy.com/v2/your-api-key" PRIVATE_KEY="your-metamask-private-key" + ``` 为了将它们实际连接到我们的代码,我们将在步骤 13 中在 hardhat.config.js 文件中引用这些变量。 @@ -243,13 +259,15 @@ Alchemy 非常自豪能够推动非同质化代币领域的一些巨头,包括 ## 步骤 12:安装 Ethers.js {#install-ethers} -Ethers.js 是一个软件库,通过以更加方便用户的方法打包[标准 JSON RPC 方法](/developers/docs/apis/json-rpc/),从而更容易与以太坊互动,并向以太坊提出请求。 +Ethers.js 是一个程序库,它通过将[标准的 JSON-RPC 方法](/developers/docs/apis/json-rpc/)封装成对用户更友好的方法,使得与以太坊交互和发出请求变得更加容易。 -安全帽使我们更容易将[插件](https://hardhat.org/plugins/)集成到工具和扩展功能中。 我们将利用 [Ethers 插件](https://hardhat.org/docs/plugins/official-plugins#hardhat-ethers)完成合约部署([Ethers.js](https://github.com/ethers-io/ethers.js/) 有非常简洁的部署方法)。 +Hardhat可以非常轻松地集成[插件](https://hardhat.org/plugins/),以获得额外的工具和扩展功能。 我们将利用 [Ethers 插件](https://hardhat.org/docs/plugins/official-plugins#hardhat-ethers)进行合约部署([Ethers.js](https://github.com/ethers-io/ethers.js/) 有一些非常简洁的合约部署方法)。 在你的项目目录中输入: + ``` npm install --save-dev @nomiclabs/hardhat-ethers ethers@^5.0.0 + ``` 下一步中,我们还将在 hardhat.config.js 中使用以太币。 @@ -279,30 +297,32 @@ Ethers.js 是一个软件库,通过以更加方便用户的方法打包[标准 } ``` -## 步骤 14:编写合约 {#compile-contract} +## 步骤 14:编译我们的合约 {#compile-contract} -为了确保一切正常,我们来编译一下合约。 编译任务是安全帽的内部任务之一。 +为了确保一切正常,我们来编译一下合约。 编译任务是 hardhat 的内部任务之一。 在命令行中运行: + ``` npx hardhat compile + ``` -你可能会看到关于源文件中未提供 SPDX 许可证识别码的警告,但无需担心,但愿其他的一切正常! 如果遇到问题,你可以随时在 [Alchemy cord](https://discord.gg/u72VCg3) 社区中发消息询问。 +你可能会看到关于源文件中未提供 SPDX 许可证识别码的警告,但无需担心,但愿其他的一切正常! 如果编译不成功,可以随时在 [Alchemy discord](https://discord.gg/u72VCg3) 中发消息。 ## 步骤 15:编写部署脚本 {#write-deploy} 合约已经写完,配置文件也准备妥当,现在是写合约部署脚本的时候了。 -转到 `scripts/` 文件夹,创建一个名为 `deploy.js` 的新文件,在其中添加以下内容: +导航至 `scripts/` 文件夹并创建一个名为 `deploy.js` 的新文件,将以下内容添加进去: ```js async function main() { const MyNFT = await ethers.getContractFactory("MyNFT") - // Start deployment, returning a promise that resolves to a contract object + // 开始部署,返回一个解析为合约对象的 promise const myNFT = await MyNFT.deploy() await myNFT.deployed() - console.log("Contract deployed to address:", myNFT.address) + console.log("合约已部署到地址:", myNFT.address) } main() @@ -313,40 +333,48 @@ main() }) ``` -安全帽在[合约教程](https://hardhat.org/tutorial/testing-contracts.html#writing-tests)中对这些代码的每一行均提供了很好的解释,我们在这里直接引用他们的解释。 +Hardhat在他们的[合约教程](https://hardhat.org/tutorial/testing-contracts.html#writing-tests)中极好地解释了每一行代码的作用,我们在此处采用了他们的解释。 + ``` const MyNFT = await ethers.getContractFactory("MyNFT"); + ``` ethers.js 中的 ContractFactory 是用于部署新智能合约的抽象对象,因此这里的 MyNFT 是我们非同质化代币合约实例的工厂。 使用 hardhat-ethers 插件时,ContractFactory 和合约实例默认与第一个签名者相连。 + ``` const myNFT = await MyNFT.deploy(); + ``` -调用 ContractFactory 代码中的 deploy() 函数会启动合约部署,然后返回解析为合约的 Promise。 这个对象包括我们智能合约中每个函数的对应调用方法。 +调用 ContractFactory 代码中的 deploy() 函数会启动合约部署,并返回解析为合约的 Promise。 这个对象包括我们智能合约中每个函数的对应调用方法。 -## 步骤 16:部署合约 {#deploy-contract} +## 步骤 16:部署我们的合约 {#deploy-contract} 我们终于准备好部署我们的智能合约啦! 返回项目目录的根目录,在命令行中运行: + ``` npx hardhat --network sepolia run scripts/deploy.js + ``` 你会看到类似以下所示的信息: + ``` 在地址 0x4C5266cCc4b3F426965d2f51b6D910325a0E7650 部署的合约 + ``` -如果我们访问 [Sepolia etherscan](https://sepolia.etherscan.io/) 并搜索我们的合约地址,应该能够看到它已成功部署。 如果未能立即看到它,请稍等片刻,因为部署可能需要一些时间。 交易将类似以下: +如果我们前往 [Sepolia etherscan](https://sepolia.etherscan.io/) 并搜索我们的合约地址,应该能看到它已成功部署。 如果未能立即看到它,请稍等片刻,因为部署可能需要一些时间。 交易将类似以下: ![在 Etherscan 上查看你的交易地址](./etherscan-sepoila-contract-creation.png) -From 地址应匹配你的 MetaMask 帐户地址,To 地址将显示“合约创建”。 如果我们点击进入交易,将会在“To”字段中看到我们的合约地址: +From 地址应与你的 MetaMask 帐户地址匹配,To 地址将显示“合约创建”。 如果我们点击进入交易,将会在“To”字段中看到我们的合约地址: -![在 Etherscan 区块浏览器 上查看你的合约地址](./etherscan-sepolia-tx-details.png) +![在 Etherscan 上查看你的合约地址](./etherscan-sepolia-tx-details.png) 太棒了! 你刚刚在以太坊(测试网)区块链上部署了你的非同质化代币智能合约! -为了更深入了解到底发生了什么,我们转到 [Alchemy 仪表板](https://dashboard.alchemyapi.io/explorer)中的 Explorer 选项卡。 如果你有多个 Alchemy 应用程序,请确保按应用程序筛选,然后选择“MyNFT”。 +要了解其内部工作原理,我们导航至 [Alchemy 仪表板](https://dashboard.alchemyapi.io/explorer)中的“浏览器”选项卡。 如果你有多个 Alchemy 应用程序,请确保按应用程序筛选,然后选择“MyNFT”。 -![使用 Alchemy 的浏览器仪表板查看“后端”调用](./alchemy-explorer-goerli.png) +![使用 Alchemy 的浏览器仪表板查看“内部”调用](./alchemy-explorer-goerli.png) -在这里,你会看到一系列 JSON-RPC 调用,都是在我们调用 .deploy() 函数时 Hardhat/Ethers 替我们在后端完成的。 这里有两项重要调用,一个是 [eth_sendRawTransaction](/developers/docs/apis/json-rpc/#eth_sendrawtransaction),这是实际将我们的智能合约写入 Sepolia 链的请求,另一个是 [eth_getTransactionByHash](/developers/docs/apis/json-rpc/#eth_gettransactionbyhash),这是在提供哈希值时读取有关我们交易信息的请求(发送交易时的典型模式)。 如需了解更多关于发送交易的信息,请查看关于[使用 Web3 发送交易](/developers/tutorials/sending-transactions-using-web3-and-alchemy/)的教程。 +在这里,你会看到一系列 JSON-RPC 调用,都是在我们调用 .deploy() 函数时 Hardhat/Ethers 替我们在后端完成的。 这里要指出的两个重要调用是 [eth_sendRawTransaction](/developers/docs/apis/json-rpc/#eth_sendrawtransaction)(这是将我们的智能合约实际写入 Sepolia 链的请求)和 [eth_getTransactionByHash](/developers/docs/apis/json-rpc/#eth_gettransactionbyhash)(这是在给定哈希的情况下读取我们交易相关信息的请求,是发送交易时的典型模式)。 要详细了解发送交易,请查看这篇关于[使用 Web3 发送交易](/developers/tutorials/sending-transactions-using-web3-and-alchemy/)的教程。 -以上即为本教程第 1 部分的全部内容。 在[第 2 部分,我们将通过铸造非同质化代币与我们的智能合约进行交互](/developers/tutorials/how-to-mint-an-nft/),在[第 3 部分,我们将向你演示如何在以太坊钱包中查看你的非同质化代币](/developers/tutorials/how-to-view-nft-in-metamask/)! +以上即为本教程第 1 部分的全部内容。 在[第 2 部分,我们将通过铸币 NFT 与我们的智能合约进行实际交互](/developers/tutorials/how-to-mint-an-nft/),在[第 3 部分,我们将向你展示如何在你的以太坊钱包中查看你的 NFT](/developers/tutorials/how-to-view-nft-in-metamask/)! diff --git a/public/content/translations/zh/developers/tutorials/interact-with-other-contracts-from-solidity/index.md b/public/content/translations/zh/developers/tutorials/interact-with-other-contracts-from-solidity/index.md index cf60c3c7889..d9748c8bb51 100644 --- a/public/content/translations/zh/developers/tutorials/interact-with-other-contracts-from-solidity/index.md +++ b/public/content/translations/zh/developers/tutorials/interact-with-other-contracts-from-solidity/index.md @@ -1,14 +1,8 @@ --- -title: 通过solidity与其他合约进行交互 -description: 如何对已经存在的合约进行智能合约的部署,并与其进行交互 +title: "通过 Solidity 与其他合约交互" +description: "如何从现有合约部署智能合约并与之交互" author: "jdourlens" -tags: - - "智能合约" - - "solidity" - - "remix" - - "工厂" - - "部署" - - "可组合性" +tags: [ "智能合同", "Solidity", "remix", "部署", "可组合性" ] skill: advanced lang: zh published: 2020-04-05 @@ -17,9 +11,9 @@ sourceUrl: https://ethereumdev.io/interact-with-other-contracts-from-solidity/ address: "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" --- -在之前的教程中,我们学习到了关于 [如何部署您的第一个智能合约](/developers/tutorials/deploying-your-first-smart-contract/)的内容。在此基础上,还进一步学习了一些特性,比如[使用修饰符控制访问权限](https://ethereumdev.io/organize-your-code-and-control-access-to-your-smart-contract-with-modifiers/)、[Solidity 中的错误处理等](https://ethereumdev.io/handle-errors-in-solidity-with-require-and-revert/)。 在本教程中,我们将学习如何基于一个已有的合约进行智能合约的部署,并与其交互。 +在之前的教程中,我们学习了很多知识,例如[如何部署你的第一个智能合约](/developers/tutorials/deploying-your-first-smart-contract/),以及如何为它添加一些功能,例如[使用修饰符控制访问](https://ethereumdev.io/organize-your-code-and-control-access-to-your-smart-contract-with-modifiers/)或 [Solidity 中的错误处理](https://ethereumdev.io/handle-errors-in-solidity-with-require-and-revert/)。 在本教程中,我们将学习如何从现有合约部署智能合约并与之交互。 -我们将会通过创建工厂的方式编写一个允许任何人拥有自己的`Counter`智能合约的合约,这个合约的名称将为`CounterFactory`。 首先,我们给大家展示一下初始`Counter`智能合约的代码。 +我们将创建一个合约,为 `Counter` 智能合约创建一个工厂,使其支持任何人拥有自己的 `Counter` 智能合约,该工厂的名称为 `CounterFactory`。 首先,这是我们初始 `Counter` 智能合约的代码: ```solidity pragma solidity 0.5.17; @@ -32,12 +26,12 @@ contract Counter { modifier onlyOwner(address caller) { - require(caller == _owner, "You're not the owner of the contract"); + require(caller == _owner, "你不是此合约的所有者"); _; } modifier onlyFactory() { - require(msg.sender == _factory, "You need to use the factory"); + require(msg.sender == _factory, "你需要使用工厂"); _; } @@ -57,19 +51,19 @@ contract Counter { } ``` -注意,我们稍微修改了合约代码,来记录工厂的地址和合约所有者的地址。 当您从另一个合约来调用这个合约的代码的时,msg.sender 将引用合约工厂的地址。 这是**要理解的一个要点**,因为使用合约来与其他合约进行交互是一种常见做法。 因此,在复杂的情况下,您需要特别注意谁是发送者。 +请注意,我们对合约代码进行了轻微修改,以跟踪工厂地址和合约所有者地址。 当你从另一个合约调用一个合约代码时,msg.sender 将引用我们合约工厂的地址。 由于使用一个合约与其他合约交互是一种常见做法,因此**理解这一点非常重要**。 因此,在复杂情况下,你应该注意发送者是谁。 -为此,我们也添加了修饰符`onlyFactory`,以确保改变状态的函数只能由将传递原始调用者作为参数的工厂调用。 +为此,我们还添加了一个 `onlyFactory` 修饰符,以确保更改状态的函数只能由将原始调用者作为参数传递的工厂调用。 -在我们将管理所有其他 Counters 的新`CounterFactory`中,我们会添加一个映射,该映射会将所有者关联到其 counter 合约地址: +在我们将管理所有其他计数器的新 `CounterFactory` 内部,我们将添加一个映射,它会将所有者与其计数器合约的地址关联起来: ```solidity mapping(address => Counter) _counters; ``` -在以太坊中,映射等同于 javascript 中的对象,它们允许将类型 A 的值映射到类型 B 的值。在本例中,我们将所有者的地址与 Counter 的实例进行映射。 +在以太坊中,映射等同于 Javascript 中的对象,它们可以将类型 A 的键映射到类型 B 的值。在本例中,我们将所有者的地址与其 Counter 实例进行映射。 -为某人实例化一个新的 Counter 的代码将类似于如下: +为某人实例化一个新的 Counter 将如下所示: ```solidity function createCounter() public { @@ -78,9 +72,9 @@ mapping(address => Counter) _counters; } ``` -首先,我们会检查一下此人是否已经拥有了一个 counter。 如果他未拥有 counter,我们会将他的地址传给`Counter`构造函数来实例化一个新的 counter,并将新创建的实例分配至映射。 +我们首先检查此人是否已拥有计数器。 如果他没有计数器,我们会通过将其地址传递给 `Counter` 构造函数来实例化一个新的计数器,并将新创建的实例分配给映射。 -获取一个特定 Counter 的计数的代码将类似于如下: +获取特定 Counter 的计数将如下所示: ```solidity function getCount(address account) public view returns (uint256) { @@ -93,9 +87,9 @@ function getMyCount() public view returns (uint256) { } ``` -第一个函数会检查对于某个给定的地址 Counter 合约是否存在,然后从实例中调用`getCount`方法。 第二个函数`getMyCount`只是将 msg.sender 直接传递到`getCount`函数的方法。 +第一个函数检查给定地址的 Counter 合约是否存在,然后从实例中调用 `getCount` 方法。 第二个函数 `getMyCount` 只是一个将 msg.sender 直接传递给 `getCount` 函数的快捷方式。 -`increment`函数非常相似,但是会将原始交易发送者传递到`Counter`合约。 +`increment` 函数非常类似,但是它将原始交易发送者传递给 `Counter` 合约: ```solidity function increment() public { @@ -104,11 +98,11 @@ function increment() public { } ``` -注意,如果被调用次数过多,counter 可能会遇到溢出的问题。 您应尽可能多地使用[SafeMath 库](https://ethereumdev.io/using-safe-math-library-to-prevent-from-overflows/)来防止出现这种可能的情况。 +请注意,如果调用次数过多,我们的计数器可能会成为溢出的受害者。 你应该尽可能使用 [SafeMath 库](https://ethereumdev.io/using-safe-math-library-to-prevent-from-overflows/)来防止这种情况的发生。 -要部署合约,您需要同时提供`CounterFactory`和`Counter`的代码。 针对 Remix 中的示例进行部署时,您需要选择 CounterFactory。 +要部署我们的合约,你需要同时提供 `CounterFactory` 和 `Counter` 的代码。 例如,在 Remix 中部署时,你需要选择 CounterFactory。 -下面是完整的代码: +以下是完整代码: ```solidity pragma solidity 0.5.17; @@ -121,12 +115,12 @@ contract Counter { modifier onlyOwner(address caller) { - require(caller == _owner, "You're not the owner of the contract"); + require(caller == _owner, "你不是此合约的所有者"); _; } modifier onlyFactory() { - require(msg.sender == _factory, "You need to use the factory"); + require(msg.sender == _factory, "你需要使用工厂"); _; } @@ -171,8 +165,8 @@ contract CounterFactory { } ``` -编译完成后,您将在 Remix 的部署部分选择要部署的工厂。 +编译后,在 Remix 部署部分,你将选择要部署的工厂: -![选择要在Remix中部署的工厂。](./counterfactory-deploy.png) +![在 Remix 中选择要部署的工厂](./counterfactory-deploy.png) -然后,您可以运行工厂合约并且观察值的变化情况。 如果希望通过其他地址来调用智能合约,您需要在 Remix 的帐户选择中更改地址。 +然后,你可以使用你的合约工厂并检查值的变化。 如果你想从不同的地址调用智能合约,则需要在 Remix 的帐户选择中更改地址。 diff --git a/public/content/translations/zh/developers/tutorials/ipfs-decentralized-ui/index.md b/public/content/translations/zh/developers/tutorials/ipfs-decentralized-ui/index.md new file mode 100644 index 00000000000..ccae4a07398 --- /dev/null +++ b/public/content/translations/zh/developers/tutorials/ipfs-decentralized-ui/index.md @@ -0,0 +1,73 @@ +--- +title: "用于去中心化用户界面的 IPFS" +description: "本教程将教读者如何使用 IPFS 来存储去中心化应用程序的用户界面。 尽管应用程序的数据和业务逻辑是去中心化的,但如果没有一个抗审查的用户界面,用户仍有可能失去对它的访问权限。" +author: Ori Pomerantz +tags: [ "ipfs" ] +skill: beginner +lang: zh +published: 2024-06-29 +--- + +你编写了一个令人难以置信的全新去中心化应用程序。 你甚至为它编写了一个[用户界面](/developers/tutorials/creating-a-wagmi-ui-for-your-contract/)。 但现在你担心有人会试图通过关闭你的用户界面来审查它,而这个界面只是云端的一台服务器。 在本教程中,你将学习如何通过将用户界面上传到 **[星际文件系统 (IPFS)](https://ipfs.tech/developers/)** 来避免审查,这样任何感兴趣的人都能够将其固定到服务器上以供将来访问。 + +你可以使用像 [Fleek](https://resources.fleek.xyz/docs/) 这样的第三方服务来完成所有工作。 本教程适用于那些即使需要更多工作也想充分了解自己在做什么的人。 + +## 在本地开始 {#getting-started-locally} + +有多个[第三方 IPFS 提供商](https://docs.ipfs.tech/how-to/work-with-pinning-services/#use-a-third-party-pinning-service),但最好从本地运行 IPFS 开始进行测试。 + +1. 安装 [IPFS 用户界面](https://docs.ipfs.tech/install/ipfs-desktop/#install-instructions)。 + +2. 创建一个包含你的网站的目录。 如果你正在使用 [Vite](https://vite.dev/),请使用此命令: + + ```sh + pnpm vite build + ``` + +3. 在 IPFS Desktop 中,点击**导入 > 文件夹**,然后选择上一步中创建的目录。 + +4. 选择你刚刚上传的文件夹,然后点击**重命名**。 给它一个更有意义的名称。 + +5. 再次选择它,然后点击**分享链接**。 将 URL 复制到剪贴板。 该链接将类似于 `https://ipfs.io/ipfs/QmaCuQ7yN6iyBjLmLGe8YiFuCwnePoKfVu6ue8vLBsLJQJ`。 + +6. 点击**状态**。 展开**高级**选项卡以查看网关地址。 例如,在我的系统上,地址是 `http://127.0.0.1:8080`。 + +7. 将链接步骤中的路径与网关地址结合起来,找到你的地址。 例如,对于上面的示例,URL 是 `http://127.0.0.1:8080/ipfs/QmaCuQ7yN6iyBjLmLGe8YiFuCwnePoKfVu6ue8vLBsLJQJ`。 在浏览器中打开该 URL 以查看你的网站。 + +## 上传 {#uploading} + +所以现在你可以使用 IPFS 在本地提供文件,这并不是很令人兴奋。 下一步是在你离线时让全世界都可以访问它们。 + +有许多知名的[固定服务](https://docs.ipfs.tech/concepts/persistence/#pinning-services)。 选择其中一个。 无论你使用哪种服务,都需要创建一个帐户,并向其提供 IPFS 桌面版中的**内容标识符 (CID)**。 + +就我个人而言,我发现 [4EVERLAND](https://docs.4everland.org/storage/4ever-pin/guides) 是最容易使用的。 以下是相关说明: + +1. 浏览到[仪表板](https://dashboard.4everland.org/overview)并用你的钱包登录。 + +2. 在左侧边栏中,点击 **Storage > 4EVER Pin**。 + +3. 点击**上传 > 选定的 CID**。 为你的内容命名,并提供来自 IPFS 桌面版的 CID。 目前,CID 是一个以 `Qm` 开头的字符串,后面跟着 44 个字母和数字,代表一个 [base-58 编码的](https://medium.com/bootdotdev/base64-vs-base58-encoding-c25553ff4524)哈希,例如 `QmaCuQ7yN6iyBjLmLGe8YiFuCwnePoKfVu6ue8vLBsLJQJ`,但[这很可能会改变](https://docs.ipfs.tech/concepts/content-addressing/#version-1-v1)。 + +4. 初始状态为**排队中**。 重新加载,直到它变为**已固定**。 + +5. 点击你的 CID 以获取链接。 你可以在[这里](https://bafybeifqka2odrne5b6l5guthqvbxu4pujko2i6rx2zslvr3qxs6u5o7im.ipfs.dweb.link/)看到我的应用程序。 + +6. 你可能需要激活你的帐户,才能将其固定超过一个月。 帐户激活费用约为 1 美元。 如果你关闭了它,请注销并重新登录,系统会再次要求你激活。 + +## 从 IPFS 使用 {#using-from-ipfs} + +此时,你拥有一个指向中心化网关的链接,该网关为你的 IPFS 内容提供服务。 简而言之,你的用户界面可能更安全一些,但仍然不具备抗审查能力。 要实现真正的抗审查能力,用户需要[直接从浏览器](https://docs.ipfs.tech/install/ipfs-companion/#prerequisites)使用 IPFS。 + +一旦你安装了它(并且桌面版 IPFS 正常工作),你可以在任何网站上访问 [/ipfs/``](https://any.site/ipfs/bafybeifqka2odrne5b6l5guthqvbxu4pujko2i6rx2zslvr3qxs6u5o7im),你将以去中心化的方式获得该内容。 + +## 缺点 {#drawbacks} + +你无法可靠地删除 IPFS 文件,因此,只要你在修改用户界面,最好要么保持其中心化,要么使用[星际名称系统 (IPNS)](https://docs.ipfs.tech/concepts/ipns/#mutability-in-ipfs),这是一个在 IPFS 之上提供可变性的系统。 当然,任何可变的东西都可能被审查,就 IPNS 而言,可以通过向持有其对应私钥的人施压来实现。 + +此外,某些软件包与 IPFS 存在兼容性问题,因此如果你的网站非常复杂,这可能不是一个好的解决方案。 当然,任何依赖于服务器集成的东西都不能仅仅通过将客户端放在 IPFS 上来实现去中心化。 + +## 结论 {#conclusion} + +正如以太坊让你能够将去中心化应用程序的数据库和业务逻辑方面去中心化一样,IPFS 也能让你将用户界面去中心化。 这可以让你关闭针对你的去中心化应用程序的又一个攻击向量。 + +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 diff --git a/public/content/translations/zh/developers/tutorials/kickstart-your-dapp-frontend-development-with-create-eth-app/index.md b/public/content/translations/zh/developers/tutorials/kickstart-your-dapp-frontend-development-with-create-eth-app/index.md index 6abf8c58b78..626c3fe19f3 100644 --- a/public/content/translations/zh/developers/tutorials/kickstart-your-dapp-frontend-development-with-create-eth-app/index.md +++ b/public/content/translations/zh/developers/tutorials/kickstart-your-dapp-frontend-development-with-create-eth-app/index.md @@ -1,14 +1,8 @@ --- -title: 使用 create-eth-app 启动去中心化应用程序前端开发 -description: 如何使用 create-eth-app 及其功能的概述 +title: "使用 create-eth-app 启动去中心化应用程序前端开发" +description: "create-eth-app 的用法及其功能概述" author: "Markus Waas" -tags: - - "create-eth-app" - - "前端" - - "javascript" - - "ethers.js" - - "图表" - - "defi" +tags: [ "前端", "javascript", "ethers.js", "the graph", "DeFi" ] skill: beginner lang: zh published: 2020-04-27 @@ -16,11 +10,11 @@ source: soliditydeveloper.com sourceUrl: https://soliditydeveloper.com/create-eth-app --- -上一次,我们了解 [Solidity](https://soliditydeveloper.com/solidity-overview-2020) 大的框架时,已经提到了 [create-eth-app](https://github.com/PaulRBerg/create-eth-app)。 现在,您将了解如何使用它,它集成了哪些功能以及如何对其进行扩展等内容。 这个应用程序由 [Sablier](http://sablier.com/)创始人 Paul Razvan Berg 启动,它将启动您的前端开发,并且具有多个可选集成供您选择。 +上次我们探讨了 [Solidity 的宏观概况](https://soliditydeveloper.com/solidity-overview-2020),并提到了 [create-eth-app](https://github.com/PaulRBerg/create-eth-app)。 现在,你将了解如何使用它,它集成了哪些功能以及如何对其进行扩展等内容。 这个应用程序由 [Sablier](http://sablier.com/) 创始人 Paul Razvan Berg 发起,将帮助你启动前端开发,并提供多种可选集成。 ## 安装 {#installation} -安装需要 Yarn 0.25 或更高版本 (`npm install yarn --global`)。 安装就像运行程序一样简单: +安装需要 Yarn 0.25 或更高版本(`npm install yarn --global`)。 操作非常简单,只需运行: ```bash yarn create eth-app my-eth-app @@ -28,44 +22,44 @@ cd my-eth-app yarn react-app:start ``` -这是正后台使用 [create-react-app](https://github.com/facebook/create-react-app)。 要查看您的应用程序,请打开 `http://localhost:3000/`。 当您准备好部署到生产环境中时,使用 yarn build 创建一个缩小的捆绑包。 一个简单的托管它的方法是使用 [ Netlify](https://www.netlify.com/)。 您可以创建一个 GitHub 存储库,将其添加到 Netlify,设置构建命令,这样就完成了! 您的应用程序将被托管并可供所有人使用。 所有这些都是免费的。 +它在底层使用了 [create-react-app](https://github.com/facebook/create-react-app)。 要查看你的应用程序,请打开 `http://localhost:3000/`。 当你准备好部署到生产环境中时,使用 yarn build 创建一个精简捆绑包。 一种简单的托管方法是 [Netlify](https://www.netlify.com/)。 你可以创建一个 GitHub 存储库,将其添加到 Netlify,设置构建命令,这样就完成了! 你的应用程序将被托管并可供所有人使用。 所有这些都是免费的。 ## 功能 {#features} ### React 和 create-react-app {#react--create-react-app} -首先,我们来了解应用程序的核心:React 和 _create-react-app_ 带来的所有附加功能。 如果您不想集成以太坊,那么仅使用它是一个很好的选择。 [React](https://reactjs.org/) 本身使构建交互式 UI 变得非常容易。 它可能不像 [Vue](https://vuejs.org/) 那样方便初学者,但仍然被广泛使用。 它具有更多的功能,最重要的是还有数千个附加库可供选择。 _create-react-app_ 也使它非常容易开始使用,具有的功能包括: +首先,我们来了解应用程序的核心:React 和 _create-react-app_ 带来的所有附加功能。 如果你不想集成以太坊,那么仅使用它是一个很好的选择。 [React](https://react.dev/) 本身使构建交互式用户界面变得非常容易。 它可能不像 [Vue](https://vuejs.org/) 那样对初学者友好,但它仍是主流,功能更丰富,最重要的是有数以千计的附加程序库可供选择。 使用 _create-react-app_ 也很容易上手,其功能包括: - React、JSX、ES6、TypeScript、Flow 语法支持。 -- ES6 之外的语言附加功能,如对象扩展运算符。 -- 自动添加前缀的 CSS,所以您不需要 -webkit- 或其他前缀。 +- ES6 之外的语言附加功能,如对象展开运算符。 +- 自动添加前缀的 CSS,所以你不需要 -webkit- 或其他前缀。 - 快速交互式单元测试运行程序,内置对覆盖率报告的支持。 - 对常见错误发出警告的实时开发服务器。 -- 一个用于捆绑 JS、CSS 和图片的构建脚本,带有哈希值和资源映射。 +- 一个用于捆绑JS、CSS和图片的构建脚本,带有哈希值和源映射。 -尤其是 _create-eth-app_ 正在使用新的 [hooks effect](https://reactjs.org/docs/hooks-effect.html)。 这是一种编写强大而又非常小巧的所谓功能组件的方法。 关于如何在 _create-eth-app_ 中使用 Apollo,请看下面关于 Apollo 的部分。 +_create-eth-app_ 特别使用了新的 [effect hook](https://legacy.reactjs.org/docs/hooks-effect.html)。 一种编写功能强大但代码量很小的所谓函数式组件的方法。 要了解它们在 _create-eth-app_ 中的用法,请参阅下文关于 Apollo 的部分。 -### Yarn Workspace {#yarn-workspaces} +### Yarn Workspaces {#yarn-workspaces} -[Yarn Workspace](https://classic.yarnpkg.com/en/docs/workspaces/)允许您拥有多个包, 但可以从根目录对他们进行管理,而且可以使用 `yarn install` 一次性安装所有依赖项。 这对于较小的附加包,例如智能合约地址/ABI 管理(关于您在哪里部署了哪些智能合约以及如何与它们通信的信息)或图集成等,尤其有意义,这两个包都是 `create-eth-app` 的一部分。 +[Yarn Workspaces](https://classic.yarnpkg.com/en/docs/workspaces/) 允许多个包存在,同时能够从根目录管理所有这些包,并使用 `yarn install` 一次性为所有包安装依赖项。 这对于较小的附加包尤其有意义,例如智能合约地址/ABI 管理(关于你将哪个智能合约部署在何处以及如何与其通信的信息)或图谱集成,这两者都是 `create-eth-app` 的一部分。 ### ethers.js {#ethersjs} -虽然 [Web3](https://docs.web3js.org/) 仍被广泛使用,但 [ethers.js](https://docs.ethers.io/) 作为一种替代方案,在过去一年中获得了更多的关注,并且已集成到 _create-eth-app_ 中。 您可以使用这个操作,将它更改为 Web3,或者考虑升级为 [ethers.js v5](https://docs.ethers.org/v5/),该版本即将完成测试阶段。 +虽然 [Web3.js](https://docs.web3js.org/) 仍是主流,但 [ethers.js](https://docs.ethers.io/) 在去年作为替代方案获得了更多关注,并被集成到了 _create-eth-app_ 中。 你可以使用这个操作,将它更改为 Web3,或者考虑升级为 [ethers.js v5](https://docs.ethers.org/v5/),该版本即将完成测试阶段。 -### 图表 {#the-graph} +### The Graph {#the-graph} -与 [Restful API](https://restfulapi.net/) 相比,[GraphQL](https://graphql.org/) 是处理数据的另一种方式。 与 Restful Api 相比,它们有几个优势,特别是对于去中心化的区块链数据来说更是如此。 如果您对这背后的原因感兴趣,可以看看 [GraphQL 将为去中心化网络提供动力](https://medium.com/graphprotocol/graphql-will-power-the-decentralized-web-d7443a69c69a)。 +[GraphQL](https://graphql.org/) 是与 [Restful API](https://restfulapi.net/) 相对应的一种处理数据的方式。 与 Restful 应用程序接口相比,它们有几个优势,特别是对于去中心化的区块链数据来说更是如此。 如果你对此背后的原因感兴趣,可以看看 [GraphQL Will Power the Decentralized Web](https://medium.com/graphprotocol/graphql-will-power-the-decentralized-web-d7443a69c69a)。 -通常您会直接从您的智能合约中获取数据。 想要读取上次交易的时间吗? 只需调用 `MyContract.methods.latestTradeTime().call()`,它将数据从以太坊节点(如 Infura)提取到你的去中心化应用程序。 但如果您需要数百个不同的数据点,该怎么办? 这将导致在节点上进行数百次数据提取操作,每次都有[往返延时](https://wikipedia.org/wiki/Round-trip_delay_time),使你的去中心化应用程序缓慢且效率低下。 一个变通的办法是在您的合约中设置一个取数器调用函数,一次性返回多个数据。 但这并不总是理想的。 +通常你会直接从你的智能合约中获取数据。 想要读取最新一笔交易的时间吗? 只需调用 `MyContract.methods.latestTradeTime().call()`,它会从以太坊节点获取数据并传输到你的去中心化应用程序中。 但如果你需要数百个不同的数据点,该怎么办? 这将导致在节点上进行数百次数据提取操作,每次都有[往返时延 (RTT)](https://wikipedia.org/wiki/Round-trip_delay_time),使你的去中心化应用程序缓慢且效率低下。 一个变通方法可能是在你的合约中设置一个获取器调用函数,一次返回多个数据。 但这并不总是理想的。 -然后您可能对历史数据也感兴趣。 您不仅想知道上次交易的时间,还想知道自己做过的所有交易的时间。 使用 _create-eth-app_ 子图包,阅读[文档](https://thegraph.com/docs/en/subgraphs/developing/creating/starting-your-subgraph)并使其适合您自己的合约。 如果您正在寻找受欢迎的智能合约,甚至可能已经有了一个子图。 可以查看[子图浏览器](https://thegraph.com/explorer/)。 +然后你可能对历史数据也感兴趣。 你不仅想知道上次交易的时间,还想知道自己做过的所有交易的时间。 使用 _create-eth-app_ 子图包,阅读[相关文档](https://thegraph.com/docs/en/subgraphs/developing/creating/starting-your-subgraph)并将其适配到你自己的合约。 如果你正在寻找受欢迎的智能合约,甚至可能已经有了一个子图。 查看[子图浏览器](https://thegraph.com/explorer/) 有了子图后,你可以在去中心化应用程序中编写一个简单的查询来检索所有重要的区块链数据,包括你需要的历史数据,并且只需一次提取操作即可。 ### Apollo {#apollo} -由于 [Apollo Boost](https://www.apollographql.com/docs/react/get-started/) 集成,你可以轻松将图集成到 React 去中心化应用程序中。 特别是在使用 [React hooks 和 Apollo](https://www.apollographql.com/blog/apollo-client-now-with-react-hooks) 时,获取数据就像在您的组件中写一个 GraphQl 查询一样简单: +借助 [Apollo Boost](https://www.apollographql.com/docs/react/get-started/) 集成,你可以轻松地将子图集成到你的 React 去中心化应用程序中。 特别是在使用 [React hooks 和 Apollo](https://www.apollographql.com/blog/apollo-client-now-with-react-hooks) 时,获取数据就像在你的组件中写一个 GraphQl 查询一样简单: ```js const { loading, error, data } = useQuery(myGraphQlQuery) @@ -79,32 +73,32 @@ React.useEffect(() => { ## 模板 {#templates} -在顶部,您可以从几个不同的模板中进行选择。 到目前为止,您可以使用 Aave、Comp、UniSwap 或 sablier 集成。 它们都增加了重要的服务智能合约地址以及预先制作的子图集成。 只需将模板添加到创建命令,例如 `yarn create eth-app my-eth-app --with-template aave`。 +在顶部,你可以从几个不同的模板中进行选择。 到目前为止,你可以使用 Aave、Compound、UniSwap 或 sablier 集成。 它们都增加了重要的服务智能合约地址以及预先制作的子图集成。 只需将模板添加到创建命令,例如 `yarn create eth-app my-eth-app --with-template aave`。 ### Aave {#aave} -[Aave](https://aave.com/) 是一个去中心化的货币借贷市场。 存款人向市场提供流动性以赚取被动收入,而借款人则可以利用抵押物进行借贷。 Aave 的一个独特功能是那些[闪电贷](https://docs.aave.com/developers/guides/flash-loans),让您可以在没有任何抵押品的情况下借钱,只要您在一次交易中返还贷款即可。 例如,这对于在套利交易中为您提供额外的现金很有用。 +[Aave](https://aave.com/) 是一个去中心化的货币借贷市场。 存款人向市场提供流动性以赚取被动收入,而借款人则可以利用抵押品进行借贷。 Aave 的一个独特功能是[闪电贷](https://aave.com/docs/developers/flash-loans),让你可以在没有任何抵押品的情况下借钱,只要你在一次交易中返还贷款即可。 例如,这对于在套利交易中为你提供额外的现金很有用。 -为您赢得利益的交易代币被称为 _aTokens_。 +为你赚取利息的交易代币被称为 _aTokens_。 -当您选择将 Aave 与 _create-eth-app_ 集成时,您将获得[子图集成](https://docs.aave.com/developers/getting-started/using-graphql)。 Aave 使用 The Graph,并且已经在 [Ropsten](https://thegraph.com/explorer/subgraph/aave/protocol-ropsten) 和 [Mainnet](https://thegraph.com/explorer/subgraph/aave/protocol) 上以[原始](https://thegraph.com/explorer/subgraph/aave/protocol-raw)或[格式化](https://thegraph.com/explorer/subgraph/aave/protocol)形式为您提供了几个现成的子图。 +当你选择将 Aave与 _create-eth-app_ 集成时,你将获得一个[子图集成](https://docs.aave.com/developers/getting-started/using-graphql)。 Aave 使用 The Graph,并已在 [Ropsten 测试网](https://thegraph.com/explorer/subgraph/aave/protocol-ropsten)和[主网](https://thegraph.com/explorer/subgraph/aave/protocol)上以[原始](https://thegraph.com/explorer/subgraph/aave/protocol-raw)或[格式化](https://thegraph.com/explorer/subgraph/aave/protocol)形式为你提供多个即用型子图。 -![Aave 闪电贷备忘录 – “是啊,如果我的闪电贷可以保留超过 1 笔交易,那就太好了”](./flashloan-meme.png) +![Aave 闪电贷梗图 – “是啊,如果我的闪电贷能保留超过 1 笔交易,那就太好了”](./flashloan-meme.png) ### Compound {#compound} -[ Compound ](https://compound.finance/) 类似于 Aave。 集成中已包含新的 [Compound v2 Subgraph](https://medium.com/graphprotocol/https-medium-com-graphprotocol-compound-v2-subgraph-highlight-a5f38f094195)。 在这里,赚取利益的代币竟然被称为* cTokens*。 +[Compound](https://compound.finance/) 与 Aave 类似。 该集成已包含新的 [Compound v2 子图](https://medium.com/graphprotocol/https-medium-com-graphprotocol-compound-v2-subgraph-highlight-a5f38f094195)。 令人惊讶的是,这里赚取利息的代币被称为 _cTokens_。 ### Uniswap {#uniswap} -[Uniswap](https://uniswap.exchange/) 是一个去中心化的交易所 (DEX)。 流动性供应商可以通过为交易双方提供所需的代币或以太币来赚取费用。 它正在被广泛使用,因此对于非常多的各种代币来说,它的流动性是最高的当中的一个。 例如,你可以轻松地将其集成到你的去中心化应用程序中,让用户可以将他们的以太币换成 DAI 币。 +[Uniswap](https://uniswap.exchange/) 是一个去中心化交易所 (DEX)。 流动性供应商可以通过为交易双方提供所需的代币或以太币来赚取费用。 它被广泛使用,因此在众多代币中拥有最高的流动性之一。 例如,你可以轻松地将其集成到你的去中心化应用程序中,让用户可以将他们的 ETH 兑换成 DAI。 -遗憾的是,在撰写本文时,集成仅针对 Uniswap v1,而不是 [刚刚发布的 v2](https://uniswap.org/blog/uniswap-v2/)。 +遗憾的是,在撰写本文时,集成仅针对 Uniswap v1,而不是[刚刚发布的 v2](https://uniswap.org/blog/uniswap-v2/)。 ### Sablier {#sablier} -[Sablier](https://sablier.com/) 允许用户进行流支付。 完成最初的设置后,您实际上是不断地得到您的货币,而不是在某个支付日,并且不需要进行进一步的管理。 该集成包含了它[自己的子图](https://thegraph.com/explorer/subgraph/sablierhq/sablier)。 +[Sablier](https://sablier.com/) 允许用户进行流支付。 完成最初的设置后,你实际上是不断地得到你的货币,而不是在某个支付日,并且不需要进行进一步的管理。 该集成包含其[自己的子图](https://thegraph.com/explorer/subgraph/sablierhq/sablier)。 -## 接下来是什么? {#whats-next} +## 接下来该做什么? {#whats-next} -如果您对 _create-eth-app_ 有任何疑问,请访问 [Sablier 社区服务器](https://discord.gg/bsS8T47),在那里您可以与 _create-eth-app_ 的作者取得联系。 作为接下来的第一步,您可能希望集成一个 UI 框架,例如 [Material UI](https://material-ui.com/),为您实际需要的数据编写 GraphQL 查询并设置部署。 +如果你对 _create-eth-app_ 有任何疑问,请访问 [Sablier 社区服务器](https://discord.gg/bsS8T47),在那里你可以与 _create-eth-app_ 的作者取得联系。 作为接下来的第一步,你可能希望集成一个 UI 框架,例如 [Material UI](https://mui.com/material-ui/),为你实际需要的数据编写 GraphQL 查询并设置部署。 diff --git a/public/content/translations/zh/developers/tutorials/learn-foundational-ethereum-topics-with-sql/index.md b/public/content/translations/zh/developers/tutorials/learn-foundational-ethereum-topics-with-sql/index.md index f5d501d3dce..8385de17136 100644 --- a/public/content/translations/zh/developers/tutorials/learn-foundational-ethereum-topics-with-sql/index.md +++ b/public/content/translations/zh/developers/tutorials/learn-foundational-ethereum-topics-with-sql/index.md @@ -1,11 +1,8 @@ --- -title: 通过 SQL 学习以太坊基础主题 -description: 本教程帮助读者通过使用结构化查询语言 (SQL) 查询链上数据,了解以太坊的基本概念,包括交易、区块和燃料。 +title: "通过 SQL 学习以太坊基础主题" +description: "本教程帮助读者通过使用结构化查询语言 (SQL) 查询链上数据,了解以太坊的基本概念,包括交易、区块和燃料。" author: "Paul Apivat" -tags: - - "SQL" - - "查询" - - "交易" +tags: [ "SQL", "查询", "交易" ] skill: beginner lang: zh published: 2021-05-11 @@ -13,25 +10,25 @@ source: paulapivat.com sourceUrl: https://paulapivat.com/post/query_ethereum/ --- -针对开发者的以太坊教程很多,但对于数据分析师或希望不运行客户端或节点就能查看链上数据的人员,教育资源却稀缺。 +面向开发者的以太坊教程很多,但缺少面向数据分析师或希望在不运行客户端或节点的情况下查看链上数据的人员的教育资源。 -本教程帮助读者通过 [Dune Analytics](https://dune.xyz/home) 提供的接口,使用结构化查询语言 (SQL) 查询链上数据,从而了解以太坊的基本概念,包括交易、区块和燃料。 +本教程通过 [Dune Analytics](https://dune.com/) 提供的界面,帮助读者使用结构化查询语言 (SQL) 查询链上数据,从而了解以太坊的基本概念,包括交易、区块和燃料。 -链上数据可以帮助我们理解网络和算力经济 — 以太坊,并且帮助我们理解以太坊当前所面临的挑战(例如不断上涨的燃料),更重要的是,了解一些围绕扩容解决方案的讨论。 +链上数据可以帮助我们了解以太坊(它是一个网络,也是一个算力经济体),并且应该作为理解以太坊当今所面临挑战(即不断上涨的燃料价格)以及更重要的扩容解决方案相关讨论的基础。 ### 交易 {#transactions} -用户以太坊之旅的第一步是初始化具有以太币余额的用户控制帐户或实体。 帐户类型分为两种 — 用户控制帐户或智能合约(参阅 [ethereum.org](/developers/docs/accounts/))。 +用户的以太坊之旅,始于初始化一个拥有 ETH 余额的用户控制帐户或实体。 帐户类型分为两种——用户控制帐户或智能合约(请参阅 [ethereum.org](/developers/docs/accounts/))。 -可以在诸如 [Etherscan](https://etherscan.io/) 等区块浏览器上查看任何帐户。 区块浏览器是你访问以太坊数据的门户。 它们实时显示区块上的数据、交易、矿工、帐户和其他链上活动(参阅[此处](/developers/docs/data-and-analytics/block-explorers/))。 +任何帐户都可以在 [Etherscan](https://etherscan.io/) 或 [Blockscout](https://eth.blockscout.com/) 等区块浏览器上查看。 区块浏览器是访问以太坊数据的门户。 它们实时显示区块、交易、矿工、帐户及其他链上活动的数据(请参阅[此处](/developers/docs/data-and-analytics/block-explorers/))。 -然而,用户可能希望直接查询数据,以核对外部区块浏览器提供的信息。 [Dune Analytics](https://duneanalytics.com/) 为任何对 SQL 有一定了解的人提供了这种功能。 +然而,用户可能希望直接查询数据,以核对外部区块浏览器提供的信息。 [Dune Analytics](https://dune.com/) 为任何对 SQL 有一定了解的人提供了这种功能。 -作为参考,以太坊基金会 (EF) 的智能合约帐户可以在 [Etherscan](https://etherscan.io/address/0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae) 上查看。 +作为参考,以太坊基金会 (EF) 的智能合约帐户可以在 [Blockscout](https://eth.blockscout.com/address/0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe) 上查看。 -值得注意的是,包括以太坊基金会帐户在内的所有帐户都有一个公共地址,可用来发送和接收交易。 +值得注意的是,包括以太坊基金会的帐户在内的所有帐户都有一个公共地址,可用来发送和接收交易。 -Etherscan 上的帐户余额由常规交易和内部交易构成。 尽管使用了这一名称,但内部交易并不是改变链状态的_真正_交易。 它们是通过执行合约发起的价值转移([原文](https://ethereum.stackexchange.com/questions/3417/how-to-get-contract-internal-transactions))。 因为内部交易没有签名,它们**没有**包含在区块上,并且不能通过 Dune Analytics 查询。 +Etherscan 上的帐户余额由常规交易和内部交易构成。 尽管名为内部交易,但它们并不是改变链上状态的_真正_交易。 它们是通过执行合约发起的价值转移([来源](https://ethereum.stackexchange.com/questions/3417/how-to-get-contract-internal-transactions))。 由于内部交易没有签名,它们**并未**包含在区块链上,因此无法用 Dune Analytics 查询。 因此,本教程将侧重于常规交易。 可以这样查询: @@ -61,33 +58,33 @@ SELECT FROM temp_table ``` -产生的信息与 Etherscan 交易页面提供的信息相同。 为了比较起见,下面是两种来源的信息: +这将产生与 Etherscan 交易页面上提供的信息相同的信息。 为便于比较,以下是这两个来源: #### Etherscan {#etherscan} ![](./etherscan_view.png) -[Etherscan 上以太坊基金会的合约页面。](https://etherscan.io/address/0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe) +[Blockscout 上的 EF 合约页面。](https://eth.blockscout.com/address/0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe) #### Dune Analytics {#dune-analytics} ![](./dune_view.png) -可以在[此处](https://duneanalytics.com/paulapivat/Learn-Ethereum)找到仪表板。 点击表格查看查询(另请参阅上文)。 +你可以在[此处](https://dune.com/paulapivat/Learn-Ethereum)找到看板。 点击表格查看查询(另请参阅上文)。 -### 交易明细 {#breaking_down_transactions} +### 交易详解 {#breaking_down_transactions} -提交的交易包含几条信息,包括[(原文)](/developers/docs/transactions/): +一笔已提交的交易包含以下几项信息([来源](/developers/docs/transactions/)): -- **接收者**:接收地址(通过“to”查询) -- **签名**:虽然由发送者的私钥签署交易,但我们可以通过 SQL 查询的是发送者的公共地址(“from”)。 -- **价值**:指的是转移的以太币数量(参阅 `ether` 列)。 -- **数据**:指的是经过哈希运算的任意数据(参阅 `data` 列) -- **gasLimit** – 交易可以消耗的最大数量的燃料单位。 燃料单位代表计算步骤 -- **maxPriorityFeePerGas** - 作为矿工小费包含的最大燃料数量 +- **接收方**:接收地址(查询时用 "to") +- **签名**:虽然由发送者的私钥签署交易,但我们可以用 SQL 查询的是发送者的公共地址("from")。 +- **价值**:这是转移的 ETH 数量(请参阅 `ether` 列)。 +- **数据**:这是经过哈希运算的任意数据(请参阅 `data` 列) +- **gasLimit** – 交易可消耗的最大燃料单位数量。 燃料单位代表计算步骤 +- **maxPriorityFeePerGas** - 作为给矿工的小费所包含的最大燃料数量 - **maxFeePerGas** - 愿意为交易支付的最大燃料数量(包括 baseFeePerGas 和 maxPriorityFeePerGas) -我们可以向以太坊基金会公共地址查询这些具体的交易信息: +我们可以查询发送至以太坊基金会公共地址的交易中的这些具体信息: ```sql SELECT @@ -106,15 +103,15 @@ ORDER BY block_time DESC ### 区块 {#blocks} -每笔交易都会改变以太坊虚拟机 ([EVM](/developers/docs/evm/)) 的状态([原文](/developers/docs/transactions/))。 交易广播到网络上进行验证并被记录在一个区块中。 每笔交易都与一个区块编号相关联。 要查看数据,我们可以查询一个具体的区块编码:12396854(截至本文撰写日期 2021 年 11 月 5 日,以太坊基金会交易中最新的区块)。 +每笔交易都会改变以太坊虚拟机 ([EVM](/developers/docs/evm/)) 的状态([来源](/developers/docs/transactions/))。 交易会广播到网络进行验证,并被包含在一个区块中。 每笔交易都与一个区块编号相关联。 要查看数据,我们可以查询一个具体的区块编号:12396854(在撰写本文时 [2021 年 5 月 11 日],这是以太坊基金会交易中最新的区块)。 -此外,当我们查询下两个区块时,我们可以看到每个区块包含上一个区块的哈希值(即父哈希值),以此来说明区块链是如何形成的。 +此外,当我们查询下两个区块时,可以看到每个区块都包含上一个区块的哈希值(即父哈希),这说明了区块链是如何形成的。 -每个区块都包含对其父块的引用。 如下面的 `hash` 和 `parent_hash` 列所示([原文](/developers/docs/blocks/)): +每个区块都包含对其父区块的引用。 这在下面的 `hash` 和 `parent_hash` 列之间有所显示([来源](/developers/docs/blocks/)): -![父_哈希值](./parent_hash.png) +![parent_hash](./parent_hash.png) -下面是 Dune Analytics上的[查询](https://duneanalytics.com/queries/44856/88292): +以下是 Dune Analytics 上的[查询](https://dune.com/queries/44856/88292): ```sql SELECT @@ -130,14 +127,14 @@ LIMIT 10 我们可以通过查询时间、区块编号、难度、哈希值、父哈希值及随机数来检查一个区块。 -此查询唯一不包含的内容是_交易列表_,需要通过下面的单独查询和_状态根_来查看它。 完整或归档节点将存储所有交易和状态转换,允许客户端随时查询链的状态。 因为这需要非常大的存储空间,我们可以将链数据与状态数据分开: +此查询唯一未涵盖的是_交易列表_(这需要下文的单独查询)和_状态根_。 完整节点或归档节点将存储所有交易和状态转换,允许客户端随时查询链的状态。 因为这需要非常大的存储空间,我们可以将链数据与状态数据分开: - 链数据(区块列表、交易) - 状态数据(每次交易状态转换的结果) -状态根属于状态数据,是_隐式_数据(未存储在链上),而链数据是显式数据并存储在链上([原文](https://ethereum.stackexchange.com/questions/359/where-is-the-state-data-stored))。 +状态根属于后者,是_隐式_数据(不存储在链上),而链数据是显式数据,存储在链本身上([来源](https://ethereum.stackexchange.com/questions/359/where-is-the-state-data-stored))。 -在本教程中,我们将侧重于_可以_在 Dune Analytics 上使用 SQL 查询的链上数据。 +在本教程中,我们将重点关注那些_可以_通过 Dune Analytics 用 SQL 查询的链上数据。 如上所述,每个区块都包含一个交易列表,我们可以通过筛选一个特定区块来查询它。 我们将尝试最新的区块 12396854: @@ -151,7 +148,7 @@ ORDER BY block_time DESC` ![](./list_of_txn.png) -添加到链中的这个单独区块改变了以太坊虚拟机 ([EVM](/developers/docs/evm/)) 的状态。 几十笔,有时数百笔交易会同时进行验证。 在本例中,记录了 222 笔交易。 +这个被添加到链上的区块,改变了以太坊虚拟机 ([EVM](/developers/docs/evm/)) 的状态。 有时几十笔、甚至几百笔交易会同时得到验证。 在这个特定的案例中,包含了 222 笔交易。 要查看实际有多少笔成功交易,我们将添加另一个筛选器来计算成功的交易: @@ -166,13 +163,13 @@ SELECT FROM temp_table ``` -对于区块 12396854,在 222 笔交易中,有 204 笔成功验证: +对于区块 12396854,在 222 笔总交易中,有 204 笔成功验证: ![](./successful_txn.png) -交易请求每秒发生数十次,但区块大约每 15 秒提交一次([原文](/developers/docs/blocks/))。 +交易请求每秒发生数十次,但区块大约每 15 秒提交一次([来源](/developers/docs/blocks/))。 -要了解大约每 15 秒产生一个区块,我们可以用一天的总秒数 (86400) 除以 15,得到估算的每日平均区块数量(大约 5760 个)。 +要了解大约每 15 秒产生一个区块,我们可以用一天的总秒数 (86400) 除以 15,得到估算的每日平均区块数量(约 5760 个)。 每天产生的以太坊区块数量图表(2016 年至今)如下所示: @@ -182,10 +179,10 @@ FROM temp_table ![](./avg_daily_blocks.png) -查询如下所示: +查询如下: ```sql -# query to visualize number of blocks produced daily since 2016 +# 用于可视化自 2016 年以来每日产出区块数量的查询 SELECT DATE_TRUNC('day', time) AS dt, @@ -194,7 +191,7 @@ FROM ethereum."blocks" GROUP BY dt OFFSET 1 -# average number of blocks produced per day +# 每日产出区块的平均数量 WITH temp_table AS ( SELECT @@ -209,13 +206,13 @@ SELECT FROM temp_table ``` -2016 年以来每天产生的平均区块数量略高于 5,874 个。 或者,将 86400 秒除以平均区块数量 5874 应得到 14.7 秒,或大约每 15 秒一个区块。 +自 2016 年以来,每日产出的平均区块数量为 5,874,略高于该估算值。 另外,将 86400 秒除以 5874 个平均区块数,得出 14.7 秒,即大约每 15 秒一个区块。 ### 燃料 {#gas} -区块的大小是有限的。 最大区块大小是动态的,根据网络需求在 12,500,000 到 25,000,000 个单位之间变化。 需要设置大小限制,防止任意大的区块大小给全节点造成磁盘空间和速度要求方面的压力([出处](/developers/docs/blocks/))。 +区块的大小是有限的。 最大区块大小是动态的,根据网络需求在 12,500,000 到 25,000,000 个单位之间变化。 需要设置限制,以防止任意大的区块给完整节点在磁盘空间和速度方面带来压力([来源](/developers/docs/blocks/))。 -了解区块燃料限额的一种方法是将其视为区块空间(可在其中批量处理交易)的**供应**。 可以查询并显示从 2016 年至今的区块燃料限额: +理解区块燃料限制的一种方法是,将其看作是可用于批量处理交易的区块空间的**供应**。 可以查询并可视化从 2016 年至今的区块燃料限制: ![](./avg_gas_limit.png) @@ -228,7 +225,7 @@ GROUP BY dt OFFSET 1 ``` -每天都有实际的燃料使用量,用于支付在以太坊链上完成的计算(例如,发送交易、调用智能合同、铸造非同质化代币)。 这是对以太坊可用区块空间的**需求**: +然后是每日实际使用的燃料,用于支付在以太坊链上完成的计算(即发送交易、调用智能合约、铸造 NFT)。 这是对以太坊可用区块空间的**需求**: ![](./daily_gas_used.png) @@ -241,17 +238,17 @@ GROUP BY dt OFFSET 1 ``` -我们还可以将这两个图表合并在一起,看看**需求和供应**如何契合: +我们还可以将这两个图表并列,看看**需求和供应**如何匹配: -![燃料_需求_供应](./gas_demand_supply.png) +![gas_demand_supply](./gas_demand_supply.png) -因此,考虑到现有的供应情况,我们可以理解燃料价格是以太坊区块空间需求量的函数。 +因此,在给定可用供应的情况下,我们可以将燃料价格理解为以太坊区块空间需求的函数。 -最后,我们可能想查询以太坊链的日均燃料价格,但种查询会造成特别长的查询时间,所以我们将进行筛选,查询以太坊基金会对每笔交易支付的平均燃料数额。 +最后,我们可能想查询以太坊链的日均燃料价格,但这样做会导致查询时间特别长,所以我们将筛选查询,只查询以太坊基金会为每笔交易支付的平均燃料量。 ![](./ef_daily_gas.png) -我们可以看到多年来为以太坊基金会地址上进行的全部交易而支付的燃料价格。 查询如下: +我们可以看到多年来,向以太坊基金会地址发起的交易所支付的燃料价格。 查询如下: ```sql SELECT @@ -265,8 +262,8 @@ ORDER BY block_time DESC ### 总结 {#summary} -在本教程中,我们经过查询和感受链上数据,了解了以太坊基础概念以及以太坊区块链工作原理。 +通过本教程,我们查询并感受了链上数据,从而了解了以太坊的基本概念以及以太坊区块链的工作原理。 -包含本教程中所用全部代码的仪表板可以在[此处](https://duneanalytics.com/paulapivat/Learn-Ethereum)找到。 +包含本教程中所有代码的看板可以在[此处](https://dune.com/paulapivat/Learn-Ethereum)找到。 -若要更多地使用数据来探索 Web3,[请在推特上找到我](https://twitter.com/paulapivat)。 +若要更多地使用数据来探索 Web3,请在 [Twitter](https://twitter.com/paulapivat) 上找到我。 diff --git a/public/content/translations/zh/developers/tutorials/logging-events-smart-contracts/index.md b/public/content/translations/zh/developers/tutorials/logging-events-smart-contracts/index.md index 1edade90aac..94f0caf04b4 100644 --- a/public/content/translations/zh/developers/tutorials/logging-events-smart-contracts/index.md +++ b/public/content/translations/zh/developers/tutorials/logging-events-smart-contracts/index.md @@ -1,12 +1,8 @@ --- -title: 使用事件记录智能合约中的数据 -description: 智能合约事件的简介,以及如何利用事件来记录数据 +title: "使用事件记录智能合约中的数据" +description: "智能合约事件的简介,以及如何利用事件来记录数据" author: "jdourlens" -tags: - - "智能合约" - - "remix" - - "solidity" - - "事件" +tags: [ "智能合同", "remix", "Solidity", "事件" ] skill: intermediate lang: zh published: 2020-04-03 @@ -15,7 +11,7 @@ sourceUrl: https://ethereumdev.io/logging-data-with-events/ address: "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" --- -在solidity中,[事件](/developers/docs/smart-contracts/anatomy/#events-and-logs)是智能合约可触发的调度信号。 去中心化应用程序或其他任何连接到以太坊 JSON-PRC 应用程序接口的程序,都可以监听这些事件并执行相应操作。 还可以为事件编制索引,便于以后可以搜索事件历史。 +在 Solidity 中,[事件](/developers/docs/smart-contracts/anatomy/#events-and-logs)是智能合约可以发出的信号。 去中心化应用程序或任何连接到以太坊 JSON-RPC API 的应用都可以监听这些事件并采取相应行动。 还可以为事件编制索引,便于以后可以搜索事件历史。 ## 事件 {#events} @@ -25,9 +21,9 @@ address: "0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE" event Transfer(address indexed from, address indexed to, uint256 value); ``` -事件签名在合约代码中声明,可以使用 emit 关键字触发。 例如,转账事件记录谁发送了转账 (_from_)、发送给谁 (_to_) 以及转移了多少代币 (_value_)。 +事件签名在合约代码中声明,可以使用 `emit` 关键字触发。 例如,转账事件记录了谁发送了转账 (`_from`)、转账给谁 (`_to`),以及转账的代币数量 (`_value`)。 -如果我们回到我们的 Counter 智能合约并决定在每次价值变化时记录。 由于这个合约不是为了部署,而是作为基础,通过扩展来构建另一个合约:因此它被称为抽象合约。 在我们的计数器示例中,此合约如下所示: +如果我们回到我们的 Counter 智能合约并决定在每次值变化时记录。 由于这个合约不是为了部署,而是作为基础,通过扩展来构建另一个合约:因此它被称为抽象合约。 在我们的计数器示例中,此合约如下所示: ```solidity pragma solidity 0.5.17; @@ -36,16 +32,16 @@ contract Counter { event ValueChanged(uint oldValue, uint256 newValue); - // Private variable of type unsigned int to keep the number of counts + // 用于保存计数的私有无符号整数变量 uint256 private count = 0; - // Function that increments our counter + // 递增计数器的函数 function increment() public { count += 1; emit ValueChanged(count - 1, count); } - // Getter to get the count value + // 用于获取计数值的 getter 函数 function getCount() public view returns (uint256) { return count; } @@ -55,12 +51,12 @@ contract Counter { 注意: -- **第5行**:我们声明了事件及其包含的内容、旧值以及新值。 +- **第 5 行**:我们声明了事件及其包含的内容、旧值以及新值。 -- **第13行**:当我们增加count变量的值时,我们会触发事件。 +- **第 13 行**:当我们增加 `count` 变量的值时,我们会触发事件。 -如果我们现在部署合约并调用increment函数,如果你在名为logs的数组内单击新交易,我们将看到Remix会自动显示它。 +如果我们现在部署合约并调用 `increment` 函数,如果你在名为 `logs` 的数组内单击新交易,我们将看到 Remix 会自动显示它。 -![Remix截屏](./remix-screenshot.png) +![Remix 屏幕截图](./remix-screenshot.png) -日志在调试智能合约时非常有用,另一方面,如果你构建一个不同人使用的应用,并且使分析更容易跟踪和了解你的智能合约的使用情况,那么日志也是非常重要的手段。 交易生成的日志显示在常见区块浏览器中,例如,你还可以使用日志创建链下脚本,以便监听特定事件并在事件发生时采取行动。 +日志在调试智能合约时非常有用,但如果你构建供不同人使用的应用程序,日志也很重要,因为它们可以让你更轻松地进行分析,以跟踪和了解你的智能合约是如何被使用的。 交易生成的日志显示在常见区块浏览器中,例如,你还可以使用日志创建链下脚本,以便监听特定事件并在事件发生时采取行动。 diff --git a/public/content/translations/zh/developers/tutorials/merkle-proofs-for-offline-data-integrity/index.md b/public/content/translations/zh/developers/tutorials/merkle-proofs-for-offline-data-integrity/index.md index 6b874fe3699..cd11dc0992f 100644 --- a/public/content/translations/zh/developers/tutorials/merkle-proofs-for-offline-data-integrity/index.md +++ b/public/content/translations/zh/developers/tutorials/merkle-proofs-for-offline-data-integrity/index.md @@ -1,9 +1,8 @@ --- -title: 离线数据完整性的默克尔证明 -description: 在链上确保链下数据的完整性 +title: "离线数据完整性的默克尔证明" +description: "在链上确保主要存储在链下的数据的数据完整性" author: Ori Pomerantz -tags: - - "storage" +tags: [ "存储" ] skill: advanced lang: zh published: 2021-12-30 @@ -11,15 +10,21 @@ published: 2021-12-30 ## 简介 {#introduction} -理想的情况下,我们想要将所有东西存储在以太坊存储器中。这些数据存储于数以千计的计算机中 且有极高的可用性(数据不会被审查)和完整性(不能在未经授权的情况下修改数据), 但存储一个 32 字节的词一般需要花费 20,000 燃料。 在撰写此教程时,该费用 等于 6.60 美元。 每字节 21 美分对许多应用程序来说都过于昂贵。 +理想的情况下,我们想要将所有东西存储在以太坊存储器中。这些数据存储于数以千计的计算机中 +且有极高的可用性(数据不会被审查)和完整性(不能在未经授权的情况下修改数据), +但存储一个 32 字节的词一般需要花费 20,000 燃料。 在撰写此教程时,该费用 +等于 6.60 美元。 每字节 21 美分对许多应用程序来说都过于昂贵。 -为了解决这个问题,以太坊生态系统开发了[许多以去中心化方式存储数据的 代替方法](/developers/docs/storage/)。 通常情况下, 需要在可用性与价格之间进行取舍。 然而,完整性通常可以得到保证。 +为了解决这个问题,以太坊生态系统开发了许多以去中心化 +方式存储数据的替代方法。 通常情况下, +需要在可用性与价格之间进行取舍。 然而,完整性通常可以得到保证。 -本篇文章中,你将学习**如何**在以下情况下确保数据的完整性:不将数据存储在区块链上,而是使用 [Merkle 证明](https://computersciencewiki.org/index.php/Merkle_proof)。 +在本文中,你将学习**如何**使用 +[默克尔证明](https://computersciencewiki.org/index.php/Merkle_proof),在不将数据存储在区块链上的情况下确保数据完整性。 ## 工作原理 {#how-does-it-work} -理论上,我们只需要存储链上数据的哈希值,然后将所有数据发送到需要这些数据的交易中。 但是,这会非常昂贵。 1 字节的数据通过交易发送的成本约 16 个燃料,目前约 0.5 美分,或每千字节约 5 美元。 每兆字节 5,000 美元,这对于许多应用程序来说仍然太昂贵,而且还没有加上对数据进行哈希计算的费用。 +理论上,我们只需将数据的哈希存储在链上,并在需要它的交易中发送所有数据。 但是,这会非常昂贵。 1 字节的数据通过交易发送的成本约 16 个燃料,目前约 0.5 美分,或每千字节约 5 美元。 每兆字节 5,000 美元,这对于许多应用程序来说仍然太昂贵,而且还没有加上对数据进行哈希计算的费用。 解决办法是反复对不同的数据子集进行哈希计算。对于不需要发送的数据,只要发送哈希值即可。 默克尔树是一种树型数据结构,每个节点值都是其下方节点的哈希值: @@ -27,15 +32,15 @@ published: 2021-12-30 根哈希是唯一需要存储在链上的部分。 为了证明一个特定值,你需要提供所有与之合并才能获取根的哈希值。 例如,要证明 `C`,你需要提供 `D`、`H(A-B)` 和 `H(E-H)`。 -![C 值证明](proof-c.png) +![C 值的证明](proof-c.png) ## 实现 {#implementation} -[此处提供示例代码](https://github.com/qbzzt/merkle-proofs-for-offline-data-integrity)。 +[此处提供了示例代码](https://github.com/qbzzt/merkle-proofs-for-offline-data-integrity)。 -### 链下代码 {#off-chain-code} +### 链下代码 {#offchain-code} -在这篇文章中,我们使用 JavaScript 进行链下计算。 大多数去中心化应用程序的 JavaScript 中都有链下组件。 +在本文中,我们使用 JavaScript 进行链下计算。 大多数去中心化应用程序的 JavaScript 中都有其链下组件。 #### 创建默克尔根 {#creating-the-merkle-root} @@ -45,44 +50,48 @@ published: 2021-12-30 const ethers = require("ethers") ``` -[我们使用源自以太币包的哈希函数](https://docs.ethers.io/v5/api/utils/hashing/#utils-keccak256)。 +[我们使用 ethers 包中的哈希函数](https://docs.ethers.io/v5/api/utils/hashing/#utils-keccak256)。 ```javascript -// The raw data whose integrity we have to verify. The first two bytes a -// are a user identifier, and the last two bytes the amount of tokens the -// user owns at present. +// 需要我们验证其完整性的原始数据。前两个字节 +// 是用户标识符,后两个字节是该 +// 用户当前拥有的代币数量。 const dataArray = [ 0x0bad0010, 0x60a70020, 0xbeef0030, 0xdead0040, 0xca110050, 0x0e660060, 0xface0070, 0xbad00080, 0x060d0091, ] ``` -例如,将每条数据编码为单个 256 位整数,并以非 JSON 的格式存储。 然而,这意味着在提取合约中的数据时,可以大大减少处理工作,从而显著降低了燃料成本。 [你可以在链上读取 JSON 格式的数据](https://github.com/chrisdotn/jsmnSol),但请尽量避免这么做。 +例如,将每条数据编码为单个 256 位整数,并以非 JSON 的格式存储。 然而,这意味着在提取合约中的数据时,可以大大减少处理工作,从而显著降低了燃料成本。 [你可以在链上读取 JSON](https://github.com/chrisdotn/jsmnSol),但如果可以避免,最好不要这么做。 ```javascript -// The array of hash values, as BigInts +// 作为 BigInt 的哈希值数组 const hashArray = dataArray ``` 在此例中,我们的数据开始就是 256 位,因此不需要处理。 如果我们使用更复杂的数据结构,如字符串,我们需要确保先取数据的哈希值并获取哈希数组。 请注意,还有一个原因是我们不关心用户是否知道其他用户的信息。 否则,我们将不得不进行散列计算,使用户 1 不知道用户 0 的值,用户 2 不知道用户 3 的值,等等。 ```javascript -// Convert between the string the hash function expects and the -// BigInt we use everywhere else. +// 在哈希函数所需的字符串与 +// 我们在其他任何地方使用的 BigInt 之间进行转换。 const hash = (x) => BigInt(ethers.utils.keccak256("0x" + x.toString(16).padStart(64, 0))) ``` -以太币哈希函数的预期结果是一个带十六进制数字的 JavaScript 字符串,如 `0x60A7`,并用另一个相同结构的字符串响应。 然而,对于代码的其他部分,使用 `BigInt` 类型更为容易,所以我们将转换为一个十六进制字符串,然后再转回 BigInt。 +ethers 哈希函数需要一个包含十六进制数的 JavaScript 字符串(例如 `0x60A7`),并返回另一个具有相同结构的字符串。 但是,对于代码的其余部分,使用 `BigInt` 会更简单,因此我们将其转换为十六进制字符串,然后再转换回来。 ```javascript -// Symmetrical hash of a pair so we won't care if the order is reversed. +// 对称哈希一对值,这样我们就不必关心顺序是否颠倒。 const pairHash = (a, b) => hash(hash(a) ^ hash(b)) ``` -此函数是对称的(a [xor](https://en.wikipedia.org/wiki/Exclusive_or) b 的哈希值)。 这意味着在检查默克尔证明时,我们不必烦恼是将证明中的值放在计算值之前还是之后。 默克尔证明在链上进行检查,所以链上的步骤越少越好。 +这个函数是对称的(a [xor](https://en.wikipedia.org/wiki/Exclusive_or) b 的哈希)。 这意味着在检查默克尔证明时,我们不必烦恼是将证明中的值放在计算值之前还是之后。 默克尔证明在链上进行检查,所以链上的操作越少越好。 -警告: 密码学没有表面看起来那么容易。 本文的初始版本提供了哈希函数 `hash(a^b)`。 那是一个**糟糕的**想法,因为这意味着如果知道 `a` 和 `b` 的合法值,则可以使用 `b' = a^b^a'` 证明任何所需的 `a'` 值。 使用此函数,就必须计算 `b'`,令 `hash(a') ^ hash(b')` 等于一个已知值(通往根的下一个分支),这要困难得多。 +警告: +密码学没有表面看起来那么容易。 +本文的初始版本使用了哈希函数 `hash(a^b)`。 +那是一个**糟糕**的想法,因为这意味着如果你知道 `a` 和 `b` 的合法值,就可以使用 `b' = a^b^a'` 来证明任何你想要的 `a'` 值。 +使用这个函数,你必须计算 `b'`,使得 `hash(a') ^ hash(b')` 等于一个已知值(通往根节点的下一个分支),这就困难得多了。 ```javascript // The value to denote that a certain branch is empty, doesn't @@ -95,11 +104,11 @@ const empty = 0n ![缺少分支的默克尔树](merkle-empty-hash.png) ```javascript -// Calculate one level up the tree of a hash array by taking the hash of -// each pair in sequence +// 通过按顺序获取每对值的哈希, +// 计算哈希数组在树中的上一层 const oneLevelUp = (inputArray) => { var result = [] - var inp = [...inputArray] // To avoid over writing the input // Add an empty value if necessary (we need all the leaves to be // paired) + var inp = [...inputArray] // 避免覆盖输入 // 如有必要,添加一个空值(我们需要所有的叶子都 // 配对) if (inp.length % 2 === 1) inp.push(empty) @@ -110,13 +119,13 @@ const oneLevelUp = (inputArray) => { } // oneLevelUp ``` -此函数通过对默克尔树中当前层级的值对进行哈希处理来上升一个层级。 请注意,这不是最高效的实现。我们本来可以避免重复输入,并且只需在循环中适当地加上 `hashEmpty`,但此代码为了提高可读性进行过优化。 +此函数通过对默克尔树中当前层级的值对进行哈希处理来上升一个层级。 请注意,这不是最高效的实现,我们本可以避免复制输入,只需在循环中的适当位置添加 `hashEmpty`,但此代码为可读性进行了优化。 ```javascript const getMerkleRoot = (inputArray) => { var result - result = [...inputArray] // Climb up the tree until there is only one value, that is the // root. // // If a layer has an odd number of entries the // code in oneLevelUp adds an empty value, so if we have, for example, // 10 leaves we'll have 5 branches in the second layer, 3 // branches in the third, 2 in the fourth and the root is the fifth + result = [...inputArray] // 沿树向上,直到只剩一个值,这个值就是 // 根。 // // 如果某一层有奇数个条目, // oneLevelUp 中的代码会添加一个空值,因此如果我们有(例如) // 10 个叶子,那么第二层将有 5 个分支,第三层 // 有 3 个,第四层有 2 个,根是第五个 while (result.length > 1) result = oneLevelUp(result) @@ -126,35 +135,35 @@ const getMerkleRoot = (inputArray) => { 要到达根,一直上升到只剩下一个值的层级。 -#### 创建一个默克尔证明 {#creating-a-merkle-proof} +#### 创建默克尔证明 {#creating-a-merkle-proof} 默克尔证明是与要证明的值一起哈希处理以便返回默克尔根的值。 要证明的值往往来自其他数据,因此这里更愿意单独提供,而不是作为代码的一部分。 ```javascript -// A merkle proof consists of the value of the list of entries to -// hash with. Because we use a symmetrical hash function, we don't -// need the item's location to verify the proof, only to create it +// 默克尔证明包含与之哈希的条目 +// 列表的值。因为我们使用了对称哈希函数,我们不 +// 需要条目的位置来验证证明,只需要用它来创建证明 const getMerkleProof = (inputArray, n) => {     var result = [], currentLayer = [...inputArray], currentN = n -    // Until we reach the top +    // 直到我们到达顶部     while (currentLayer.length > 1) { -        // No odd length layers +        // 没有奇数长度的层         if (currentLayer.length % 2)             currentLayer.push(empty)         result.push(currentN % 2 -               // If currentN is odd, add with the value before it to the proof +               // 如果 currentN 是奇数,则将其之前的值添加到证明中             ? currentLayer[currentN-1] -               // If it is even, add the value after it +               // 如果是偶数,则添加其后的值             : currentLayer[currentN+1]) ``` -我们对 `(v[0],v[1])`、`(v[2],v[3])` 等进行哈希处理。 因此,对于偶数值,我们需要下一个值,而奇数值则需要上一个值。 +我们对 `(v[0],v[1])`、`(v[2],v[3])` 等进行哈希。 因此,对于偶数值,我们需要下一个值,而奇数值则需要上一个值。 ```javascript -        // Move to the next layer up +        // 移动到上一层         currentN = Math.floor(currentN/2)         currentLayer = oneLevelUp(currentLayer)     }   // while currentLayer.length > 1 @@ -163,9 +172,9 @@ const getMerkleProof = (inputArray, n) => { }   // getMerkleProof ``` -### 链上代码 {#on-chain-code} +### 链上代码 {#onchain-code} -最后,我们有核查证明的代码。 链上代码用 [Solidity](https://docs.soliditylang.org/en/v0.8.11/) 语言编写。 优化在这里更为重要,因为燃料费相对昂贵。 +最后,我们有核查证明的代码。 链上代码是用 [Solidity](https://docs.soliditylang.org/en/v0.8.11/) 编写的。 优化在这里更为重要,因为燃料费相对昂贵。 ```solidity //SPDX-License-Identifier: Public Domain @@ -174,7 +183,7 @@ pragma solidity ^0.8.0; import "hardhat/console.sol"; ``` -编写此代码时,我使用的是[安全帽开发环境](https://hardhat.org/),它使我们在开发过程中可以获得 [Solidity 的控制台输出](https://hardhat.org/tutorial/debugging-with-hardhat-network.html)。 +我使用 [Hardhat 开发环境](https://hardhat.org/) 编写了此代码,该环境允许我们在开发时从 [Solidity 获取控制台输出](https://hardhat.org/tutorial/debugging-with-hardhat-network.html)。 ```solidity @@ -185,15 +194,15 @@ contract MerkleProof {       return merkleRoot;     } -    // Extremely insecure, in production code access to -    // this function MUST BE strictly limited, probably to an -    // owner +    // 极不安全,在生产代码中,对 +    // 此函数的访问权限必须受到严格限制,可能仅限于 +    // 所有者     function setRoot(uint _merkleRoot) external {       merkleRoot = _merkleRoot;     }   // setRoot ``` -为默克尔根设置和获取函数。 在生产系统中,让每个人都更新默克尔根是一个_非常糟糕的主意_。 这里这样做是为了简化示例代码。 **不要在数据完整性非常重要的系统上执行**。 +为默克尔根设置和获取函数。 在生产系统中,允许任何人更新默克尔根是一个_极其糟糕的主意_。 这里这样做是为了简化示例代码。 **不要在数据完整性至关重要的系统上这样做**。 ```solidity     function hash(uint _a) internal pure returns(uint) { @@ -205,12 +214,12 @@ contract MerkleProof {     } ``` -此函数生成一个配对哈希值。 它只是将 `hash` 和 `pairHash` 函数的 JavaScript 代码转变为 Solidity。 +此函数生成一个配对哈希值。 这只是 `hash` 和 `pairHash` 的 JavaScript 代码的 Solidity 翻译版本。 -**注意:**这是又一次对可读性的优化。 根据[函数定义](https://www.tutorialspoint.com/solidity/solidity_cryptographic_functions.htm),也许可以将数据存储为 [`bytes32`](https://docs.soliditylang.org/en/v0.5.3/types.html#fixed-size-byte-arrays) 类型值并避免转换。 +\*\*注意:\*\*这是另一个为可读性而优化的例子。 根据[函数定义](https://www.tutorialspoint.com/solidity/solidity_cryptographic_functions.htm),或许可以将数据存储为 [`bytes32`](https://docs.soliditylang.org/en/v0.5.3/types.html#fixed-size-byte-arrays) 值,从而避免转换。 ```solidity -    // Verify a Merkle proof +    // 验证默克尔证明     function verifyProof(uint _value, uint[] calldata _proof)         public view returns (bool) {       uint temp = _value; @@ -226,16 +235,18 @@ contract MerkleProof { }  // MarkleProof ``` -用数学符号表示,默克尔证明的验证看起来像这样:`H(proof_n, H(proof_n-1, H(proof_n-2, ... H(proof_1, H(proof_0, value))...)))`. 此代码实现了默克尔证明。 +用数学符号表示,默克尔证明验证如下所示:`H(proof_n, H(proof_n-1, H(proof_n-2, ...` H(proof_1, H(proof_0, value))...)))`。 此代码实现了默克尔证明。 -## 默克尔证明和卷叠很难混淆 {#merkle-proofs-and-rollups} +## 默克尔证明与卷叠 {#merkle-proofs-and-rollups} -默克尔证明对[卷叠](/developers/docs/scaling/#rollups)的作用不大。 原因在于,卷叠将所有交易数据写入一层网络,但在二层网络进行处理。 发送交易的默克尔证明的成本平均达到每个层级 638 个燃料(目前,如果字节不为零,调用数据中一个字节花费 16 个燃料,如果为零,则花费 4 个燃料)。 如果我们的数据包含 1024 个字,默克尔证明需要 10 个层级,或者总共 6380 个燃料。 +默克尔证明不能与[卷叠](/developers/docs/scaling/#rollups)很好地配合使用。 原因在于,卷叠将所有交易数据写入一层网络,但在二层网络进行处理。 发送交易的默克尔证明的成本平均达到每个层级 638 个燃料(目前,如果字节不为零,调用数据中一个字节花费 16 个燃料,如果为零,则花费 4 个燃料)。 如果我们的数据包含 1024 个字,默克尔证明需要 10 个层级,或者总共 6380 个燃料。 -举一个[乐观卷叠](https://public-grafana.optimism.io/d/9hkhMxn7z/public-dashboard?orgId=1&refresh=5m)的示例,写入一层网络的燃料成本约为 100 gwei,写入二层网络的成本为 0.001 gwei(这里按正常价格计,成本可能因为网络拥塞而增加)。 所以对于一层网络上 1 个燃料的成本,我们可能需要在二层网络上花费 10 万个燃料的处理费用。 假定我们不用重写存储,这意味着我们可以用一个一层网络燃料的价格将大约五个字写入二层网络的存储中。 对于单个默克尔证明,我们可以将全部 1024 个字写入存储(假定它们可以在链上计算出来,而不是在交易中提供),并且还剩下大部分燃料。 +以 [Optimism](https://public-grafana.optimism.io/d/9hkhMxn7z/public-dashboard?orgId=1&refresh=5m) 为例,写入 L1 的燃料成本约为 100 gwei,写入 L2 的燃料成本为 0.001 gwei(这是正常价格,拥堵时可能会上涨)。 所以对于一层网络上 1 个燃料的成本,我们可能需要在二层网络上花费 10 万个燃料的处理费用。 假定我们不用重写存储,这意味着我们可以用一个一层网络燃料的价格将大约五个字写入二层网络的存储中。 对于单个默克尔证明,我们可以将全部 1024 个字写入存储(假设它们一开始就可以在链上计算,而不是在交易中提供),并且仍然有大部分燃料剩余。 -## 总结 {#conclusion} +## 结论 {#conclusion} 在现实中,你可能永远不会独立实现默克尔树。 有很多广为人知并经过审核的程序库可供使用,一般来说,最好不要自己独立实现加密基元。 但我希望你们现在能够更好地理解默克尔证明,并能够决定何时值得使用。 -请注意,虽然默克尔证明能维持_完整性_,但并不维持_可用性_。 如果数据存储方决定禁止访问,而且你不能构建默克尔树来访问你的资产,那么知道没有人可以拿走你的资产也只能作为一种小小的慰藉而已。 所以默克尔树最好和某种去中心化存储一起使用,例如星际文件系统。 +请注意,虽然默克尔证明可以保持_完整性_,但不能保持_可用性_。 如果数据存储方决定禁止访问,而且你不能构建默克尔树来访问你的资产,那么知道没有人可以拿走你的资产也只能作为一种小小的慰藉而已。 所以默克尔树最好和某种去中心化存储一起使用,例如星际文件系统。 + +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 diff --git a/public/content/translations/zh/developers/tutorials/monitoring-geth-with-influxdb-and-grafana/index.md b/public/content/translations/zh/developers/tutorials/monitoring-geth-with-influxdb-and-grafana/index.md index 7585e1ca55a..64fc1748493 100644 --- a/public/content/translations/zh/developers/tutorials/monitoring-geth-with-influxdb-and-grafana/index.md +++ b/public/content/translations/zh/developers/tutorials/monitoring-geth-with-influxdb-and-grafana/index.md @@ -1,29 +1,27 @@ --- -title: 使用 InfluxDB 和 Grafana 监测 Geth -description: +title: "使用 InfluxDB 和 Grafana 监控 Geth" +description: "使用 InfluxDB 和 Grafana 为你的 Geth 节点设置监控,以跟踪性能并识别问题。" author: "Mario Havel" -tags: - - "客户端" - - "节点" +tags: [ "客户端", "节点" ] skill: intermediate lang: zh published: 2021-01-13 --- -本教程将帮助你设置 Geth 节点的监测方法,以便更好地了解其性能并发现潜在问题。 +本教程将帮助你为你的 Geth 节点设置监控,以便更好地了解其性能并发现潜在问题。 ## 前提条件 {#prerequisites} - 你应该已经运行一个 Geth 实例。 - 大部分步骤和示例都针对 linux 环境,基础的终端知识会有所帮助。 -- 请观看这段关于 Geth 指标集的概览视频:[监测以太坊基础设施(作者 Péter Szilágyi)](https://www.youtube.com/watch?v=cOBab8IJMYI) +- 请观看这段关于 Geth 指标集的概览视频:[监测以太坊基础设施(作者 Péter Szilágyi)](https://www.youtube.com/watch?v=cOBab8IJMYI)。 -## 监测堆栈 {#monitoring-stack} +## 监控堆栈 {#monitoring-stack} -以太坊客户端收集大量数据,可以通过时序数据库读取这些数据。 为了便于监测,你可以将数据输入数据可视化软件。 下面提供了多种选项供你选择: +以太坊客户端收集大量数据,可以通过时序数据库读取这些数据。 为了便于监控,你可以将数据输入数据可视化软件。 有多种可用选项: -- [Prometheus](https://prometheus.io/)(拉取模式) -- [InfluxDB](https://www.influxdata.com/get-influxdb/)(推送模式) +- [Prometheus](https://prometheus.io/)(拉取模型) +- [InfluxDB](https://www.influxdata.com/get-influxdb/)(推送模型) - [Telegraf](https://www.influxdata.com/get-influxdb/) - [Grafana](https://www.grafana.com/) - [Datadog](https://www.datadoghq.com/) @@ -35,7 +33,8 @@ published: 2021-01-13 ## 设置 InfluxDB {#setting-up-influxdb} -首先,下载并安装 InfluxDB。 [Influxdata 下载页面](https://portal.influxdata.com/downloads/)提供了多种下载选项。 选择适合你安装环境的下载选项。 你还可以通过[资源库](https://repos.influxdata.com/)安装它。 例如,在基于 Debian 的发行版中: +首先,我们来下载并安装 InfluxDB。 可以在 [Influxdata 发布页面](https://portal.influxdata.com/downloads/)找到各种下载选项。 选择适合你环境的版本。 +你也可以从[资源库](https://repos.influxdata.com/)安装。 例如,在基于 Debian 的发行版中: ``` curl -tlsv1.3 --proto =https -sL https://repos.influxdata.com/influxdb.key | sudo apt-key add @@ -48,26 +47,27 @@ sudo systemctl start influxdb sudo apt install influxdb-client ``` -在成功安装 InfluxDB 后,确保它在后台运行。 默认情况下,可以通过 `localhost:8086` 访问它。 在使用 `influx` 客户端前,你必须创建具有管理员权限的新用户。 该用户将进行高级管理,创建数据库和用户。 +成功安装 InfluxDB 后,请确保它正在后台运行。 默认情况下,可以通过 `localhost:8086` 访问它。 +在使用 `influx` 客户端之前,你必须创建一个拥有管理员权限的新用户。 此用户将用于高级别管理,例如创建数据库和用户。 ``` curl -XPOST "http://localhost:8086/query" --data-urlencode "q=CREATE USER username WITH PASSWORD 'password' WITH ALL PRIVILEGES" ``` -现在,你可以用此用户的身份通过 influx 客户端进入 [InfluxDB 命令行](https://docs.influxdata.com/influxdb/v1.8/tools/shell/)。 +现在你可以用此用户通过 influx 客户端进入 [InfluxDB 命令行](https://docs.influxdata.com/influxdb/v1.8/tools/shell/)。 ``` influx -username 'username' -password 'password' ``` -你可以通过其命令行直接与 InfluxDB 通信,为 geth 指标创建数据库和用户。 +在其命令行中与 InfluxDB 直接通信,你可以为 geth 指标创建数据库和用户。 ``` create database geth create user geth with password choosepassword ``` -如下验证已创建的条目: +使用以下命令验证创建的条目: ``` show databases @@ -80,19 +80,20 @@ show users exit ``` -InfluxDB 正在运作,将其配置为存储来自 Geth 的指标。 +InfluxDB 正在运行,并已配置为存储来自 Geth 的指标。 ## 准备 Geth {#preparing-geth} -设置好数据库后,我们需要在 Geth 中启用指标收集。 留意 `geth - help` 中的 `METRICS AND STATS OPTIONS`。 此处可以找到多个选项,在此例中,我们希望 Geth 将数据推送到 InfluxDB。 基本设置指定了端点,可以通过它访问 InfluxDB 并进行数据库身份验证。 +设置好数据库后,我们需要在 Geth 中启用指标收集功能。 请注意 `geth --help` 中的 `METRICS AND STATS OPTIONS`。 那里有多个选项,在本例中,我们希望 Geth 将数据推送到 InfluxDB。 +基本设置指定了 InfluxDB 的可访问端点以及数据库的身份验证信息。 ``` geth --metrics --metrics.influxdb --metrics.influxdb.endpoint "http://0.0.0.0:8086" --metrics.influxdb.username "geth" --metrics.influxdb.password "chosenpassword" ``` -此标记可以附加到启动客户端的命令或保存到配置文件中。 +这些标志可以附加到启动客户端的命令中,或保存到配置文件中。 -你可以通过在数据库中列出指标来验证 Geth 是否成功推送了数据。 在 InfluxDB 命令行中: +你可以通过在数据库中列出指标等方式,验证 Geth 是否正在成功推送数据。 在 InfluxDB 命令行中: ``` use geth @@ -101,7 +102,8 @@ show measurements ## 设置 Grafana {#setting-up-grafana} -下一步是安装 Grafana,后者通过图形解释数据。 按照 Grafana 文档中针对你安装环境的安装过程操作。 如果不想安装其他版本,确保安装 OSS 版本。 下面是通过资源库安装 发行版本的示例安装步骤: +下一步是安装 Grafana,它将以图形方式解译数据。 请遵照 Grafana 文档中适用于你的环境的安装流程进行操作。 若无其他特殊需求,请确保安装 OSS 版本。 +使用资源库为 Debian 发行版安装的示例步骤: ``` curl -tlsv1.3 --proto =https -sL https://packages.grafana.com/gpg.key | sudo apt-key add - @@ -112,36 +114,38 @@ sudo systemctl enable grafana-server sudo systemctl start grafana-server ``` -在 Grafana 开始运行后,应该能够在 `localhost:3000` 访问它。 使用你喜欢的浏览器访问此路径,然后用默认凭据登录(用户:`admin` 和密码:`admin`)。 当提示时,更改默认密码并保存。 +Grafana 运行后,应该可以通过 `localhost:3000` 访问。 +使用你偏好的浏览器访问此路径,然后使用默认凭据(用户:`admin`,密码:`admin`)登录。 出现提示时,请更改默认密码并保存。 ![](./grafana1.png) -你将被重定向到 Grafana 主页。 首先,设置你的源数据。 点击左边栏中的配置图标并选择“Data sources”。 +你将被重定向到 Grafana 主页。 首先,设置你的数据源。 点击左侧栏的配置图标,然后选择“Data sources”。 ![](./grafana2.png) -现在尚未创建任何数据源,点击“Add data source”定义一个数据源。 +目前还没有创建任何数据源,点击“添加数据源”来定义一个。 ![](./grafana3.png) -在本次设置中,请选择“InfluxDB”并继续操作。 +对于此设置,选择“InfluxDB”并继续。 ![](./grafana4.png) -如果你在同台一机器上运行工具,数据源配置就相当简单。 你需要设置 InfluxDB 地址和详细信息,以便访问数据库。 请参考下图。 +如果你在同一台机器上运行这些工具,数据源配置会非常简单。 你需要设置 InfluxDB 地址和用于访问数据库的详细信息。 请参考下图。 ![](./grafana5.png) -如果所有操作都已完成并且 InfluxDB 可以访问,请点击“Save and test”,等待确认信息弹出。 +如果一切都已完成且 InfluxDB 可访问,请点击“保存并测试”,然后等待确认信息弹出。 ![](./grafana6.png) -现在 Grafana 设置为读取 InfluxDB 中的数据。 此时,你需要创建一个解释和显示数据的仪表板。 仪表板属性是在 JSON 文件中编码的,可让任何人创建并轻松导入。 在左侧栏上,点击“Create and Import”。 +Grafana 现已设置为从 InfluxDB 读取数据。 现在,你需要创建一个仪表板来解译和显示数据。 仪表板属性在 JSON 文件中编码,任何人都可以创建并轻松导入。 在左侧栏上,点击“创建和导入”。 ![](./grafana7.png) -要创建 Geth 监测仪表板,复制[此仪表板](https://grafana.com/grafana/dashboards/13877/)的 ID 并粘贴到 Grafana 的“导入页面”中。 保存仪表板后,其外观应该如下所示: +对于 Geth 监控仪表板,请复制[此仪表板](https://grafana.com/grafana/dashboards/13877/)的 ID,并将其粘贴到 Grafana 的“导入页面”中。 保存仪表板后,它应如下所示: ![](./grafana8.png) -你可以修改你的仪表板。 每个面板都可以编辑、移动、删除或添加。 你可以更改你的配置。 一切由你决定! 要了解有关仪表板工作原理的更多信息,请参阅 [Grafana 文档](https://grafana.com/docs/grafana/latest/dashboards/)。 你也可能对[警报](https://grafana.com/docs/grafana/latest/alerting/)感兴趣。 这可以让你设置在指标达到特定值时的提醒通知。 支持各种交流渠道。 +你可以修改你的仪表板。 每个面板都可以编辑、移动、移除或添加。 你可以更改你的配置。 一切由你决定! 要详细了解仪表板的工作原理,请参阅 [Grafana 的文档](https://grafana.com/docs/grafana/latest/dashboards/)。 +你可能还对[警报](https://grafana.com/docs/grafana/latest/alerting/)感兴趣。 这使你可以设置当指标达到特定值时的警报通知。 支持多种通信渠道。 diff --git a/public/content/translations/zh/developers/tutorials/nft-minter/index.md b/public/content/translations/zh/developers/tutorials/nft-minter/index.md index 19b68ed3c1b..74116a10787 100644 --- a/public/content/translations/zh/developers/tutorials/nft-minter/index.md +++ b/public/content/translations/zh/developers/tutorials/nft-minter/index.md @@ -1,17 +1,16 @@ --- -title: 非同质化代币铸币机教程 -description: 在本教程中,你将构建一个非同质化代币铸币机,并学习如何通过使用 MetaMask 和 Web3 工具将智能合约连接到 React 前端来创建全栈去中心化应用程序。 +title: "非同质化代币铸币机教程" +description: "在本教程中,你将构建一个非同质化代币铸币机,并学习如何通过使用 MetaMask 和 Web3 工具将智能合约连接到 React 前端来创建全栈去中心化应用程序。" author: "smudgil" tags: - - "solidity" - - "非同质化代币" - - "铸币机" - - "Alchemy" - - "智能合约" - - "前端" - - "用户界面" - - "钱包" - - "Pinata" + [ + "Solidity", + "非同质化代币", + "Alchemy", + "智能合同", + "前端", + "Pinata" + ] skill: intermediate lang: zh published: 2021-10-06 @@ -19,88 +18,88 @@ published: 2021-10-06 对于具有 Web2 背景的开发者来说,最大的挑战之一是弄清楚如何将智能合约连接到前端项目并与之交互。 -通过构建非同质化代币铸币机 — 一个可以用来输入数字资产链接、名称与描述的简单用户界面 — 您将学会如何: +通过构建非同质化代币铸币机 — 一个可以用来输入数字资产链接、名称与描述的简单用户界面 — 你将学会如何: -- 通过您的前端项目连接到 MetaMask +- 通过你的前端项目连接到 MetaMask - 在前端调用智能合约的方法 - 使用 MetaMask 签署交易 -在本教程中,我们将使用 [React](https://reactjs.org/) 作为前端框架。 由于本教程主要侧重于 Web3 开发,我们不会花太多时间来细讲 React 基础知识。 相反,我们将专注于为项目添加功能。 +在本教程中,我们将使用 [React](https://react.dev/) 作为我们的前端框架。 由于本教程主要侧重于 Web3 开发,我们不会花太多时间来细讲 React 基础知识。 相反,我们将专注于为项目添加功能。 -作为先决条件,您应该对 React 有入门水平的认识 — 了解组件、属性、useState/useEffect 和基本函数调用是如何工作的。 如果您以前从未听过这些术语,您可能想参阅这个 [React 入门教程](https://reactjs.org/tutorial/tutorial.html)。 对于视觉型学习者,我们强烈推荐 Net Ninja 推出的[现代 React 开发完整教程](https://www.youtube.com/playlist?list=PL4cUxeGkcC9gZD-Tvwfod2gaISzfRiP9d)精彩视频系列。 +作为先决条件,你应该对 React 有入门水平的认识 — 了解组件、属性、useState/useEffect 和基本函数调用是如何工作的。 如果你以前从未听说过这些术语,不妨看看这篇 [React 入门教程](https://react.dev/learn/tutorial-tic-tac-toe)。 对于视觉型学习者,我们强烈推荐 Net Ninja 推出的这个优秀的[现代 React 完整教程](https://www.youtube.com/playlist?list=PL4cUxeGkcC9gZD-Tvwfod2gaISzfRiP9d)视频系列。 -如果您还没有 Alchemy 帐户,您肯定需要一个来完成本教程以及在区块链上完成任何构建。 点击[此处](https://alchemy.com/)注册一个免费帐户。 +如果你还没有 Alchemy 帐户,你肯定需要一个来完成本教程以及在区块链上完成任何构建。 请[在此](https://alchemy.com/)注册一个免费帐户。 事不宜迟,让我们开始吧! -## 制作非同质化代币 101 {#making-nfts-101} +## NFT 制作入门 {#making-nfts-101} 在我们开始考虑任何代码之前,了解非同质化代币的工作原理非常重要。 它包括两个步骤: -### 在以太坊区块链上发布非同质化代币智能合约 {#publish-nft} +### 在以太坊区块链上发布 NFT 智能合约 {#publish-nft} 两种非同质化代币智能合约标准的最大区别在于,ERC-1155 是多代币标准且包含批量功能,而 ERC-721 是单代币标准,因此仅支持一次转账一个代币。 ### 调用铸币函数 {#minting-function} -通常,此铸币函数需要您传入两个变量作为参数,第一个是 `recipient`,它指定将要接收您的新铸造非同质化代币的地址,第二个是非同质化代币的 `tokenURI`,它是一个字符串,解析为描述非同质化代币元数据的 JSON 文档。 +通常,这个铸币函数需要你传入两个变量作为参数:第一个是 `recipient`,它指定将接收你新铸造的 NFT 的地址;第二个是 NFT 的 `tokenURI`,它是一个字符串,可解析为描述此 NFT 元数据的 JSON 文档。 -非同质化代币的元数据是其核心所在,使它拥有多种属性,例如名称、描述、图像(或不同的数字资产)及其他特性。 这是 [tokenURI 示例](https://gateway.pinata.cloud/ipfs/QmSvBcb4tjdFpajGJhbFAWeK3JAxCdNQLQtr6ZdiSi42V2),其中包含非同质化代币的元数据。 +非同质化代币的元数据是其核心所在,使它拥有多种属性,例如名称、描述、图像(或不同的数字资产)及其他特性。 这是一个 `tokenURI` 的[示例](https://gateway.pinata.cloud/ipfs/QmSvBcb4tjdFpajGJhbFAWeK3JAxCdNQLQtr6ZdiSi42V2),其中包含某个 NFT 的元数据。 在本教程中,我们将重点关注第 2 部分,使用我们的 React UI 调用现有的非同质化代币智能合约铸币函数。 -在本教程中,我们将要调用的 ERC-721 非同质化代币智能合约的[链接在此处](https://ropsten.etherscan.io/address/0x4C4a07F737Bf57F6632B6CAB089B78f62385aCaE)。 如果您想了解我们如何创建该合约,强烈建议您参阅我们另一个教程[“如何创建非同质化代币”](https://docs.alchemyapi.io/alchemy/tutorials/how-to-create-an-nft)。 +本教程中我们将调用的 ERC-721 NFT 智能合约的[链接在此](https://ropsten.etherscan.io/address/0x4C4a07F737Bf57F6632B6CAB089B78f62385aCaE)。 如果你想了解我们是如何制作它的,我们强烈建议你查看我们的另一篇教程:[“如何创建 NFT”](https://www.alchemy.com/docs/how-to-create-an-nft)。 太好了,现在我们已经了解了非同质化代币的工作原理,我们来克隆我们的启动文件! ## 克隆启动文件 {#clone-the-starter-files} -首先,浏览到 [nft-minter-tutorial GitHub 资源库](https://github.com/alchemyplatform/nft-minter-tutorial),获取此项目的启动文件。 将此资源库克隆到您的本地环境中。 +首先,访问 [nft-minter-tutorial GitHub 仓库](https://github.com/alchemyplatform/nft-minter-tutorial)以获取本项目的启动文件。 将此仓库克隆到你的本地环境中。 -打开这个克隆的 `nft-minter-tutorial` 资源库后,您会注意到它包含两个文件夹:`minter-starter-files` 和 `nft-minter`。 +打开这个克隆的 `nft-minter-tutorial` 仓库后,你会发现它包含两个文件夹:`minter-starter-files` 和 `nft-minter`。 -- `minter-starter-files` 包含此项目的启动文件(基本上是 React UI)。 在本教程中,**我们将在此目录中操作**,您将学习如何通过将其连接到您的以太坊钱包和非同质化代币智能合约来实现此用户界面。 -- `nft-minter` 包含已完成的完整教程,**如果您遇到困难**,可以作为**参考**。 +- `minter-starter-files` 包含此项目的启动文件(主要是 React UI)。 在本教程中,**我们将在该目录中工作**,你将学习如何通过将其连接到你的以太坊钱包和 NFT 智能合约来激活此 UI。 +- `nft-minter` 包含完整的教程,**如果你遇到困难**,可以作为**参考**。 -接下来,在代码编辑器中打开 `minter-starter-files` 副本,然后浏览到 `src` 文件夹。 +接下来,在你的代码编辑器中打开 `minter-starter-files` 的副本,然后导航到 `src` 文件夹。 -我们编写的所有代码都将保存在 `src` 文件夹下。 我们将编辑 `Minter.js` 组件并编写额外的 javascript 文件来为我们的项目提供 Web3 功能。 +我们将编写的所有代码都将存放在 `src` 文件夹下。 我们将编辑 `Minter.js` 组件并编写额外的 javascript 文件,为我们的项目提供 Web3 功能。 ## 第 2 步:查看我们的启动文件 {#step-2-check-out-our-starter-files} 在我们开始编码之前,必须检查起始文件中已经为我们提供了什么。 -### 让您的 react 项目运行起来 {#get-your-react-project-running} +### 运行你的 React 项目 {#get-your-react-project-running} 首先在浏览器中运行 React 项目。 React 的美妙之处在于,一旦我们的项目在浏览器中运行,保存的任何更改都会在浏览器中实时更新。 -要让项目运行,浏览到 `minter-starter-files` 文件夹的根目录,然后在终端运行 `npm install` 以安装项目的依赖项: +要运行项目,请导航到 `minter-starter-files` 文件夹的根目录,然后在终端中运行 `npm install` 来安装项目的依赖项: ```bash cd minter-starter-files npm install ``` -依赖项安装完成后,在终端运行 `npm start`: +安装完成后,在终端中运行 `npm start`: ```bash npm start ``` -运行后,http://localhost:3000/ 应该在浏览器中打开,您可以在其中看到项目前端。 其中应该包括 3 个字段:一个用于输入非同质化代币资产的链接、一个用于输入非同质化代币的名称,一个提供描述。 +运行后,http://localhost:3000/ 应该在浏览器中打开,你可以在其中看到项目前端。 其中应该包括 3 个字段:一个用于输入非同质化代币资产的链接、一个用于输入非同质化代币的名称,一个提供描述。 -如果您尝试点击“Connect Wallet”或“Mint NFT”按钮,您会发现它们不起作用 — 那是因为我们仍然需要对它们的功能进行编程! :\) +如果你尝试点击“Connect Wallet”或“Mint NFT”按钮,你会发现它们不起作用 — 那是因为我们仍然需要对它们的功能进行编程! :\) -### Minter.js 组件 {#minter-js} +### `Minter.js` 组件 {#minter-js} -**注:**确保您位于 `minter-starter-files` 文件夹而不是 `nft-minter` 文件夹! +\*\*注意:\*\*请确保你位于 `minter-starter-files` 文件夹,而不是 `nft-minter` 文件夹! -我们在编辑器中返回 `src` 文件夹并打开 `Minter.js` 文件。 理解该文件中的所有内容非常重要,因为它是我们将要处理的主要 React 组件。 +让我们在编辑器中返回 `src` 文件夹,并打开 `Minter.js` 文件。 理解该文件中的所有内容非常重要,因为它是我们将要处理的主要 React 组件。 在该文件的顶部,有我们将在特定事件后更新的状态变量。 ```javascript -//State variables +//状态变量 const [walletAddress, setWallet] = useState("") const [status, setStatus] = useState("") const [name, setName] = useState("") @@ -108,135 +107,135 @@ const [description, setDescription] = useState("") const [url, setURL] = useState("") ``` -从未听过 React 状态变量或状态挂钩? 参阅[这些](https://reactjs.org/docs/hooks-state.html)文档。 +从未听过 React 状态变量或状态挂钩? 查看[这些](https://legacy.reactjs.org/docs/hooks-state.html)文档。 以下是每个变量的含义: -- `walletAddress` — 存储用户钱包地址的字符串 -- `status` — 包含要在用户界面底部显示的消息的字符串 -- `name` — 存储非同质化代币名称的字符串 -- `description` — 存储非同质化代币描述的字符串 -- `url` — 字符串,表示指向非同质化代币数字资产的链接 +- `walletAddress` - 存储用户钱包地址的字符串 +- `status` - 包含要显示在 UI 底部的消息的字符串 +- `name` - 存储 NFT 名称的字符串 +- `description` - 存储 NFT 描述的字符串 +- `url` - 指向 NFT 数字资产链接的字符串 -在状态变量之后,您会看到三个未实现的函数:`useEffect`、`connectWalletPressed` 和 `onMintPressed`。 您会注意到所有这些函数都是 `async` 函数,这是因为我们将在其中进行异步 API 调用! 它们的名称与功能同名: +在状态变量之后,你会看到三个未实现的函数:`useEffect`、`connectWalletPressed` 和 `onMintPressed`。 你会注意到所有这些函数都是 `async` 的,这是因为我们将在其中进行异步 API 调用! 它们的名称与功能同名: ```javascript useEffect(async () => { - //TODO: implement + //待办:实现 }, []) const connectWalletPressed = async () => { - //TODO: implement + //待办:实现 } const onMintPressed = async () => { - //TODO: implement + //待办:实现 } ``` -- [`useEffect`](https://reactjs.org/docs/hooks-effect.html) — 这是一个 React 挂钩,在渲染组件后调用。 因为向它传入了一个空的数组 `[]` 属性(见第 3 行),只会在组件的*第一次*渲染时调用它。 在这里,我们将调用钱包监听器和另一个钱包函数,来更新我们的用户界面以指示钱包是否已经连接。 -- `connectWalletPressed` - 将调用此函数,将用户的 MetaMask 钱包连接到我们的去中心化应用程序。 -- `onMintPressed` — 将调用此函数来铸造用户的非同质化代币。 +- [`useEffect`](https://legacy.reactjs.org/docs/hooks-effect.html) - 这是一个 React 钩子,在组件渲染后调用。 因为它传入了一个空数组 `[]` 属性(见第 3 行),所以它只会在组件_首次_渲染时被调用。 在这里,我们将调用钱包监听器和另一个钱包函数,来更新我们的用户界面以指示钱包是否已经连接。 +- `connectWalletPressed` - 此函数将被调用,以将用户的 MetaMask 钱包连接到我们的去中心化应用程序。 +- `onMintPressed` - 此函数将被调用,以铸币用户的 NFT。 -在接近该文件末尾处,我们获得我们组件的用户界面。 如果您仔细查看此代码,您会注意到,当相应文本字段的输入发生变化时,我们更新了 `url`、`name` 和 `description` 状态变量。 +在接近该文件末尾处,我们获得我们组件的用户界面。 如果你仔细查看此代码,你会注意到当相应文本字段中的输入发生变化时,我们会更新 `url`、`name` 和 `description` 状态变量。 -您还将看到,在分别单击 ID 为 `mintButton` 和 `walletButton` 的按钮时,会调用 `connectWalletPressed` 和 `onMintPressed`。 +你还会看到,当分别点击 ID 为 `mintButton` 和 `walletButton` 的按钮时,会调用 `connectWalletPressed` 和 `onMintPressed`。 ```javascript -//the UI of our component +//我们组件的 UI return (


-

🧙‍♂️ Alchemy NFT Minter

+

🧙‍♂️ Alchemy NFT 铸币器

- Simply add your asset's link, name, and description, then press "Mint." + 只需添加你的资产链接、名称和描述,然后按“铸币”。

-

🖼 Link to asset:

+

🖼 资产链接:

setURL(event.target.value)} /> -

🤔 Name:

+

🤔 名称:

setName(event.target.value)} /> -

✍️ Description:

+

✍️ 描述:

setDescription(event.target.value)} />

{status}

-
+ ) ``` 最后,我们来看看这个铸币机组件是在哪里添加的。 -如果您打开 `App.js` 文件,将会看到我们的铸币机组件是在第 7 行添加的。此文件是 React 中的主要组件,作为所有其他组件的容器。 +如果你转到 `App.js` 文件(它是 React 中的主组件,充当所有其他组件的容器),你会看到我们的 Minter 组件在第 7 行被注入。 -**在本教程中,我们将只编辑 `Minter.js file` 并在我们的 `src` 文件夹中添加文件。** +**在本教程中,我们将只编辑 `Minter.js file` 文件,并在我们的 `src` 文件夹中添加文件。** 我们已经了解了我们正在进行的操作,现在我们来设置我们的以太坊钱包! -## 设置您的以太坊钱包 {#set-up-your-ethereum-wallet} +## 设置你的以太坊钱包 {#set-up-your-ethereum-wallet} 为了让用户能够与你的智能合约交互,他们需要将其以太坊钱包连接到你的去中心化应用程序。 ### 下载 MetaMask {#download-metamask} -在本教程中,我们将使用 MetaMask,它是浏览器中的虚拟钱包,用来管理您的以太坊账户地址。 如果您想了解更多关于以太坊交易如何运作的信息,请参阅[此页面](/developers/docs/transactions/)。 +在本教程中,我们将使用 MetaMask,它是浏览器中的虚拟钱包,用来管理你的以太坊帐户地址。 如果你想进一步了解以太坊上的交易如何运作,请查看[此页面](/developers/docs/transactions/)。 -您可以点击[此处](https://metamask.io/download)免费下载并创建一个 MetaMask 账户。 在创建账户时,或者如果您已经有一个账户,确保切换到右上角的“Ropsten 测试网络”\(这样我们就不会交易真正的钱币\)。 +你可以[在此处](https://metamask.io/download)免费下载和创建 MetaMask 帐户。 在创建帐户时,或者如果你已经有一个帐户,确保切换到右上角的“Ropsten 测试网络”\(这样我们就不会交易真正的钱币\)。 -### 通过水龙头中添加以太币 {#add-ether-from-faucet} +### 从水龙头获取以太币 {#add-ether-from-faucet} -为了铸造我们的非同质化代币(或在以太坊区块链上签署任何交易),我们需要一些虚拟以太币。 要获取以太币,您可以转到 [Ropsten 水龙头](https://faucet.ropsten.be/)并输入您的 Ropsten 帐户地址,然后点击“Send Ropsten Eth”。 您应该会很快在您的 MetaMask 帐户中看到以太币! +为了铸造我们的非同质化代币(或在以太坊区块链上签署任何交易),我们需要一些虚拟以太币。 要获取 Eth,你可以前往 [Ropsten 水龙头](https://faucet.ropsten.be/) 并输入你的 Ropsten 帐户地址,然后点击“Send Ropsten Eth”。 你应该会很快在你的 MetaMask 帐户中看到以太币! -### 检查您的余额 {#check-your-balance} +### 检查你的余额 {#check-your-balance} -为了核查我们账户中有余额,我们使用 [Alchemy composer 工具](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D)发出 [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) 请求。 这将返回我们钱包中的以太币数量。 输入您的 MetaMask 帐户地址并点击“Send Request”后,您应该会看到这样的响应: +为了仔细检查我们的余额,让我们使用 [Alchemy 的 composer 工具](https://composer.alchemyapi.io/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D) 发出一个 [eth_getBalance](https://docs.alchemyapi.io/alchemy/documentation/alchemy-api-reference/json-rpc#eth_getbalance) 请求。 这将返回我们钱包中的以太币数量。 输入你的 MetaMask 帐户地址并点击“Send Request”后,你应该会看到这样的响应: ```text {"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"} ``` -**注意:**结果以 wei 为单位,而非 ETH。 Wei 是以太币的最小计量单位。 从 wei 到 eth 的转换是:1 eth = 10¹⁸ wei。 因此,如果我们将 0xde0b6b3a7640000 转换为十进制,我们会得到 1\*10¹⁸,它等于 1 eth。 +\*\*注意:\*\*此结果以 wei 为单位,而不是 eth。 Wei 是以太币的最小计量单位。 从 wei 到 eth 的转换是:1 eth = 10¹⁸ wei。 因此,如果我们将 0xde0b6b3a7640000 转换为十进制,我们会得到 1\*10¹⁸,它等于 1 eth。 哦! 我们的虚拟以太币都在那里了! -## 将 MetaMask 连接到您的用户界面 {#connect-metamask-to-your-UI} +## 将 MetaMask 连接到你的 UI {#connect-metamask-to-your-UI} 既然我们的 MetaMask 钱包已经设置好了,我们将我们的去中心化应用程序与之连接! -因为我们建议采用 [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) 规范,所以我们要创建一个单独的文件,其中包含用来管理我们的去中心化应用程序的逻辑、数据和规则的函数,然后将这些函数传递给我们的前端(Minter.js 组件)。 +因为我们想要遵循 [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) 范式,所以我们将创建一个单独的文件,其中包含用于管理我们去中心化应用程序的逻辑、数据和规则的函数,然后将这些函数传递到我们的前端(我们的 Minter.js 组件)。 ### `connectWallet` 函数 {#connect-wallet-function} -为此,我们在 `src` 目录中创建一个名为 `utils` 的新文件夹,并在其中添加一个名为 `interact.js` 的文件,其中将包含我们所有的钱包和智能合约交互函数。 +为此,让我们在 `src` 目录中创建一个名为 `utils` 的新文件夹,并在其中添加一个名为 `interact.js` 的文件,该文件将包含我们所有的钱包和智能合约交互函数。 -在我们的 `interact.js` 文件中,我们将编写一个 `connectWallet` 函数,然后我们将在 `Minter.js` 组件中导入并调用该函数。 +在我们的 `interact.js` 文件中,我们将编写一个 `connectWallet` 函数,然后我们将在 `Minter.js` 组件中导入并调用它。 -在您的 `interact.js` 文件中,添加以下内容 +在你的 `interact.js` 文件中,添加以下内容 ```javascript export const connectWallet = async () => { @@ -246,7 +245,7 @@ export const connectWallet = async () => { method: "eth_requestAccounts", }) const obj = { - status: "👆🏽 Write a message in the text-field above.", + status: "👆🏽 请在上面的文本字段中写入一条消息。", address: addressArray[0], } return obj @@ -264,8 +263,7 @@ export const connectWallet = async () => {

{" "} 🦊 - You must install MetaMask, a virtual Ethereum wallet, in your - browser. + 你必须在浏览器中安装 MetaMask(一个虚拟的以太坊钱包)。

@@ -277,26 +275,26 @@ export const connectWallet = async () => { 我们详细讲解一下这段代码的作用: -首先,我们的函数会检查您的浏览器是否启用了 `window.ethereum`。 +首先,我们的函数会检查 `window.ethereum` 是否在你的浏览器中启用。 -`window.ethereum` 是一个由 MetaMask 和其他钱包提供商注入的全局应用程序接口,它允许网站请求用户的以太坊账户。 如果获得批准,它可以从用户连接的区块链中读取数据,并建议用户签署消息和交易。 参阅 [MetaMask 文档](https://docs.metamask.io/guide/ethereum-provider.html#table-of-contents)了解更多信息! +`window.ethereum` 是由 MetaMask 和其他钱包提供商注入的全局 API,允许网站请求用户的以太坊帐户。 如果获得批准,它可以从用户连接的区块链中读取数据,并建议用户签署消息和交易。 有关详细信息,请查看 [MetaMask 文档](https://docs.metamask.io/guide/ethereum-provider.html#table-of-contents)! -如果 `window.ethereum` _ 不存在_,则表示未安装 MetaMask。 这会导致返回一个 JSON 对象,其中返回的 `address` 是一个空字符串,而 `status` JSX 对象指示用户必须安装 MetaMask。 +如果 `window.ethereum` _不_存在,则意味着 MetaMask 未安装。 这将导致返回一个 JSON 对象,其中返回的 `address` 是一个空字符串,而 `status` JSX 对象则会提示用户必须安装 MetaMask。 -**我们编写的大多数函数都将返回 JSON 对象,我们可以使用这些对象更新我们的状态变量和用户界面。** +**我们编写的大多数函数都将返回 JSON 对象,我们可以用它们来更新我们的状态变量和 UI。** -现在如果 `window.ethereum` _存在_,那么事情就会变得有趣。 +现在,如果 `window.ethereum` _是_存在的,事情就变得有趣了。 -使用 try/catch 循环,我们将尝试通过调用 `[window.ethereum.request({ method: "eth_requestAccounts" });](https://docs.metamask.io/guide/rpc-api.html#eth-requestaccounts)` 连接到 MetaMask。 调用此函数将在浏览器中打开 MetaMask,提示用户将他们的钱包连接到你的去中心化应用程序。 +使用 try/catch 循环,我们将通过调用 [`window.ethereum.request({ method: \"eth_requestAccounts\" });`](https://docs.metamask.io/guide/rpc-api.html#eth-requestaccounts) 来尝试连接到 MetaMask。 调用此函数将在浏览器中打开 MetaMask,提示用户将他们的钱包连接到你的去中心化应用程序。 -- 如果用户选择连接,`method: "eth_requestAccounts"` 将返回一个数组,其中包含连接到去中心化应用程序的用户的所有帐户地址。 总之,我们的 `connectWallet` 函数将返回一个 JSON 对象,其中包含此数组中的*第一个 * `address` \(见第 9 行\),并返回一条 `status` 信息,提示用户向智能合约写入信息。 -- 如果用户拒绝连接,则 JSON 对象将包含返回的 `address` 的空字符串和反映用户拒绝连接的 `status` 信息。 +- 如果用户选择连接,`method: \"eth_requestAccounts\"` 将返回一个数组,其中包含连接到该去中心化应用程序的所有用户帐户地址。 总而言之,我们的 `connectWallet` 函数将返回一个 JSON 对象,其中包含此数组中的_第一个_ `address`(见第 9 行)和一条提示用户向智能合约写入消息的 `status` 消息。 +- 如果用户拒绝连接,则 JSON 对象将包含一个空字符串作为返回的 `address`,以及一条反映用户拒绝连接的 `status` 消息。 -### 将 connectWallet 函数添加到您的 Minter.js 用户界面组件 {#add-connect-wallet} +### 将 `connectWallet` 函数添加到你的 Minter.js UI 组件 {#add-connect-wallet} -我们已经编写了 `connectWallet` 函数,现在我们将它连接到我们的 `Minter.js.` 组件。 +既然我们已经编写了 `connectWallet` 函数,现在就把它连接到我们的 `Minter.js` 组件。 -首先,我们必须通过将 `import { connectWallet } from "./utils/interact.js";` 添加到 `Minter.js` 文件顶部,将我们的函数导入 `Minter.js` 文件。 `Minter.js` 的前 11 行现在应该如下所示: +首先,我们必须通过在 `Minter.js` 文件顶部添加 `import { connectWallet } from \"./utils/interact.js\";`,将我们的函数导入到 `Minter.js` 文件中。 现在,`Minter.js` 的前 11 行应该如下所示: ```javascript import { useEffect, useState } from "react"; @@ -304,7 +302,7 @@ import { connectWallet } from "./utils/interact.js"; const Minter = (props) => { - //State variables + //状态变量 const [walletAddress, setWallet] = useState(""); const [status, setStatus] = useState(""); const [name, setName] = useState(""); @@ -312,7 +310,7 @@ const Minter = (props) => { const [url, setURL] = useState(""); ``` -然后,在我们的 `connectWalletPressed` 函数中,我们将调用导入的 `connectWallet` 函数,如下所示: +然后,在 `connectWalletPressed` 函数中,我们将调用导入的 `connectWallet` 函数,如下所示: ```javascript const connectWalletPressed = async () => { @@ -322,25 +320,25 @@ const connectWalletPressed = async () => { } ``` -请注意我们的大部分功能是如何从 `interact.js` 文件中的 `Minter.js` 组件中抽取出来的? 这就是我们遵守 M-V-C 规范的原因! +请注意我们的大部分功能是如何从 `interact.js` 文件中抽象出来,并与 `Minter.js` 组件分离的? 这就是我们遵守 M-V-C 规范的原因! -在 `connectWalletPressed` 中,我们只需对导入的 `connectWallet` 函数进行 await 调用,并使用其响应,通过变量的状态挂钩更新我们的 `status` 和 `walletAddress ` 变量。 +在 `connectWalletPressed` 中,我们只需对导入的 `connectWallet` 函数进行 `await` 调用,并使用其响应通过它们的状态钩子来更新 `status` 和 `walletAddress` 变量。 -现在,我们保存 `Minter.js` 和 `interact.js` 这两个文件并测试我们目前为止获得的用户界面。 +现在,让我们保存 `Minter.js` 和 `interact.js` 这两个文件,并测试一下我们目前的 UI。 在 localhost:3000 地址打开浏览器,然后按页面右上角的“连接钱包”按钮。 如果你安装了 MetaMask,系统会提示你将钱包连接到去中心化应用程序。 接受邀请并连接。 -您应该会看到钱包按钮现在显示您的地址已连接。 +你应该会看到钱包按钮现在显示你的地址已连接。 -接下来,尝试刷新页面......有点儿奇怪。 我们的钱包按钮提示我们连接 MetaMask,尽管它已经连接...... +接下来,尝试刷新页面…… 这很奇怪。 我们的钱包按钮提示我们连接 MetaMask,尽管它已经连接...... -不过不用担心! 我们可以通过实现一个名为 `getCurrentWalletConnected` 的函数轻松解决这个问题,该函数将检查地址是否已连接到我们的去中心化应用程序并相应地更新我们的用户界面! +不过不用担心! 我们可以通过实现一个名为 `getCurrentWalletConnected` 的函数来轻松解决这个问题,该函数将检查一个地址是否已连接到我们的去中心化应用程序,并相应地更新我们的 UI! -### getCurrentWalletConnected 函数 {#get-current-wallet} +### `getCurrentWalletConnected` 函数 {#get-current-wallet} -在您的 `interact.js` 文件中,添加以下 `getCurrentWalletConnected` 函数: +在你的 `interact.js` 文件中,添加以下 `getCurrentWalletConnected` 函数: ```javascript export const getCurrentWalletConnected = async () => { @@ -352,12 +350,12 @@ export const getCurrentWalletConnected = async () => { if (addressArray.length > 0) { return { address: addressArray[0], - status: "👆🏽 Write a message in the text-field above.", + status: "👆🏽 请在上面的文本字段中写入一条消息。", } } else { return { address: "", - status: "🦊 Connect to MetaMask using the top right button.", + status: "🦊 使用右上角的按钮连接到 MetaMask。", } } } catch (err) { @@ -374,8 +372,7 @@ export const getCurrentWalletConnected = async () => {

{" "} 🦊 - You must install MetaMask, a virtual Ethereum wallet, in your - browser. + 你必须在浏览器中安装 MetaMask(一个虚拟的以太坊钱包)。

@@ -385,9 +382,9 @@ export const getCurrentWalletConnected = async () => { } ``` -这段代码*非常*类似于我们之前写的 `connectWallet` 函数。 +此代码与我们刚才编写的 `connectWallet` 函数_非常_相似。 -主要区别在于,这里我们调用了 `eth_accounts` 方法,它只是返回一个数组,其中包含当前连接到我们的去中心化应用程序的 MetaMask 地址,而不是调用 `eth_requestAccounts` 方法来打开 MetaMask 以供用户连接他们的钱包。 +主要区别在于,我们这里调用的方法是 `eth_accounts`,它只是返回一个包含当前连接到我们去中心化应用程序的 MetaMask 地址的数组,而不是调用会打开 MetaMask 供用户连接钱包的 `eth_requestAccounts` 方法。 要查看这个函数的实际作用,我们在 `Minter.js` 组件的 `useEffect` 函数中调用它。 @@ -397,7 +394,7 @@ export const getCurrentWalletConnected = async () => { import { useEffect, useState } from "react" import { connectWallet, - getCurrentWalletConnected, //import here + getCurrentWalletConnected, //在此导入 } from "./utils/interact.js" ``` @@ -413,13 +410,13 @@ useEffect(async () => { 请注意,我们使用调用 `getCurrentWalletConnected` 的响应来更新我们的 `walletAddress` 和 `status` 状态变量。 -添加这段代码后,请尝试刷新我们的浏览器窗口。 按钮应显示您已连接,并显示已连接钱包地址的预览 — 即使在您刷新后也是如此! +添加这段代码后,请尝试刷新我们的浏览器窗口。 按钮应显示你已连接,并显示已连接钱包地址的预览 — 即使在你刷新后也是如此! ### 实现 addWalletListener {#implement-add-wallet-listener} 我们的去中心化应用程序钱包设置的最后一步是实现钱包监听器,以便我们的用户界面在钱包状态发生变化时更新,例如当用户断开或切换帐户时。 -在您的 `Minter.js` 文件中,添加如下所示的函数 `addWalletListener`: +在你的 `Minter.js` 文件中,添加如下所示的函数 `addWalletListener`: ```javascript function addWalletListener() { @@ -427,10 +424,10 @@ function addWalletListener() { window.ethereum.on("accountsChanged", (accounts) => { if (accounts.length > 0) { setWallet(accounts[0]) - setStatus("👆🏽 Write a message in the text-field above.") + setStatus("👆🏽 请在上面的文本字段中写入一条消息。") } else { setWallet("") - setStatus("🦊 Connect to MetaMask using the top right button.") + setStatus("🦊 使用右上角的按钮连接到 MetaMask。") } }) } else { @@ -438,7 +435,7 @@ function addWalletListener() {

{" "} 🦊 - You must install MetaMask, a virtual Ethereum wallet, in your browser. + 你必须在浏览器中安装 MetaMask(一个虚拟的以太坊钱包)。

) @@ -448,9 +445,9 @@ function addWalletListener() { 我们快速分板一下这段代码的运行情况: -- 首先,我们的函数检查是否启用了 `window.ethereum` \(即 MetaMask 已安装\)。 +- 首先,我们的函数会检查 `window.ethereum` 是否已启用(即 MetaMask 是否已安装)。 - 如果未启用,我们只需将 `status` 状态变量设置为提示用户安装 MetaMask 的 JSX 字符串。 - - 如果启用,我们会在第 3 行设置监听器 `window.ethereum.on("accountsChanged")` 监听 MetaMask 钱包中的状态变化,变化包括用户将其他帐户连接到去中心化应用程序、切换帐户或断开帐户。 如果至少连接了一个账户,`walletAddress` 状态变量将更新为监听器返回的 `accounts` 数组中的第一个账户。 否则,`walletAddress` 设置为空字符串。 + - 如果启用,我们会在第 3 行设置监听器 `window.ethereum.on("accountsChanged")` 监听 MetaMask 钱包中的状态变化,变化包括用户将其他帐户连接到去中心化应用程序、切换帐户或断开帐户。 如果至少连接了一个帐户,`walletAddress` 状态变量将更新为监听器返回的 `accounts` 数组中的第一个帐户。 否则,`walletAddress` 将设置为空字符串。 最后,我们必须在 `useEffect` 函数中调用它: @@ -466,7 +463,7 @@ useEffect(async () => { 瞧! 我们已经完成了所有钱包功能的编程! 我们的钱包已经设置好了,现在让我们弄清楚如何铸造非同质化代币! -## 非同质化代币元数据 101 {#nft-metadata-101} +## NFT 元数据入门 {#nft-metadata-101} 所以,请记住我们刚刚在本教程的第 0 步讨论过的非同质化代币元数据,它是非同质化代币的核心,让非同质化代币具有属性,例如数字资产、名称、描述及其他特性。 @@ -478,25 +475,25 @@ useEffect(async () => { - 我们可以将其存储在中心化服务器上,例如 AWS 或 Firebase。 但这会违背我们的去中心化核心理念。 - 我们可以使用去中心化协议和对等网络星际文件系统,在分布式文件系统中存储和共享数据。 由于该协议是去中心化且免费的,因此它是我们的最佳选择! -要将我们的元数据存储在星际文件系统上,我们将使用 [Pinata](https://pinata.cloud/),这是一种方便的星际文件系统应用程序接口和工具包。 下一步,我们将准确解释如何操作! +要将我们的元数据存储在 IPFS 上,我们将使用 [Pinata](https://pinata.cloud/),这是一种方便的 IPFS API 和工具包。 下一步,我们将准确解释如何操作! -## 使用 Pintata 将元数据固定到星际文件系统 {#use-pinata-to-pin-your-metadata-to-IPFS} +## 使用 Pinata 将你的元数据固定到 IPFS {#use-pinata-to-pin-your-metadata-to-IPFS} -如果您没有 [Pinata](https://pinata.cloud/) 帐户,请点击[此处](https://app.pinata.cloud/auth/signup)注册一个免费帐户完成您的电子邮件和帐户验证步骤。 +如果你没有 [Pinata](https://pinata.cloud/) 帐户,请[在此处](https://app.pinata.cloud/auth/signup)注册一个免费帐户,并完成验证你的电子邮件和帐户的步骤。 -### 创建您的 Pinata 应用程序接口密钥 {#create-pinata-api-key} +### 创建你的 Pinata API 密钥 {#create-pinata-api-key} -导航到 [https://pinata.cloud/keys](https://pinata.cloud/keys) 页面,然后选择顶部的“新建密钥”按钮并将“管理”小组件设置为启用,然后给您的密钥命名。 +导航到 [https://pinata.cloud/keys](https://pinata.cloud/keys) 页面,然后选择顶部的“New Key”按钮并将“管理”小组件设置为启用,然后给你的密钥命名。 -然后,将显示一个包含您的应用程序接口信息的弹出窗口。 确保把它放在安全的地方。 +然后,将显示一个包含你的应用程序接口信息的弹出窗口。 确保把它放在安全的地方。 我们的密钥已经设置好了,我们现在将它添加到项目中以便可以使用它。 ### 创建 .env 文件 {#create-a-env} -我们可以将 Pinata 密钥和私钥安全地存储在环境文件中。 我们在您的项目目录中安装 [dotenv 软件包](https://www.npmjs.com/package/dotenv)。 +我们可以将 Pinata 密钥和私钥安全地存储在环境文件中。 让我们在你的项目目录中安装 [dotenv 包](https://www.npmjs.com/package/dotenv)。 -在您的终端\(与运行本地主机的终端分开\)中打开一个新选项卡,并确保您位于 `minter-starter-files` 文件夹中,然后在终端运行以下命令: +在你的终端中打开一个新标签页(与运行本地主机的标签页分开),并确保你位于 `minter-starter-files` 文件夹中,然后在终端运行以下命令: ```text npm install dotenv --save @@ -508,22 +505,22 @@ npm install dotenv --save vim.env ``` -这将在 vim \(一种文本编辑器)中弹出并打开您的 `.env` 文件。 要保存它,依次在键盘上按“esc” + “:” + “q”。 +这将在 vim(一种文本编辑器)中弹出并打开你的 `.env` 文件。 要保存它,依次在键盘上按“esc” + “:” + “q”。 -接下来,在 VSCode 中,导航到您的 `.env` 文件并向其中添加您的 Pinata 应用程序接口密钥和应用程序接口私钥,如下所示: +接下来,在 VSCode 中,导航到你的 `.env` 文件并向其中添加你的 Pinata API 密钥和 API 私钥,如下所示: ```text REACT_APP_PINATA_KEY = REACT_APP_PINATA_SECRET = ``` -保存该文件,然后您就可以开始编写函数将您的 JSON 元数据上传到星际文件系统! +保存该文件,然后你就可以开始编写函数将你的 JSON 元数据上传到星际文件系统! ### 实现 pinJSONToIPFS {#pin-json-to-ipfs} -对我们来说幸运的是,Pinata 提供了一个[专门用于将 JSON 数据上传到星际文件系统的应用程序接口](https://docs.pinata.cloud/api-reference/endpoint/ipfs/pin-json-to-ipfs#pin-json)和一个方便的使用 axios 示例的 JavaScript,我们做一些轻微修改后就可以使用它。 +幸运的是,Pinata 有一个[专门用于将 JSON 数据上传到 IPFS 的 API](https://docs.pinata.cloud/api-reference/endpoint/ipfs/pin-json-to-ipfs#pin-json),以及一个方便的、带有 axios 示例的 JavaScript,我们可以稍作修改后加以使用。 -在您的 `utils` 文件夹中,我们创建另一个名为 `pinata.js` 的文件,然后从 .env 文件中导入我们的 Pinata 私钥和密钥,如下所示: +在你的 `utils` 文件夹中,我们创建另一个名为 `pinata.js` 的文件,然后从 .env 文件中导入我们的 Pinata 私钥和密钥,如下所示: ```javascript require("dotenv").config() @@ -531,7 +528,7 @@ const key = process.env.REACT_APP_PINATA_KEY const secret = process.env.REACT_APP_PINATA_SECRET ``` -接下来,将下面的代码粘贴到您的 `pinata.js` 文件中。 别担心,我们将详细讲解每一行的含义! +接下来,将下面的代码粘贴到你的 `pinata.js` 文件中。 别担心,我们将详细讲解每一行的含义! ```javascript require("dotenv").config() @@ -542,7 +539,7 @@ const axios = require("axios") export const pinJSONToIPFS = async (JSONBody) => { const url = `https://api.pinata.cloud/pinning/pinJSONToIPFS` - //making axios POST request to Pinata ⬇️ + //向 Pinata 发出 axios POST 请求 ⬇️ return axios .post(url, JSONBody, { headers: { @@ -571,40 +568,40 @@ export const pinJSONToIPFS = async (JSONBody) => { 首先,它导入 [axios](https://www.npmjs.com/package/axios),axios 是一个基于 Promise 的超文本传输协议客户端,可用于浏览器和 node.js,我们将使用它创建一个发送到 Pinata 的请求。 -然后,我们使用异步函数 `pinJSONToIPFS`,它以 `JSONBody` 作为输入参数,并在其报头中使用 Pinata 应用程序接口密钥和私钥,这些都是为了向其 `pinJSONToIPFS` 应用程序接口发出 POST 请求。 +然后,我们使用异步函数 `pinJSONToIPFS`,它以 `JSONBody` 作为输入参数,并在其报头中使用 Pinata api 密钥和私钥,这些都是为了向其 `pinJSONToIPFS` API 发出 POST 请求。 - 如果此 POST 请求成功,我们的函数返回一个 `success` 布尔值为 true 的 JSON 对象以及固定我们元数据的 `pinataUrl`。 我们将使用返回的 `pinataUrl` 作为我们智能合约的 mint 函数的 `tokenURI` 输入。 - 如果此 post 请求失败,我们的函数返回一个 `success` 布尔值为 false 的 JSON 对象和一个指示我们错误的 `message` 字符串。 -与 `connectWallet` 函数返回类型一样,会返回 JSON 对象,因此我们可以使用它们的参数更新状态变量和用户界面。 +与 `connectWallet` 函数返回类型一样,会返回 JSON 对象,因此我们可以使用它们的参数更新状态变量和 UI。 -## 加载您的智能合约 {#load-your-smart-contract} +## 加载你的智能合约 {#load-your-smart-contract} -我们有办法通过 `pinJSONToIPFS` 函数将非同质化代币元数据上传到星际文件系统,现在我们需要一种办法来加载我们智能合约的实例,以便我们可以调用其 `mintNFT ` 函数。 +我们有办法通过 `pinJSONToIPFS` 函数将 NFT 元数据上传到 IPFS,现在我们需要一种办法来加载我们智能合约的实例,以便我们可以调用其 `mintNFT` 函数。 -正如我们之前提到的,在本教程中,我们将使用[这个现有的非同质化代币智能合约](https://ropsten.etherscan.io/address/0x4C4a07F737Bf57F6632B6CAB089B78f62385aCaE);但是,如果您想了解我们如何创建或者想自己创建一个,我们强烈建议您参阅我们的另一个教程[“如何创建非同质化代币。”](https://docs.alchemyapi.io/alchemy/tutorials/how-to-create-an-nft)。 +正如我们之前提到的,在本教程中,我们将使用[这个现有的 NFT 智能合约](https://ropsten.etherscan.io/address/0x4C4a07F737Bf57F6632B6CAB089B78f62385aCaE);但是,如果你想了解我们如何创建或者想自己创建一个,我们强烈建议你参阅我们的另一个教程[“如何创建 NFT”](https://www.alchemy.com/docs/how-to-create-an-nft)。 -### 智能合约应用程序二进制接口 {#contract-abi} +### 合约 ABI {#contract-abi} -如果您仔细研究我们的文件,您会注意到我们的 `src` 目录中有一个 `contract-abi.json` 文件。 在指定合约将要调用的函数以及确保函数以您期望的格式返回数据时,应用程序二进制接口必不可少。 +如果你仔细研究我们的文件,你会注意到我们的 `src` 目录中有一个 `contract-abi.json` 文件。 在指定合约将要调用的函数以及确保函数以你期望的格式返回数据时,应用程序二进制接口必不可少。 我们还需要一个 Alchemy 应用程序接口密钥和 Alchemy Web3 应用程序接口,用来连接到以太坊区块链并加载我们的智能合约。 -### 创建您的 Alchemy API 密钥 {#create-alchemy-api} +### 创建你的 Alchemy API 密钥 {#create-alchemy-api} -如果您还没有 Alchemy 帐户,请[在此处免费注册。](https://alchemy.com/?a=eth-org-nft-minter) +如果你还没有 Alchemy 帐户,[请在此处免费注册。](https://alchemy.com/?a=eth-org-nft-minter) -创建 Alchemy 帐户后,您可以通过创建应用程序来生成应用程序接口密钥。 我们可以用它向 Ropsten 测试网发出请求。 +创建 Alchemy 帐户后,你可以通过创建应用程序来生成应用程序接口密钥。 我们可以用它向 Ropsten 测试网发出请求。 -通过将鼠标悬停在导航栏中的“Apps”上方并点击“Create App”,导航到您的 Alchemy 仪表板中的“Create App”页面。 +通过将鼠标悬停在导航栏中的“Apps”上方并点击“Create App”,导航到你的 Alchemy 仪表板中的“Create App”页面。 -给您的应用程序命名,我们选择“My First NFT!”(我的第一个非同质化代币!),提供简短描述,对于您的应用程序簿记环境选择“Staging”,对于网络选择“Ropsten”。 +给你的应用程序命名,我们选择“My First NFT!”(我的第一个非同质化代币!),提供简短描述,对于你的应用程序簿记环境选择“Staging”,对于网络选择“Ropsten”。 -点击“Create app”,完成! 您的应用程序应该就会出现在下面的表格中。 +点击“Create app”,完成! 你的应用程序应该就会出现在下面的表格中。 太棒了,我们已经创建了我们的 HTTP Alchemy 应用程序接口网址,现在请将其复制到剪贴板...... -…...然后让我们将它添加到我们的 `.env` 文件中。 总之,您的 .env 文件应如下所示: +…然后让我们将它添加到我们的 `.env` 文件中。 总之,你的 .env 文件应如下所示: ```text REACT_APP_PINATA_KEY = @@ -612,18 +609,18 @@ REACT_APP_PINATA_SECRET = REACT_APP_ALCHEMY_KEY = https://eth-ropsten.alchemyapi.io/v2/ ``` -既然我们已经有合约应用程序二进制接口和 Alchemy 应用程序接口密钥了,现在我们可以使用 [Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3) 加载我们的智能合约。 +既然我们已经有合约 ABI 和 Alchemy API 密钥了,现在我们可以使用 [Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3) 加载我们的智能合约。 -### 设置您的 Alchemy Web3 端点和合约 {#setup-alchemy-endpoint} +### 设置你的 Alchemy Web3 端点和合约 {#setup-alchemy-endpoint} -首先,如果您还没有 [Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3),您需要通过在终端导航到主目录 `nft-minter-tutorial` 来安装它: +首先,如果你还没有 [Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3),你需要通过在终端导航到主目录 `nft-minter-tutorial` 来安装它: ```text cd .. npm install @alch/alchemy-web3 ``` -接下来,我们返回 `interact.js` 文件。 在该文件顶部添加以下代码,以便从您的 .env 文件中导入 Alchemy 密钥并设置您的 Alchemy Web3 端点: +接下来,我们返回 `interact.js` 文件。 在该文件顶部添加以下代码,以便从你的 .env 文件中导入 Alchemy 密钥并设置你的 Alchemy Web3 端点: ```javascript require("dotenv").config() @@ -632,7 +629,7 @@ const { createAlchemyWeb3 } = require("@alch/alchemy-web3") const web3 = createAlchemyWeb3(alchemyKey) ``` -[Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3) 是 [Web3.js](https://docs.web3js.org/) 的包装类,提供增强的应用程序接口方法和其他重要优势,让 Web3 开发者的工作更轻松。 它设计成只需经过最少的配置即可使用,因此您可以直接在您的应用程序中开始使用它! +[Alchemy Web3](https://github.com/alchemyplatform/alchemy-web3) 是 [Web3.js](https://docs.web3js.org/) 的包装器,提供增强的 API 方法和其他重要优势,让 Web3 开发者的工作更轻松。 它设计成只需经过最少的配置即可使用,因此你可以直接在你的应用程序中开始使用它! 接下来,我们将合约应用程序二进制接口和合约地址添加到我们的文件中。 @@ -650,7 +647,7 @@ const contractAddress = "0x4C4a07F737Bf57F6632B6CAB089B78f62385aCaE" ## 实现 mintNFT 函数 {#implement-the-mintnft-function} -在 `interact.js` 文件中,我们定义的函数 `mintNFT`,它将用相同的名称铸造非同质化代币。 +在 `interact.js` 文件中,我们定义的函数 `mintNFT`,它将用相同的名称铸造 NFT。 因为我们将进行大量异步调用\(调用 Pinata 将我们的元数据固定到星际文件系统,调用 Alchemy Web3 加载我们的智能合约,并且调用 MetaMask 签署我们的交易\),我们的函数也将是异步的。 @@ -666,21 +663,21 @@ export const mintNFT = async (url, name, description) => {} ```javascript export const mintNFT = async (url, name, description) => { - //error handling + //错误处理 if (url.trim() == "" || name.trim() == "" || description.trim() == "") { return { success: false, - status: "❗Please make sure all fields are completed before minting.", + status: "❗请在铸币前确保所有字段都已填写完毕。", } } } ``` -本质上,如果有任何输入参数是空字符串,我们返回一个 JSON 对象,其中 `success` 布尔值为 false,并且 `status` 字符串指示我们用户界面中的所有字段必须完整。 +本质上,如果有任何输入参数是空字符串,我们返回一个 JSON 对象,其中 `success` 布尔值为 false,并且 `status` 字符串指示我们 UI 中的所有字段必须完整。 -### 将元数据上传到星际文件系统 {#upload-metadata-to-ipfs} +### 将元数据上传到 IPFS {#upload-metadata-to-ipfs} -在知道我们的元数据格式正确后,下一步是将其包装到 JSON 对象中,并通过我们编写的 `pinJSONToIPFS` 将其上传到星际文件系统! +在知道我们的元数据格式正确后,下一步是将其包装到 JSON 对象中,并通过我们编写的 `pinJSONToIPFS` 将其上传到 IPFS! 为此,我们首先需要将 `pinJSONToIPFS` 函数导入到 `interact.js` 文件中。 在 `interact.js` 文件最顶部,我们添加: @@ -694,26 +691,26 @@ import { pinJSONToIPFS } from "./pinata.js" ```javascript export const mintNFT = async (url, name, description) => { - //error handling + //错误处理 if (url.trim() == "" || name.trim() == "" || description.trim() == "") { return { success: false, - status: "❗Please make sure all fields are completed before minting.", + status: "❗请在铸币前确保所有字段都已填写完毕。", } } - //make metadata + //创建元数据 const metadata = new Object() metadata.name = name metadata.image = url metadata.description = description - //make pinata call + //发出 pinata 请求 const pinataResponse = await pinJSONToIPFS(metadata) if (!pinataResponse.success) { return { success: false, - status: "😢 Something went wrong while uploading your tokenURI.", + status: "😢 上传你的 tokenURI 时出错了。", } } const tokenURI = pinataResponse.pinataUrl @@ -733,16 +730,16 @@ window.contract = await new web3.eth.Contract(contractABI, contractAddress) 最后,在 `mintNFT` 函数中添加我们的以太坊交易: ```javascript -//set up your Ethereum transaction +//设置你的以太坊交易 const transactionParameters = { - to: contractAddress, // Required except during contract publications. - from: window.ethereum.selectedAddress, // must match user's active address. + to: contractAddress, // 合约发布期间外为必填项。 + from: window.ethereum.selectedAddress, // 必须与用户活动地址匹配。 data: window.contract.methods .mintNFT(window.ethereum.selectedAddress, tokenURI) - .encodeABI(), //make call to NFT smart contract + .encodeABI(), //调用 NFT 智能合约 } -//sign the transaction via MetaMask +//通过 MetaMask 签署交易 try { const txHash = await window.ethereum.request({ method: "eth_sendTransaction", @@ -751,24 +748,24 @@ try { return { success: true, status: - "✅ Check out your transaction on Etherscan: https://ropsten.etherscan.io/tx/" + + "✅ 在 Etherscan 上查看你的交易:https://ropsten.etherscan.io/tx/" + txHash, } } catch (error) { return { success: false, - status: "😥 Something went wrong: " + error.message, + status: "😥 出错了:" + error.message, } } ``` -如果您已经熟悉以太坊交易,您会注意到其结构与您以前看到的非常相似。 +如果你已经熟悉以太坊交易,你会注意到其结构与你以前看到的非常相似。 - 首先,我们设置交易参数。 - - `to` 指定接收者地址\(我们的智能合约\) - - `from` 指定交易的签名者\(用户连接到 MetaMask 的地址:`window.ethereum.selectedAddress`\) - - `data` 包含对智能合约 `mintNFT` 方法的调用,该方法接收 `tokenURI` 和用户的钱包地址 `window.ethereum.selectedAddress ` 作为输入 -- 然后,我们发出一个 await 调用 `window.ethereum.request`,我们通过它要求 MetaMask 签署交易。 注意,在该请求中,我们指定了我们的以太币方法 \(eth_SentTransaction\) 并传入了 `transactionParameters`。 此时,MetaMask 将在浏览器中打开,并提示用户签署或拒绝交易。 + - `to` 指定接收者地址(我们的智能合约) + - `from` 指定交易的签名者(用户连接到 MetaMask 的地址:`window.ethereum.selectedAddress`) + - `data` 包含对智能合约 `mintNFT` 方法的调用,该方法接收 `tokenURI` 和用户的钱包地址 `window.ethereum.selectedAddress` 作为输入 +- 接下来,我们进行对 `window.ethereum.request` 进行异步调用,请求 MetaMask 对交易进行签名。 注意,在该请求中,我们指定了我们的以太币方法(`eth_SentTransaction`)并传入了 `transactionParameters`。 此时,MetaMask 将在浏览器中打开,并提示用户签署或拒绝交易。 - 如果交易成功,该函数将返回一个 JSON 对象,其中布尔值 `success` 设置为 true,并且 `status` 字符串提示用户查看 Etherscan 区块浏览器以获取有关其交易的更多信息。 - 如果交易失败,该函数将返回一个 JSON 对象,其中 `success` 布尔值设置为 false,并且 `status` 字符串指示错误信息。 @@ -776,43 +773,43 @@ try { ```javascript export const mintNFT = async (url, name, description) => { - //error handling + //错误处理 if (url.trim() == "" || name.trim() == "" || description.trim() == "") { return { success: false, - status: "❗Please make sure all fields are completed before minting.", + status: "❗请在铸币前确保所有字段都已填写完毕。", } } - //make metadata + //创建元数据 const metadata = new Object() metadata.name = name metadata.image = url metadata.description = description - //pinata pin request + //pinata 置顶请求 const pinataResponse = await pinJSONToIPFS(metadata) if (!pinataResponse.success) { return { success: false, - status: "😢 Something went wrong while uploading your tokenURI.", + status: "😢 上传你的 tokenURI 时出错了。", } } const tokenURI = pinataResponse.pinataUrl - //load smart contract + //加载智能合约 window.contract = await new web3.eth.Contract(contractABI, contractAddress) //loadContract(); - //set up your Ethereum transaction + //设置你的以太坊交易 const transactionParameters = { - to: contractAddress, // Required except during contract publications. - from: window.ethereum.selectedAddress, // must match user's active address. + to: contractAddress, // 合约发布期间外为必填项。 + from: window.ethereum.selectedAddress, // 必须与用户活动地址匹配。 data: window.contract.methods .mintNFT(window.ethereum.selectedAddress, tokenURI) - .encodeABI(), //make call to NFT smart contract + .encodeABI(), //调用 NFT 智能合约 } - //sign transaction via MetaMask + //通过 MetaMask 签署交易 try { const txHash = await window.ethereum.request({ method: "eth_sendTransaction", @@ -821,13 +818,13 @@ export const mintNFT = async (url, name, description) => { return { success: true, status: - "✅ Check out your transaction on Etherscan: https://ropsten.etherscan.io/tx/" + + "✅ 在 Etherscan 上查看你的交易:https://ropsten.etherscan.io/tx/" + txHash, } } catch (error) { return { success: false, - status: "😥 Something went wrong: " + error.message, + status: "😥 出错了:" + error.message, } } } @@ -837,7 +834,7 @@ export const mintNFT = async (url, name, description) => { ## 将 mintNFT 连接到我们的 Minter.js 前端 {#connect-our-frontend} -打开您的 `Minter.js` 文件,并将顶部的 `import { connectWallet, getCurrentWalletConnected } from "./utils/interact.js";` 行更新为: +打开你的 `Minter.js` 文件,并将顶部的 `import { connectWallet, getCurrentWalletConnected } from "./utils/interact.js";` 行更新为: ```javascript import { @@ -847,7 +844,7 @@ import { } from "./utils/interact.js" ``` -最后,实现 `onMintPressed` 函数对导入的 `mintNFT` 函数进行 await 调用,并更新 `status` 状态变量以表示我们的交易是成功还是失败: +最后,实现 `onMintPressed` 函数对导入的 `mintNFT` 函数进行 `await` 调用,并更新 `status` 状态变量以表示我们的交易是成功还是失败: ```javascript const onMintPressed = async () => { @@ -856,22 +853,22 @@ const onMintPressed = async () => { } ``` -## 将您的非同质化代币部署到在线网站 {#deploy-your-NFT} +## 将你的 NFT 部署到在线网站 {#deploy-your-NFT} -准备好让您的项目上线和用户互动了吗? 查看[本教程](https://docs.alchemy.com/alchemy/tutorials/nft-minter/how-do-i-deploy-nfts-online),将您的铸币机部署到在线网站。 +准备好让你的项目上线和用户互动了吗? 查看[本教程](https://docs.alchemy.com/alchemy/tutorials/nft-minter/how-do-i-deploy-nfts-online)以将你的 Minter 部署到在线网站。 最后一步...... -## 掀起区块链世界的风暴 {#take-the-blockchain-world-by-storm} +## 让区块链世界为之震撼 {#take-the-blockchain-world-by-storm} -开个玩笑,您已经完成了本教程! +开个玩笑,你已经完成了本教程! -概括一下,通过构建非同质化代币铸币机,您成功学会了如何: +概括一下,通过构建非同质化代币铸币机,你成功学会了如何: -- 通过您的前端项目连接到 MetaMask +- 通过你的前端项目连接到 MetaMask - 在前端调用智能合约的方法 - 使用 MetaMask 签署交易 -大概,你想要在钱包中炫耀通过你的去中心化应用程序铸造的非同质化代币 — 所以请务必参阅我们的快速教程:[如何查看钱包中的非同质化代币](https://docs.alchemyapi.io/alchemy/tutorials/how-to-write-and-deploy-a-nft-smart-contract/how-to-view-your-nft-in-your-wallet)! +也许你希望能够在钱包中展示通过你的去中心化应用程序铸造的 NFT — 因此请务必查看我们的快速教程[“如何在钱包中查看你的 NFT”](https://www.alchemy.com/docs/how-to-view-your-nft-in-your-mobile-wallet)! -一如既往,如果您有任何问题,我们会在 [Alchemy Discord](https://discord.gg/gWuC7zB) 中随时为您提供帮助。 我们迫不及待地想看看您如何在将来的项目中应用本教程中的概念! +一如既往,如果你有任何问题,我们会在 [Alchemy Discord](https://discord.gg/gWuC7zB) 中随时为你提供帮助。 我们迫不及待地想看看你如何在将来的项目中应用本教程中的概念! diff --git a/public/content/translations/zh/developers/tutorials/optimism-std-bridge-annotated-code/index.md b/public/content/translations/zh/developers/tutorials/optimism-std-bridge-annotated-code/index.md index c5185d455c7..f44bf087138 100644 --- a/public/content/translations/zh/developers/tutorials/optimism-std-bridge-annotated-code/index.md +++ b/public/content/translations/zh/developers/tutorials/optimism-std-bridge-annotated-code/index.md @@ -1,84 +1,89 @@ --- -title: "乐观解决方案标准链桥合约演示" -description: 乐观解决方案标准链桥如何运作? 为什么它会这样工作? +title: "Optimism 标准链桥合约详解" +description: "Optimism 的标准链桥如何运作? 它为何以这种方式运作?" author: Ori Pomerantz -tags: - - "solidity" - - "链桥" - - "二层网络" +tags: [ "Solidity", "链桥", "二层网络" ] skill: intermediate published: 2022-03-30 lang: zh --- -[乐观解决方案](https://www.optimism.io/)采用[乐观卷叠](/developers/docs/scaling/optimistic-rollups/)技术。 乐观卷叠能够以比以太坊主网(也称“第一层”)低得多的价格处理交易,因为交易只是由几个节点而非网络上的所有节点处理。 同时所有数据都已写入第一层,因此一切都能够得到证明并重建,并且具有主网的所有完整性和可用性保证。 +[Optimism](https://www.optimism.io/) 是一种[乐观卷叠](/developers/docs/scaling/optimistic-rollups/)。 +乐观卷叠能够以比以太坊主网(也称为第 1 层或 L1)低得多的价格处理交易,因为交易仅由少数节点处理,而不是网络上的每个节点。 +同时,所有数据都会写入 L1,因此,所有内容都可以用主网的完整性和可用性保证来证明和重构。 -要在乐观解决方案(或任何其他第二层)上使用第一层资产,需要[桥接](/bridges/#prerequisites)该资产。 实现这一点的一种方法是,用户在一层网络上锁定资产(以太币和 [ERC-20 代币](/developers/docs/standards/tokens/erc-20/)是最常见的资产)并收到供在二层网络上使用的对等资产。 最后,拥有这些资产的任何人可能想把它们桥接回第一层。 在桥接过程中,资产会在第二层销毁,然后在第一层上发放给用户。 +要在 Optimism(或任何其他 L2)上使用 L1 资产,需要将这些资产[桥接](/bridges/#prerequisites)。 +实现这一点的一种方法是,用户在 L1 上锁定资产(最常见的是 ETH 和 [ERC-20 代币](/developers/docs/standards/tokens/erc-20/)),并在 L2 上收到等值的资产以供使用。 +最后,持有这些资产的任何人可能都想将它们桥接回 L1。 +执行此操作时,资产在 L2 上被销毁,然后在 L1 上释放回给用户。 -这就是[乐观解决方案标准链桥](https://docs.optimism.io/app-developers/bridging/standard-bridge)的工作方式。 在本文中,我们将学习链桥的源代码,看看它如何工作,并将它作为精心编写的 Solidity 代码示例加以研究。 +这就是 [Optimism 标准链桥](https://docs.optimism.io/app-developers/bridging/standard-bridge) 的运作方式。 +在本文中,我们将深入研究该链桥的源代码,了解其运作方式,并将其作为编写良好的 Solidity 代码示例进行学习。 -## 控制流通 {#control-flows} +## 控制流 {#control-flows} -链桥有两种主要流通方式: +该链桥有两个主要流程: -- 存款(从第一层到第二层) -- 提款(从第二层到第一层) +- 存款(从 L1 到 L2) +- 取款(从 L2 到 L1) -### 存款流通 {#deposit-flow} +### 存款流程 {#deposit-flow} -#### 第一层 {#deposit-flow-layer-1} +#### 第 1 层 {#deposit-flow-layer-1} -1. 如果存入 ERC-20,存款人会给链桥一笔费用,这笔费用从所存入的金额中抽取 -2. 存款人调用第一层链桥(`depositERC20`、`depositERC20To`、`depositETH` 或 `depositETHTo`) -3. 第一层链桥拥有桥接的资产 - - 以太币:资产由存款人在调用过程中转移 - - ERC-20:资产被链桥转移给链桥自身,使用的是存款人提供的费用 -4. 第一层链桥使用跨域信息机制调用第二层链桥上的 `finalizeDeposit` +1. 如果存入 ERC-20,存款人会授予链桥一笔许可额度,用于花费待存入的金额 +2. 存款人调用 L1 链桥(`depositERC20`、`depositERC20To`、`depositETH` 或 `depositETHTo`) +3. L1 链桥持有桥接的资产 + - ETH:资产由存款人在调用过程中转账 + - ERC-20:链桥使用存款人提供的许可额度将资产转账给自己 +4. L1 链桥使用跨域消息机制在 L2 链桥上调用 `finalizeDeposit` -#### 二层网络 {#deposit-flow-layer-2} +#### 第 2 层 {#deposit-flow-layer-2} -5. 第二层链桥验证调用 `finalizeDeposit` 是否合法: - - 来自交叉域信息合约 - - 最初来自第一层链桥 -6. 第二层链桥检查第二层上的 ERC-20 代币合约是否正确: - - 第二层合约报告,对应的第一层合约与第一层上提供代币的合约相同 - - 第二层合约报告它支持正确的接口([使用 ERC-165](https://eips.ethereum.org/EIPS/eip-165))。 -7. 如果第二层合约正确,请调用它以便在适当地址铸造相应数量的代币。 如果不正确,请启动提款过程让用户可以在第一层上认领代币。 +5. L2 链桥验证对 `finalizeDeposit` 的调用是合法的: + - 来自跨域消息合约 + - 最初来自 L1 上的链桥 +6. L2 链桥检查 L2 上的 ERC-20 代币合约是否正确: + - L2 合约报告其 L1 对应合约与 L1 上代币来源的合约相同 + - L2 合约报告它支持正确的接口([使用 ERC-165](https://eips.ethereum.org/EIPS/eip-165))。 +7. 如果 L2 合约正确,则调用它向相应地址铸造相应数量的代币。 如果不正确,则启动取款流程,允许用户在 L1 上认领代币。 -### 提款流程 {#withdrawal-flow} +### 取款流程 {#withdrawal-flow} -#### 二层网络 {#withdrawal-flow-layer-2} +#### 第 2 层 {#withdrawal-flow-layer-2} -1. 提款人调用第二层链桥(`withdraw` 或 `withdrawTo`) -2. 第二层链桥销毁属于 `msg.sender` 的适当数量代币 -3. 第二层链桥使用跨域信息机制调用第一层链桥上的 `finalizeETHWithdrawal` 或 `finalizeERC20Withdrawal` +1. 取款人调用 L2 链桥(`withdraw` 或 `withdrawTo`) +2. L2 链桥销毁属于 `msg.sender` 的相应数量的代币 +3. L2 链桥使用跨域消息机制在 L1 链桥上调用 `finalizeETHWithdrawal` 或 `finalizeERC20Withdrawal` -#### 第一层 {#withdrawal-flow-layer-1} +#### 第 1 层 {#withdrawal-flow-layer-1} -4. 第一层链桥验证调用 `finalizeETHWithdrawal` 或 `finalizeERC20Withdrawal` 是否合法: - - 来自交叉域信息机制 - - 最初来自第二层上的链桥 -5. 第一层链桥将适当资产(以太币或 ERC-20)转账到适当地址 +4. L1 链桥验证对 `finalizeETHWithdrawal` 或 `finalizeERC20Withdrawal` 的调用是合法的: + - 来自跨域消息机制 + - 最初来自 L2 上的链桥 +5. L1 链桥将相应资产(ETH 或 ERC-20)转账到相应地址 -## 一层网络代码 {#layer-1-code} +## 第 1 层代码 {#layer-1-code} -以下代码在第一层即以太坊主网上运行。 +这是在 L1(以太坊主网)上运行的代码。 ### IL1ERC20Bridge {#IL1ERC20Bridge} -[此接口在此处定义](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L1/messaging/IL1ERC20Bridge.sol)。 其中包括桥接 ERC-20 代币所需的函数和定义。 +[此接口在此处定义](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L1/messaging/IL1ERC20Bridge.sol)。 +它包含桥接 ERC-20 代币所需的函数和定义。 ```solidity // SPDX-License-Identifier: MIT ``` -[大多数乐观解决方案代码都是依据 MIT 许可证发布的](https://help.optimism.io/hc/en-us/articles/4411908707995-What-software-license-does-Optimism-use-)。 +[Optimism 的大部分代码都是在 MIT 许可下发布的](https://help.optimism.io/hc/en-us/articles/4411908707995-What-software-license-does-Optimism-use-)。 ```solidity pragma solidity >0.5.0 <0.9.0; ``` -编写代码时,Solidity 最新版本为 0.8.12。 在 0.9.0 版发布之前,我们不知道这段代码是否与它兼容。 +在撰写本文时,Solidity 的最新版本是 0.8.12。 +在 0.9.0 版本发布之前,我们不知道这段代码是否与其兼容。 ```solidity /** @@ -86,20 +91,23 @@ pragma solidity >0.5.0 <0.9.0; */ interface IL1ERC20Bridge { /********** - * Events * + * 事件 * **********/ event ERC20DepositInitiated( ``` -在乐观解决方案链桥术语中,_存款_是指从第一层转账到第二层,_提款_是指从第二层转账到第一层。 +在 Optimism 链桥术语中,_deposit_ 是指从 L1 到 L2 的转账,而 _withdrawal_ 是指从 L2 到 L1 的转账。 ```solidity address indexed _l1Token, address indexed _l2Token, ``` -大多数情况下,第一层上的 ERC-20 地址与第二层上对应的 ERC-20 地址不同。 [可以在此处参阅代币地址列表](https://static.optimism.io/optimism.tokenlist.json)。 带有 `chainId` 1 的地址在第一层(主网),带有 `chainId` 10 的地址在第二层(乐观解决方案)上。 另两个 `chainId` 值用于 Kovan 测试网络 (42) 和乐观 Kovan 测试网络 (69)。 +在大多数情况下,L1 上的 ERC-20 地址与 L2 上等效的 ERC-20 地址不同。 +[你可以在此处查看代币地址列表](https://static.optimism.io/optimism.tokenlist.json)。 +`chainId` 为 1 的地址在 L1(主网)上,`chainId` 为 10 的地址在 L2 (Optimism) 上。 +另外两个 `chainId` 值分别用于 Kovan 测试网 (42) 和 Optimistic Kovan 测试网 (69)。 ```solidity address indexed _from, @@ -109,7 +117,7 @@ interface IL1ERC20Bridge { ); ``` -可以为转账添加注解,在这种情况下,注解将被添加到报告它们的事件中。 +可以为转账添加备注,在这种情况下,它们将被添加到报告这些转账的事件中。 ```solidity event ERC20WithdrawalFinalized( @@ -122,33 +130,35 @@ interface IL1ERC20Bridge { ); ``` -同一链桥合约处理双向转账。 就第一层链桥而言,这意味着存款的初始化和提款的终局化。 +同一链桥合约处理双向转账。 +就 L1 链桥而言,这意味着存款的初始化和取款的最终敲定。 ```solidity /******************** - * Public Functions * + * 公共函数 * ********************/ /** - * @dev get the address of the corresponding L2 bridge contract. - * @return Address of the corresponding L2 bridge contract. + * @dev 获取相应 L2 链桥合约的地址。 + * @return 相应 L2 链桥合约的地址。 */ function l2TokenBridge() external returns (address); ``` -并不是真需要此函数,因为在第二层上它是一个预部署的合约,所以它总是位于地址 `0x4200000000000000000000000000000000000010` 处。 使用此函数是为了与第二层链桥对称,因为知道第一层桥的地址_并非_不重要。 +这个函数并非真的需要,因为在 L2 上它是一个预部署的合约,所以它总是在地址 `0x4200000000000000000000000000000000000010`。 +它在这里是为了与 L2 链桥对称,因为 L1 链桥的地址_并非_微不足道。 ```solidity /** - * @dev deposit an amount of the ERC20 to the caller's balance on L2. - * @param _l1Token Address of the L1 ERC20 we are depositing - * @param _l2Token Address of the L1 respective L2 ERC20 - * @param _amount Amount of the ERC20 to deposit - * @param _l2Gas Gas limit required to complete the deposit on L2. - * @param _data Optional data to forward to L2. This data is provided - * solely as a convenience for external contracts. Aside from enforcing a maximum - * length, these contracts provide no guarantees about its content. + * @dev 将一定数量的 ERC20 存入调用者在 L2 上的余额。 + * @param _l1Token 我们要存入的 L1 ERC20 的地址 + * @param _l2Token L1 对应的 L2 ERC20 的地址 + * @param _amount 要存入的 ERC20 的数量 + * @param _l2Gas 在 L2 上完成存款所需的燃料限制。 + * @param _data 要转发到 L2 的可选数据。此数据 + * 仅为方便外部合约而提供。除了强制执行最大 + * 长度外,这些合约对其内容不提供任何保证。 */ function depositERC20( address _l1Token, @@ -159,19 +169,21 @@ interface IL1ERC20Bridge { ) external; ``` -`_l2Gas` 参数是指允许交易花费的第二层燃料的数量。 [达到某个(上限)额度前,交易是免费的](https://community.optimism.io/docs/developers/bridge/messaging/#for-l1-%E2%87%92-l2-transactions-2),所以除非 ERC-20 合约在铸币时行为确实怪异,否则这应该不是问题。 此函数处理常见场景,即用户将资产桥接到不同区块链上的相同地址。 +`_l2Gas` 参数是交易允许花费的 L2 燃料数量。 +[在某个(高)限制内,这是免费的](https://community.optimism.io/docs/developers/bridge/messaging/#for-l1-%E2%87%92-l2-transactions-2),所以除非 ERC-20 合约在铸造时做了什么非常奇怪的事情,否则这应该不成问题。 +此函数处理常见场景,即用户将资产桥接到不同区块链上的相同地址。 ```solidity /** - * @dev deposit an amount of ERC20 to a recipient's balance on L2. - * @param _l1Token Address of the L1 ERC20 we are depositing - * @param _l2Token Address of the L1 respective L2 ERC20 - * @param _to L2 address to credit the withdrawal to. - * @param _amount Amount of the ERC20 to deposit. - * @param _l2Gas Gas limit required to complete the deposit on L2. - * @param _data Optional data to forward to L2. This data is provided - * solely as a convenience for external contracts. Aside from enforcing a maximum - * length, these contracts provide no guarantees about its content. + * @dev 将一定数量的 ERC20 存入接收者在 L2 上的余额。 + * @param _l1Token 我们要存入的 L1 ERC20 的地址 + * @param _l2Token L1 对应的 L2 ERC20 的地址 + * @param _to 用于记入取款的 L2 地址。 + * @param _amount 要存入的 ERC20 的数量。 + * @param _l2Gas 在 L2 上完成存款所需的燃料限制。 + * @param _data 要转发到 L2 的可选数据。此数据 + * 仅为方便外部合约而提供。除了强制执行最大 + * 长度外,这些合约对其内容不提供任何保证。 */ function depositERC20To( address _l1Token, @@ -183,26 +195,26 @@ interface IL1ERC20Bridge { ) external; ``` -此函数基本上与 `depositERC20` 相同,但它允许你将 ERC-20 发送到不同的地址。 +此函数与 `depositERC20` 几乎相同,但它允许你将 ERC-20 发送到不同的地址。 ```solidity /************************* - * Cross-chain Functions * + * 跨链函数 * *************************/ /** - * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the - * L1 ERC20 token. - * This call will fail if the initialized withdrawal from L2 has not been finalized. + * @dev 完成从 L2 到 L1 的取款,并将资金记入接收者 + * L1 ERC20 代币的余额。 + * 如果从 L2 初始化的取款尚未最终确定,此调用将失败。 * - * @param _l1Token Address of L1 token to finalizeWithdrawal for. - * @param _l2Token Address of L2 token where withdrawal was initiated. - * @param _from L2 address initiating the transfer. - * @param _to L1 address to credit the withdrawal to. - * @param _amount Amount of the ERC20 to deposit. - * @param _data Data provided by the sender on L2. This data is provided - * solely as a convenience for external contracts. Aside from enforcing a maximum - * length, these contracts provide no guarantees about its content. + * @param _l1Token 用于 finalizeWithdrawal 的 L1 代币地址。 + * @param _l2Token 发起取款的 L2 代币地址。 + * @param _from 发起转账的 L2 地址。 + * @param _to 用于记入取款的 L1 地址。 + * @param _amount 要存入的 ERC20 的数量。 + * @param _data 发送人在 L2 上提供的数据。此数据 + * 仅为方便外部合约而提供。除了强制执行最大 + * 长度外,这些合约对其内容不提供任何保证。 */ function finalizeERC20Withdrawal( address _l1Token, @@ -215,16 +227,20 @@ interface IL1ERC20Bridge { } ``` -乐观解决方案中的提款(以及从第二层到第一层的其他信息)是一个包含两个步骤的过程: +在 Optimism 中,取款(以及从 L2 到 L1 的其他消息)是一个两步过程: -1. 在第二层上的启动交易。 -2. 在第一层上完成或声明交易。 在第二层交易的[缺陷质询期](https://community.optimism.io/docs/how-optimism-works/#fault-proofs)结束后此交易才可以进行。 +1. 在 L2 上发起一笔交易。 +2. 在 L1 上敲定或声明一笔交易。 + 这笔交易需要在 L2 交易的[故障挑战期](https://community.optimism.io/docs/how-optimism-works/#fault-proofs)结束后才能进行。 ### IL1StandardBridge {#il1standardbridge} -[此接口在此处定义](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L1/messaging/IL1StandardBridge.sol)。 该文件包含以太币的事件和函数定义。 这些定义与上述 `IL1ERC20Bridge` 中为 ERC-20 定义的定义非常相似。 +[此接口在此处定义](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L1/messaging/IL1StandardBridge.sol)。 +该文件包含 ETH 的事件和函数定义。 +这些定义与上面 `IL1ERC20Bridge` 中为 ERC-20 定义的定义非常相似。 -链桥接口分为两个文件,因为某些 ERC-20 代币需要自定义处理,标准链桥接无法处理它们。 这样,处理此类代币的自定义链桥可以实现 `IL1ERC20Bridge`,而不必再桥接以太币。 +链桥接口分为两个文件,因为某些 ERC-20 代币需要自定义处理,标准链桥无法处理它们。 +这样,处理此类代币的自定义链桥可以实现 IL1ERC20Bridge,而不必再桥接 ETH。 ```solidity // SPDX-License-Identifier: MIT @@ -237,7 +253,7 @@ import "./IL1ERC20Bridge.sol"; */ interface IL1StandardBridge is IL1ERC20Bridge { /********** - * Events * + * 事件 * **********/ event ETHDepositInitiated( address indexed _from, @@ -247,7 +263,8 @@ interface IL1StandardBridge is IL1ERC20Bridge { ); ``` -此事件与 ERC-20 版本 (`ERC20DepositInitiated`) 几乎相同,只是没有第一层和第二层代币的地址。 其他事件和函数也是如此。 +此事件与 ERC-20 版本 (`ERC20DepositInitiated`) 几乎相同,只是没有 L1 和 L2 代币地址。 +其他事件和函数也是如此。 ```solidity event ETHWithdrawalFinalized( @@ -257,11 +274,11 @@ interface IL1StandardBridge is IL1ERC20Bridge { ); /******************** - * Public Functions * + * 公共函数 * ********************/ /** - * @dev Deposit an amount of the ETH to the caller's balance on L2. + * @dev 将一定数量的 ETH 存入调用者在 L2 上的余额。 . . . @@ -269,7 +286,7 @@ interface IL1StandardBridge is IL1ERC20Bridge { function depositETH(uint32 _l2Gas, bytes calldata _data) external payable; /** - * @dev Deposit an amount of ETH to a recipient's balance on L2. + * @dev 将一定数量的 ETH 存入接收者在 L2 上的余额。 . . . @@ -281,13 +298,13 @@ interface IL1StandardBridge is IL1ERC20Bridge { ) external payable; /************************* - * Cross-chain Functions * + * 跨链函数 * *************************/ /** - * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the - * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called - * before the withdrawal is finalized. + * @dev 完成从 L2 到 L1 的取款,并将资金记入接收者 + * L1 ETH 代币的余额。由于只有 xDomainMessenger 可以调用此函数,因此在 + * 取款最终确定之前永远不会调用它。 . . . @@ -303,62 +320,65 @@ interface IL1StandardBridge is IL1ERC20Bridge { ### CrossDomainEnabled {#crossdomainenabled} -[此合约](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/bridge/CrossDomainEnabled.sol)由两个链桥([一层网络](#the-l1-bridge-contract)和[二层网络](#the-l2-bridge-contract))继承,以便向其他层发送信息。 +[此合约](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/bridge/CrossDomainEnabled.sol)由两个链桥([L1](#the-l1-bridge-contract) 和 [L2](#the-l2-bridge-contract))继承,用于向另一层发送消息。 ```solidity // SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.9.0; -/* Interface Imports */ +/* 接口导入 */ import { ICrossDomainMessenger } from "./ICrossDomainMessenger.sol"; ``` -[这个接口](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/bridge/ICrossDomainMessenger.sol)告诉合约如何发送使用跨域信使向另一层发送信息。 跨域信使完全是另一种系统,值得单独写一篇文章来介绍,我希望将来能写出来。 +[此接口](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/bridge/ICrossDomainMessenger.sol) 告知合约如何使用跨域信使向另一层发送消息。 +跨域信使完全是另一种系统,值得单独写一篇文章来介绍,我希望将来能写出来。 ```solidity /** * @title CrossDomainEnabled - * @dev Helper contract for contracts performing cross-domain communications + * @dev 执行跨域通信的合约的帮助合约 * - * Compiler used: defined by inheriting contract + * 使用的编译器:由继承合约定义 */ contract CrossDomainEnabled { /************* - * Variables * + * 变量 * *************/ - // Messenger contract used to send and receive messages from the other domain. + // 用于从其他域发送和接收消息的信使合约。 address public messenger; /*************** - * Constructor * + * 构造函数 * ***************/ /** - * @param _messenger Address of the CrossDomainMessenger on the current layer. + * @param _messenger 当前层上的 CrossDomainMessenger 地址。 */ constructor(address _messenger) { messenger = _messenger; } ``` -合约需要知道的一个参数就是跨域信使在这一层的地址。 此参数在构造函数中设置一次,并且永远不会更改。 +合约需要知道的一个参数,就是跨域信使在这一层的地址。 +此参数在构造函数中设置一次,并且永远不会更改。 ```solidity /********************** - * Function Modifiers * + * 函数修饰符 * **********************/ /** - * Enforces that the modified function is only callable by a specific cross-domain account. - * @param _sourceDomainAccount The only account on the originating domain which is - * authenticated to call this function. + * 强制修饰的函数只能由特定的跨域帐户调用。 + * @param _sourceDomainAccount 源域上唯一经过 + * 身份验证可调用此函数的帐户。 */ modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) { ``` -跨域消息传递可以由运行在区块链(以太坊主网或乐观解决方案)上的任何合约使用。 但是每一层都需要链桥。如果信息来自于另一边的链桥,将_只_信任特定信息。 +跨域消息传递可以由运行在区块链(以太坊主网或 Optimism)上的任何合约使用。 +但是每一层都需要链桥。如果消息来自于另一边的链桥,将只信任特定消息。 ```solidity require( @@ -367,7 +387,7 @@ contract CrossDomainEnabled { ); ``` -只能信任来自适当跨域信使(`messenger`,如下所示)的信息。 +只能信任来自适当跨域信使(messenger,如下所示)的消息。 ```solidity @@ -377,9 +397,10 @@ contract CrossDomainEnabled { ); ``` -跨域信使要提供另一层发送信息的地址,就需要用到 [`.xDomainMessageSender()` 函数](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L1/messaging/L1CrossDomainMessenger.sol#L122-L128)。 只要在信息发起的交易中调用它,它就可以提供此信息。 +跨域信使提供另一层发送消息的地址的方式是[`.xDomainMessageSender()` 函数](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L1/messaging/L1CrossDomainMessenger.sol#L122-L128)。 +只要在消息发起的交易中调用它,它就可以提供此信息。 -我们需要确保我们收到的信息来自另一个链桥。 +我们需要确保我们收到的消息来自另一个链桥。 ```solidity @@ -387,29 +408,30 @@ contract CrossDomainEnabled { } /********************** - * Internal Functions * + * 内部函数 * **********************/ /** - * Gets the messenger, usually from storage. This function is exposed in case a child contract - * needs to override. - * @return The address of the cross-domain messenger contract which should be used. + * 获取信使,通常来自存储。如果子合约需要重写 + *,则公开此函数。 + * @return 应该使用的跨域信使合约的地址。 */ function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) { return ICrossDomainMessenger(messenger); } ``` -该函数返回跨域信使。 我们使用函数而不是变量 `messenger`,以允许从该函数继承的合约使用一种算法来指定要使用的跨域信使。 +该函数返回跨域信使。 +我们使用函数而不是变量 messenger,以允许从该函数继承的合约使用一种算法来指定要使用的跨域信使。 ```solidity /** - * Sends a message to an account on another domain - * @param _crossDomainTarget The intended recipient on the destination domain - * @param _message The data to send to the target (usually calldata to a function with - * `onlyFromCrossDomainAccount()`) - * @param _gasLimit The gasLimit for the receipt of the message on the target domain. + * 向另一个域上的帐户发送消息 + * @param _crossDomainTarget 目的域上的预期接收者 + * @param _message 发送到目标的数据(通常是带有 + * `onlyFromCrossDomainAccount()` 的函数的 calldata) + * @param _gasLimit 在目标域上接收消息的燃料限制。 */ function sendCrossDomainMessage( address _crossDomainTarget, @@ -417,17 +439,18 @@ contract CrossDomainEnabled { bytes memory _message ``` -最后是向另一层发送信息的函数。 +最后是向另一层发送消息的函数。 ```solidity ) internal { // slither-disable-next-line reentrancy-events, reentrancy-benign ``` -[Slither](https://github.com/crytic/slither) 是一个静态分析器,乐观解决方案在每个合约上运行它以查找漏洞和其他潜在问题。 在本例中,下面一行会触发两个漏洞: +[Slither](https://github.com/crytic/slither) 是一个静态分析器,Optimism 在每个合约上运行它以查找漏洞和其他潜在问题。 +在本例中,下面一行会触发两个漏洞: -1. [重入事件](https://github.com/crytic/slither/wiki/Detector-Documentation#reentrancy-vulnerabilities-3) -2. [良性重入](https://github.com/crytic/slither/wiki/Detector-Documentation#reentrancy-vulnerabilities-2) +1. [可重入事件](https://github.com/crytic/slither/wiki/Detector-Documentation#reentrancy-vulnerabilities-3) +2. [良性可重入](https://github.com/crytic/slither/wiki/Detector-Documentation#reentrancy-vulnerabilities-2) ```solidity getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit); @@ -435,9 +458,9 @@ contract CrossDomainEnabled { } ``` -在这种情况下,我们不担心重入漏洞,我们知道 `getCrossDomainMessenger()` 返回一个可信地址,即使 Slither 无法知道这一点。 +在这种情况下,我们不担心可重入性,我们知道 `getCrossDomainMessenger()` 返回一个可信地址,即使 Slither 无法知道这一点。 -### 第一层链桥合约 {#the-l1-bridge-contract} +### L1 链桥合约 {#the-l1-bridge-contract} [此合约的源代码在此处](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L1/messaging/L1StandardBridge.sol)。 @@ -446,46 +469,48 @@ contract CrossDomainEnabled { pragma solidity ^0.8.9; ``` -接口可以来自其他合约,因此它们必须支持各种 Solidity 版本。 但是链桥本身属于我们的合约,我们可以严格限制它使用的 Solidity 版本。 +接口可以来自其他合约,因此它们必须支持各种 Solidity 版本。 +但是链桥本身属于我们的合约,我们可以严格限制它使用的 Solidity 版本。 ```solidity -/* Interface Imports */ +/* 接口导入 */ import { IL1StandardBridge } from "./IL1StandardBridge.sol"; import { IL1ERC20Bridge } from "./IL1ERC20Bridge.sol"; ``` -[IL1ERC20Bridge](#IL1ERC20Bridge) 和 [IL1StandardBridge](#IL1StandardBridge) 已在上面进行了说明。 +[IL1ERC20Bridge](#IL1ERC20Bridge) 和 [IL1StandardBridge](#IL1StandardBridge) 已在上面解释。 ```solidity import { IL2ERC20Bridge } from "../../L2/messaging/IL2ERC20Bridge.sol"; ``` -[此接口](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/messaging/IL2ERC20Bridge.sol)让我们创建信息来控制第二层上的标准链桥。 +[此接口](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/messaging/IL2ERC20Bridge.sol) 让我们能够创建消息来控制 L2 上的标准链桥。 ```solidity import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; ``` -[此接口](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol)让我们控制 ERC-20 合约。 [你可以在此处阅读更多信息](/developers/tutorials/erc20-annotated-code/#the-interface)。 +[此接口](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol) 让我们能够控制 ERC-20 合约。 +[你可以在此处阅读更多相关信息](/developers/tutorials/erc20-annotated-code/#the-interface)。 ```solidity -/* Library Imports */ +/* 库导入 */ import { CrossDomainEnabled } from "../../libraries/bridge/CrossDomainEnabled.sol"; ``` -[如上所述](#crossdomainenabled),此合约用于层间信息传递。 +[如上所述](#crossdomainenabled),此合约用于层间消息传递。 ```solidity import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol"; ``` -[`Lib_PredeployAddresses`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/constants/Lib_PredeployAddresses.sol) 为第二层合约提供地址,这些合约始终使用相同的地址。 其中包括第二层上的标准链桥。 +[`Lib_PredeployAddresses`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/constants/Lib_PredeployAddresses.sol) 包含 L2 合约的地址,这些合约的地址始终相同。 其中包括 L2 上的标准链桥。 ```solidity import { Address } from "@openzeppelin/contracts/utils/Address.sol"; ``` -[OpenZeppelin 的地址工具](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol)。 它用于区分合约地址和属于外部帐户 (EOA) 的地址。 +[OpenZeppelin 的 Address 工具](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol)。 它用于区分合约地址和属于外部帐户 (EOA) 的地址。 请注意,这不是一个理想的解决方案,因为无法区分直接调用和合约构造函数的调用,但至少这让我们能够识别和防止一些常见的用户错误。 @@ -498,26 +523,26 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s 1. 回滚 2. 返回 `false` -处理这两种情况会使我们的代码更加复杂,因此我们使用 [OpenZeppelin 的 `SafeERC20`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/utils/SafeERC20.sol),确保[所有失败都导致回滚](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/utils/SafeERC20.sol#L96)。 +处理这两种情况会让我们的代码更复杂,因此我们改用 [OpenZeppelin 的 `SafeERC20`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/utils/SafeERC20.sol),它能确保[所有失败都会导致回滚](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/utils/SafeERC20.sol#L96)。 ```solidity /** * @title L1StandardBridge - * @dev The L1 ETH and ERC20 Bridge is a contract which stores deposited L1 funds and standard - * tokens that are in use on L2. It synchronizes a corresponding L2 Bridge, informing it of deposits - * and listening to it for newly finalized withdrawals. + * @dev L1 ETH 和 ERC20 链桥是一个合约,它存储已存入的 L1 资金和正在 L2 上使用的标准 + * 代币。它同步一个相应的 L2 链桥,通知其存款 + * 并监听其新最终确定的取款。 * */ contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled { using SafeERC20 for IERC20; ``` -此行表示我们如何指定在每次使用 `IERC20` 接口时使用 `SafeERC20` 包装器。 +此行表示我们如何指定在每次使用 IERC20 接口时使用 SafeERC20 包装器。 ```solidity /******************************** - * External Contract References * + * 外部合约引用 * ********************************/ address public l2TokenBridge; @@ -527,50 +552,65 @@ contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled { ```solidity - // Maps L1 token to L2 token to balance of the L1 token deposited + // 将 L1 代币映射到 L2 代币再映射到已存入 L1 代币的余额 mapping(address => mapping(address => uint256)) public deposits; ``` -像这样的双重[映射](https://www.tutorialspoint.com/solidity/solidity_mappings.htm)是定义[二维稀疏数组](https://en.wikipedia.org/wiki/Sparse_matrix)的方式。 此数据结构中的值被标识为 `deposit[L1 token addr][L2 token addr]`。 默认值为零。 只有设置为不同值的单元才会写入存储。 +像这样的双重 [mapping](https://www.tutorialspoint.com/solidity/solidity_mappings.htm) 是定义[二维稀疏数组](https://en.wikipedia.org/wiki/Sparse_matrix)的方式。 +此数据结构中的值被标识为 deposit[L1 代币地址][L2 代币地址]。 +默认值为零。 +只有设置为不同值的单元才会写入存储。 ```solidity /*************** - * Constructor * + * 构造函数 * ***************/ - // This contract lives behind a proxy, so the constructor parameters will go unused. + // 此合约位于代理之后,因此构造函数参数将不被使用。 constructor() CrossDomainEnabled(address(0)) {} ``` -希望能够升级此合约而无需复制存储中的所有变量。 为此,我们使用 [`Proxy`](https://docs.openzeppelin.com/contracts/3.x/api/proxy),此合约使用 [`delegatecall`](https://solidity-by-example.org/delegatecall/) 将呼叫转移到地址由代理合约存储的单独联系人(当你升级时,你告诉代理更改该地址)。 当你使用 `delegatecall` 时,存储仍然是_调用_合约的存储,因此合约所有状态变量的值不受影响。 +希望能够升级此合约而无需复制存储中的所有变量。 +为此,我们使用 [`Proxy`](https://docs.openzeppelin.com/contracts/3.x/api/proxy),这是一个使用 [`delegatecall`](https://solidity-by-example.org/delegatecall/) 将调用转移到另一个独立合约的合约,该独立合约的地址由代理合约存储(当你升级时,你告知代理更改该地址)。 +当你使用 `delegatecall` 时,存储仍然是_调用_合约的存储,因此合约所有状态变量的值不受影响。 -这种模式的结果是不使用 `delegatecall` _调用_的合约的存储,因此传递给它的构造函数值无关紧要。 这就是我们可以为 `CrossDomainEnabled` 构造函数提供一个无意义值的原因。 这也是下面的初始化与构造函数分开的原因。 +这种模式的结果是不使用 `delegatecall` 调用的合约的存储,因此传递给它的构造函数值无关紧要。 +这就是我们可以为 `CrossDomainEnabled` 构造函数提供一个无意义值的原因。 +这也是下面的初始化与构造函数分开的原因。 ```solidity /****************** - * Initialization * + * 初始化 * ******************/ /** - * @param _l1messenger L1 Messenger address being used for cross-chain communications. - * @param _l2TokenBridge L2 standard bridge address. + * @param _l1messenger 用于跨链通信的 L1 Messenger 地址。 + * @param _l2TokenBridge L2 标准链桥地址。 */ // slither-disable-next-line external-function ``` -此 [Slither 测试](https://github.com/crytic/slither/wiki/Detector-Documentation#public-function-that-could-be-declared-external)可识别不是从合约代码调用且因此可以声明为 `external` 而不是 `public` 的函数。 `external` 函数的燃料成本可以更低,因为可以在 calldata 中为它们提供参数。 声明为 `public` 的函数必须可以在合约内部访问。 合约不能修改自己的 calldata,所以参数必须位于内存中。 当外部调用这类函数时,需要将 calldata 复制到内存中,这就会消耗燃料。 在本例中,函数只被调用一次,因此效率低下对我们来说无关紧要。 +此 [Slither 测试](https://github.com/crytic/slither/wiki/Detector-Documentation#public-function-that-could-be-declared-external)识别未从合约代码中调用的函数,因此可以声明为 `external` 而不是 `public`。 +`external` 函数的燃料成本可以更低,因为可以在 calldata 中为它们提供参数。 +声明为 `public` 的函数必须可以在合约内部访问。 +合约不能修改自己的 calldata,所以参数必须位于内存中。 +当外部调用这类函数时,需要将 calldata 复制到内存中,这就会消耗燃料。 +在本例中,函数只被调用一次,因此效率低下对我们来说无关紧要。 ```solidity function initialize(address _l1messenger, address _l2TokenBridge) public { - require(messenger == address(0), "Contract has already been initialized."); + require(messenger == address(0), "合约已被初始化。" ``` -`initialize` 函数只应调用一次。 如果第一层跨域信使或第二层代币链桥的地址发生变化,我们将创建新代理和新链桥来调用它。 这种情况不太可能发生,除非升级整个系统,这非常罕见。 +`initialize` 函数只应调用一次。 +如果 L1 跨域信使或 L2 代币链桥的地址发生变化,我们将创建新代理和新链桥来调用它。 +这种情况不太可能发生,除非升级整个系统,这非常罕见。 -请注意,此函数没有任何机制限制_谁_可以调用它。 这意味着理论上,攻击者可以等到我们部署代理和第一版链桥后,抢在合法用户之前在[前台运行](https://solidity-by-example.org/hacks/front-running/)以使用 `initialize` 函数。 但是有两种方法可以防止这种情况: +请注意,此函数没有任何机制限制谁可以调用它。 +这意味着理论上,攻击者可以等到我们部署代理和第一版链桥后,通过[抢先交易](https://solidity-by-example.org/hacks/front-running/)抢在合法用户之前使用 `initialize` 函数。 但是有两种方法可以防止这种情况: -1. 如果合约不是由外部帐户直接部署,而是[在有另一个合约创建它们的交易中](https://medium.com/upstate-interactive/creating-a-contract-with-a-smart-contract-bdb67c5c8595)部署,那么整个过程可以成为最小操作单元,并且能够在执行任何其他交易之前完成。 +1. 如果合约不是由外部帐户直接部署,而是在[有另一个合约创建它们的交易中部署](https://medium.com/upstate-interactive/creating-a-contract-with-a-smart-contract-bdb67c5c8595),那么整个过程可以成为最小操作单元,并且能够在执行任何其他交易之前完成。 2. 如果对 `initialize` 的合法调用失败,总是可以忽略新创建的代理和链桥并创建新的。 ```solidity @@ -584,15 +624,15 @@ contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled { ```solidity /************** - * Depositing * + * 存款 * **************/ - /** @dev Modifier requiring sender to be EOA. This check could be bypassed by a malicious - * contract via initcode, but it takes care of the user error we want to avoid. + /** @dev 修饰符要求发送方为 EOA。 恶意 + * 合约可以通过 initcode 绕过此检查,但它能避免我们想要防止的用户错误。 */ modifier onlyEOA() { - // Used to stop deposits from contracts (avoid accidentally lost tokens) - require(!Address.isContract(msg.sender), "Account not EOA"); + // 用于阻止来自合约的存款(避免代币意外丢失) + require(!Address.isContract(msg.sender), "帐户不是 EOA"); _; } ``` @@ -601,17 +641,18 @@ contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled { ```solidity /** - * @dev This function can be called with no data - * to deposit an amount of ETH to the caller's balance on L2. - * Since the receive function doesn't take data, a conservative - * default amount is forwarded to L2. + * @dev 可以在没有数据的情况下调用此函数 + * 以将一定数量的 ETH 存入调用者在 L2 上的余额。 + * 由于接收函数不接受数据,一个保守的 + * 默认数量被转发到 L2。 */ receive() external payable onlyEOA { _initiateETHDeposit(msg.sender, msg.sender, 200_000, bytes("")); } ``` -此函数存在的目的是测试。 请注意,它没有出现在接口定义中 — 它不适合正常使用。 +此函数存在的目的是测试。 +请注意,它没有出现在接口定义中 — 它不适合正常使用。 ```solidity /** @@ -633,18 +674,18 @@ contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled { } ``` -这两个函数是 `_initiateETHDeposit` 的包装器,_initiateETHDeposit 处理实际的以太币存款。 +这两个函数是 `_initiateETHDeposit` 的包装器,`_initiateETHDeposit` 处理实际的 ETH 存款。 ```solidity /** - * @dev Performs the logic for deposits by storing the ETH and informing the L2 ETH Gateway of - * the deposit. - * @param _from Account to pull the deposit from on L1. - * @param _to Account to give the deposit to on L2. - * @param _l2Gas Gas limit required to complete the deposit on L2. - * @param _data Optional data to forward to L2. This data is provided - * solely as a convenience for external contracts. Aside from enforcing a maximum - * length, these contracts provide no guarantees about its content. + * @dev 通过存储 ETH 并通知 L2 ETH 网关 + * 存款来执行存款逻辑。 + * @param _from 在 L1 上提取存款的帐户。 + * @param _to 在 L2 上给予存款的帐户。 + * @param _l2Gas 在 L2 上完成存款所需的燃料限制。 + * @param _data 要转发到 L2 的可选数据。此数据 + * 仅为方便外部合约而提供。除了强制执行最大 + * 长度外,这些合约对其内容不提供任何保证。 */ function _initiateETHDeposit( address _from, @@ -652,11 +693,14 @@ contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled { uint32 _l2Gas, bytes memory _data ) internal { - // Construct calldata for finalizeDeposit call + // 为 finalizeDeposit 调用构建 calldata bytes memory message = abi.encodeWithSelector( ``` -跨域信息的工作方式是将信息作为其 calldata 来调用目的地合约。 Solidity 合约总是解释它们的 calldata 符合 [应用程序二进制接口规范](https://docs.soliditylang.org/en/v0.8.12/abi-spec.html)。 Solidity 函数 [`abi. encodeWithSelector`](https://docs.soliditylang.org/en/v0.8.12/units-and-global-variables.html#abi-encoding-and-decoding-functions) 可创建该 calldata。 +跨域消息的工作方式是将消息作为其 calldata 来调用目的地合约。 +Solidity 合约总是根据 +[ABI 规范](https://docs.soliditylang.org/en/v0.8.12/abi-spec.html)来解释它们的 calldata。 +Solidity 函数 [`abi.encodeWithSelector`](https://docs.soliditylang.org/en/v0.8.12/units-and-global-variables.html#abi-encoding-and-decoding-functions) 创建该 calldata。 ```solidity IL2ERC20Bridge.finalizeDeposit.selector, @@ -669,24 +713,24 @@ contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled { ); ``` -此处的信息用来使用下面的参数调用 [`finalizeDeposit` 函数](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/messaging/L2StandardBridge.sol#L141-L148): +这里的消息是使用这些参数调用 [`finalizeDeposit` 函数](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/messaging/L2StandardBridge.sol#L141-L148): -| 参数 | 值 | 意义 | -| ----------- | -------------------------------- | -------------------------------------------------------------------------------- | -| \_l1Token | address(0) | 在第一层上代表以太币(不是 ERC-20 代币)的特殊值 | -| \_l2Token | Lib_PredeployAddresses.OVM_ETH | 乐观解决方案上管理以太币的第二层合约 `0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000`(此合约仅供乐观解决方案内部使用) | -| \_from | \_from | 第一层上发送以太币的地址 | -| \_to | \_to | 第二层上接收以太币的地址 | -| amount | msg.value | 已发送的 wei 数量(已经发送到链桥的 wei) | -| \_data | \_data | 附加到存款的额外日期 | +| 参数 | Value | 含义 | +| ------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| \_l1Token | address(0) | 在 L1 上代表 ETH(不是 ERC-20 代币)的特殊值 | +| \_l2Token | Lib_PredeployAddresses.OVM_ETH | 在 Optimism 上管理 ETH 的 L2 合约,地址为 `0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000`(此合约仅供 Optimism 内部使用) | +| \_from | \_from | 发送 ETH 的 L1 地址 | +| \_to | \_to | 接收 ETH 的 L2 地址 | +| amount | msg.value | 发送的 wei 数量(已经发送到链桥) | +| \_data | \_data | 附加到存款的额外数据 | ```solidity - // Send calldata into L2 + // 将 calldata 发送到 L2 // slither-disable-next-line reentrancy-events sendCrossDomainMessage(l2TokenBridge, _l2Gas, message); ``` -通过跨域信使发送信息。 +通过跨域信使发送消息。 ```solidity // slither-disable-next-line reentrancy-events @@ -701,9 +745,9 @@ contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled { * @inheritdoc IL1ERC20Bridge */ function depositERC20( - . - . - . + . + . + . ) external virtual onlyEOA { _initiateERC20Deposit(_l1Token, _l2Token, msg.sender, msg.sender, _amount, _l2Gas, _data); } @@ -712,9 +756,9 @@ contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled { * @inheritdoc IL1ERC20Bridge */ function depositERC20To( - . - . - . + . + . + . ) external virtual { _initiateERC20Deposit(_l1Token, _l2Token, msg.sender, _to, _amount, _l2Gas, _data); } @@ -724,18 +768,18 @@ contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled { ```solidity /** - * @dev Performs the logic for deposits by informing the L2 Deposited Token - * contract of the deposit and calling a handler to lock the L1 funds. (e.g., transferFrom) + * @dev 通过通知 L2 存款代币 + * 合约存款并调用处理程序锁定 L1 资金来执行存款逻辑。(例如,transferFrom) * - * @param _l1Token Address of the L1 ERC20 we are depositing - * @param _l2Token Address of the L1 respective L2 ERC20 - * @param _from Account to pull the deposit from on L1 - * @param _to Account to give the deposit to on L2 - * @param _amount Amount of the ERC20 to deposit. - * @param _l2Gas Gas limit required to complete the deposit on L2. - * @param _data Optional data to forward to L2. This data is provided - * solely as a convenience for external contracts. Aside from enforcing a maximum - * length, these contracts provide no guarantees about its content. + * @param _l1Token 我们要存入的 L1 ERC20 的地址 + * @param _l2Token L1 对应的 L2 ERC20 的地址 + * @param _from 在 L1 上提取存款的帐户 + * @param _to 在 L2 上给予存款的帐户 + * @param _amount 要存入的 ERC20 的数量。 + * @param _l2Gas 在 L2 上完成存款所需的燃料限制。 + * @param _data 要转发到 L2 的可选数据。此数据 + * 仅为方便外部合约而提供。除了强制执行最大 + * 长度外,这些合约对其内容不提供任何保证。 */ function _initiateERC20Deposit( address _l1Token, @@ -748,26 +792,29 @@ contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled { ) internal { ``` -此函数类似于上面的 `_initiateETHDeposit`,但有一些重要区别。 第一个区别是此函数接收代币地址和转账金额作为参数。 对于以太币,对链桥的调用已经包括将资产转账到链桥帐户 (`msg.value`)。 +此函数类似于上面的 `_initiateETHDeposit`,但有一些重要区别。 +第一个区别是此函数接收代币地址和转账金额作为参数。 +对于 ETH,对链桥的调用已经包括将资产转账到链桥帐户 (`msg.value`)。 ```solidity - // When a deposit is initiated on L1, the L1 Bridge transfers the funds to itself for future - // withdrawals. safeTransferFrom also checks if the contract has code, so this will fail if - // _from is an EOA or address(0). + // 当在 L1 上发起存款时,L1 链桥将资金转移给自己以备将来 + // 取款。safeTransferFrom 还会检查合约是否有代码,因此如果 + // _from 是 EOA 或 address(0),此操作将失败。 // slither-disable-next-line reentrancy-events, reentrancy-benign IERC20(_l1Token).safeTransferFrom(_from, address(this), _amount); ``` -ERC-20 代币的转账过程不同以太币: +ERC-20 代币的转账过程不同于 ETH: -1. 用户 (`_from`) 提供费用让链桥转移适当的代币。 +1. 用户(`_from`)授予链桥许可额度以转移相应的代币。 2. 用户使用代币合约的地址、金额等调用链桥。 3. 在存款过程中,链桥转移代币(给自己)。 -第一步可能和最后两步发生在不同的交易中。 但是,前台运行不是问题,因为调用 `_initiateERC20Deposit` 的两个函数(`depositERC20` 和 `depositERC20To`)只将 `msg.sender` 作为 `_from` 参数调用该函数。 +第一步可能和最后两步发生在不同的交易中。 +但是,抢先交易不是问题,因为调用 `_initiateERC20Deposit` 的两个函数(`depositERC20` 和 `depositERC20To`)只将 `msg.sender` 作为 `_from` 参数调用该函数。 ```solidity - // Construct calldata for _l2Token.finalizeDeposit(_to, _amount) + // 为 _l2Token.finalizeDeposit(_to, _amount) 构建 calldata bytes memory message = abi.encodeWithSelector( IL2ERC20Bridge.finalizeDeposit.selector, _l1Token, @@ -778,7 +825,7 @@ ERC-20 代币的转账过程不同以太币: _data ); - // Send calldata into L2 + // 将 calldata 发送到 L2 // slither-disable-next-line reentrancy-events, reentrancy-benign sendCrossDomainMessage(l2TokenBridge, _l2Gas, message); @@ -786,7 +833,8 @@ ERC-20 代币的转账过程不同以太币: deposits[_l1Token][_l2Token] = deposits[_l1Token][_l2Token] + _amount; ``` -将存入的代币数量添加到 `deposits` 数据结构中。 第二层上可能有多个地址对应于同一个第一层 ERC-20 代币,因此仅使用链桥的第一层 ERC-20 代币余额来跟踪存款是不够的。 +将存入的代币数量添加到 `deposits` 数据结构中。 +L2 上可能有多个地址对应于同一个 L1 ERC-20 代币,因此仅使用链桥的 L1 ERC-20 代币余额来跟踪存款是不够的。 ```solidity @@ -795,7 +843,7 @@ ERC-20 代币的转账过程不同以太币: } /************************* - * Cross-chain Functions * + * 跨链函数 * *************************/ /** @@ -808,20 +856,21 @@ ERC-20 代币的转账过程不同以太币: bytes calldata _data ``` -第二层链桥向第二层跨域信使发送信息,使得第一层跨域信使调用此函数(当然是在[完成信息的交易](https://community.optimism.io/docs/developers/bridge/messaging/#fees-for-l2-%E2%87%92-l1-transactions)在第一层上提交以后)。 +L2 链桥向 L2 跨域信使发送一条消息,这会使 L1 跨域信使调用此函数(当然,前提是[最终确定该消息的交易](https://community.optimism.io/docs/developers/bridge/messaging/#fees-for-l2-%E2%87%92-l1-transactions)已在 L1 上提交)。 ```solidity ) external onlyFromCrossDomainAccount(l2TokenBridge) { ``` -确保这是一个_合法_信息,来自跨域信使并源自第二层代币链桥。 此函数用于从链桥中提取以太币,因此我们必须确保它仅由授权调用者调用。 +确保这是一条_合法_消息,来自跨域信使并源自 L2 代币链桥。 +此函数用于从链桥中提取 ETH,因此我们必须确保它仅由授权调用者调用。 ```solidity // slither-disable-next-line reentrancy-events (bool success, ) = _to.call{ value: _amount }(new bytes(0)); ``` -转移以太币的方式是用 `msg.value` 中 wei 的数量调用接收者。 +转移 ETH 的方式是用 `msg.value` 中的 wei 数量调用接收者。 ```solidity require(success, "TransferHelper::safeTransferETH: ETH transfer failed"); @@ -830,7 +879,7 @@ ERC-20 代币的转账过程不同以太币: emit ETHWithdrawalFinalized(_from, _to, _amount, _data); ``` -触发一个关于提款的事件。 +触发一个关于取款的事件。 ```solidity } @@ -858,7 +907,7 @@ ERC-20 代币的转账过程不同以太币: ```solidity - // When a withdrawal is finalized on L1, the L1 Bridge transfers the funds to the withdrawer + // 当在 L1 上最终确定取款时,L1 链桥将资金转移给取款人 // slither-disable-next-line reentrancy-events IERC20(_l1Token).safeTransfer(_to, _amount); @@ -868,28 +917,35 @@ ERC-20 代币的转账过程不同以太币: /***************************** - * Temporary - Migrating ETH * + * 临时 - 迁移 ETH * *****************************/ /** - * @dev Adds ETH balance to the account. This is meant to allow for ETH - * to be migrated from an old gateway to a new gateway. - * NOTE: This is left for one upgrade only so we are able to receive the migrated ETH from the - * old contract + * @dev 将 ETH 余额添加到帐户。这旨在允许将 ETH + * 从旧网关迁移到新网关。 + * 注意:这只保留一次升级,以便我们能够从 + * 旧合约接收迁移的 ETH */ function donateETH() external payable {} } ``` -对于早期实现的链桥, 当我们从该实现转移到当前实现时,我们必须转移所有资产。 ERC-20 代币可以转移。 但是,要将以太币转账到合约,你需要得到该合约的批准,`donateETH` 就起到这一作用。 +链桥有更早的实现。 +当我们从该实现转移到当前实现时,我们必须转移所有资产。 +ERC-20 代币可以直接移动。 +但是,要将 ETH 转账到合约,你需要得到该合约的批准,`donateETH` 就起到这一作用。 -## 第二层上的 ERC-20 代币 {#erc-20-tokens-on-l2} +## L2 上的 ERC-20 代币 {#erc-20-tokens-on-l2} -为了使 ERC-20 代币适合标准链桥,它需要允许标准链桥并且_只_允许标准链桥铸造代币。 这是必要的,因为链桥需要确保在乐观解决方案上流通的代币数量和锁定在第一层链桥合约内的代币数量相同。 如果第二层上的代币太多,一些用户将无法将他们的资产桥接到第一层。 我们实际上将重新建立[部分准备金银行制度](https://www.investopedia.com/terms/f/fractionalreservebanking.asp),而不是一个受信任的链桥。 如果第一层上的代币太多,其中一些代币将永远锁定在链桥合约中,因为不销毁第二层代币就无法释放它们。 +为了使 ERC-20 代币适合标准链桥,它需要允许标准链桥并且只允许标准链桥铸造代币。 +这是必要的,因为链桥需要确保在 Optimism 上流通的代币数量和锁定在 L1 链桥合约内的代币数量相同。 +如果 L2 上的代币太多,一些用户将无法将他们的资产桥接到 L1。 +我们本质上不是在创建一个可信的链桥,而是在重建[部分准备金银行制度](https://www.investopedia.com/terms/f/fractionalreservebanking.asp)。 +如果 L1 上的代币太多,其中一些代币将永远锁定在链桥合约中,因为不销毁 L2 代币就无法释放它们。 ### IL2StandardERC20 {#il2standarderc20} -第二层上使用标准链桥的每个 ERC-20 代币都需要提供[此接口](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/standards/IL2StandardERC20.sol),它具有标准链桥需要的函数和事件。 +在 L2 上使用标准链桥的每个 ERC-20 代币都需要提供[此接口](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/standards/IL2StandardERC20.sol),其中包含标准链桥所需的函数和事件。 ```solidity // SPDX-License-Identifier: MIT @@ -898,20 +954,24 @@ pragma solidity ^0.8.9; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; ``` -[标准 ERC-20 接口](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol)不包含 `mint` 和 `burn` 函数。 [ERC-20 标准](https://eips.ethereum.org/EIPS/eip-20)不需要这些方法,它未指定创建和销毁代币的机制。 +[标准 ERC-20 接口](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol)不包括 `mint` 和 `burn` 函数。 +[ERC-20 标准](https://eips.ethereum.org/EIPS/eip-20)不需要这些方法,它未指定创建和销毁代币的机制。 ```solidity import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; ``` -[ERC-165 接口](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/IERC165.sol)用于指定一个合约提供哪些函数。 [你可以在此处参阅该标准](https://eips.ethereum.org/EIPS/eip-165)。 +[ERC-165 接口](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/IERC165.sol)用于指定合约提供的函数。 +[你可以在此处阅读该标准](https://eips.ethereum.org/EIPS/eip-165)。 ```solidity interface IL2StandardERC20 is IERC20, IERC165 { function l1Token() external returns (address); ``` -此函数提供桥接到此合约的第一层代币的地址。 请注意,我们在相反方向没有类似函数。 我们需要能够桥接任何第一层代币,无论第二层支持是否在实施计划。 +此函数提供桥接到此合约的 L1 代币的地址。 +请注意,我们在相反方向没有类似函数。 +我们需要能够桥接任何 L1 代币,无论第二层支持是否在实施计划。 ```solidity @@ -924,11 +984,13 @@ interface IL2StandardERC20 is IERC20, IERC165 { } ``` -铸造(创建)和燃烧(销毁)代币的函数和事件。 链桥应该是唯一可以运行这些函数的实体,以确保代币数量正确(等于锁定在第一层上的代币数量)。 +铸造(创建)和销毁(销毁)代币的函数和事件。 +链桥应该是唯一可以运行这些函数的实体,以确保代币数量正确(等于锁定在 L1 上的代币数量)。 ### L2StandardERC20 {#L2StandardERC20} -[这是我们对 `IL2StandardERC20` 接口的实现](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/standards/L2StandardERC20.sol)。 除非你需要某种自定义逻辑,否则你应该使用它。 +[这是我们对 `IL2StandardERC20` 接口的实现](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/standards/L2StandardERC20.sol)。 +除非你需要某种自定义逻辑,否则你应该使用它。 ```solidity // SPDX-License-Identifier: MIT @@ -937,7 +999,8 @@ pragma solidity ^0.8.9; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; ``` -[OpenZeppelin ERC-20 合约](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)。 乐观解决方案不相信重新编写合约,尤其是合约经过严格审计并且需要足够的信任来持有资产时。 +[OpenZeppelin ERC-20 合约](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)。 +Optimism 不相信重新发明轮子,尤其是当轮子经过严格审计并且需要足够的信任来持有资产时。 ```solidity import "./IL2StandardERC20.sol"; @@ -952,10 +1015,10 @@ contract L2StandardERC20 is IL2StandardERC20, ERC20 { ```solidity /** - * @param _l2Bridge Address of the L2 standard bridge. - * @param _l1Token Address of the corresponding L1 token. - * @param _name ERC20 name. - * @param _symbol ERC20 symbol. + * @param _l2Bridge L2 标准链桥的地址。 + * @param _l1Token 相应 L1 代币的地址。 + * @param _name ERC20 名称。 + * @param _symbol ERC20 符号。 */ constructor( address _l2Bridge, @@ -973,7 +1036,7 @@ contract L2StandardERC20 is IL2StandardERC20, ERC20 { ```solidity modifier onlyL2Bridge() { - require(msg.sender == l2Bridge, "Only L2 Bridge can mint and burn"); + require(msg.sender == l2Bridge, "只有 L2 链桥可以铸造和销毁"); _; } @@ -988,11 +1051,12 @@ contract L2StandardERC20 is IL2StandardERC20, ERC20 { } ``` -这是 [ERC-165](https://eips.ethereum.org/EIPS/eip-165) 的工作方式。 每个接口都是许多受支持的函数,并被标识为这些函数的[应用程序二进制接口函数选择器](https://docs.soliditylang.org/en/v0.8.12/abi-spec.html#function-selector)的[异或](https://en.wikipedia.org/wiki/Exclusive_or)。 +这就是 [ERC-165](https://eips.ethereum.org/EIPS/eip-165) 的工作方式。 +每个接口都是由一系列支持的函数组成,并通过这些函数的 [ABI 函数选择器](https://docs.soliditylang.org/en/v0.8.12/abi-spec.html#function-selector)的[异或](https://en.wikipedia.org/wiki/Exclusive_or)运算来识别。 -第二层链桥使用 ERC-165 作为完整性检查机制,确保它发送资产的 ERC-20 合约是 `IL2StandardERC20`。 +L2 链桥使用 ERC-165 作为完整性检查,以确保它发送资产的 ERC-20 合约是 `IL2StandardERC20`。 -**注:**没有任何东西可以阻止流氓合约为 `supportsInterface` 提供虚假应答,所以这是一种完整性检查机制_而不是_安全机制。 +**注意:** 没有任何东西可以阻止恶意合约为 `supportsInterface` 提供虚假应答,所以这是一种完整性检查机制而_不是_安全机制。 ```solidity // slither-disable-next-line external-function @@ -1011,66 +1075,73 @@ contract L2StandardERC20 is IL2StandardERC20, ERC20 { } ``` -只允许第二层链桥铸造和销毁资产。 +只允许 L2 链桥铸造和销毁资产。 -`_mint` 和 `_burn` 实际上是在 [OpenZeppelin ERC-20 合约](/developers/tutorials/erc20-annotated-code/#the-_mint-and-_burn-functions-_mint-and-_burn)中定义的。 该合约只是没有将它们暴露在外部,因为铸造和销毁代币的条件与 ERC-20 使用方式的数量一样多变。 +`_mint` 和 `_burn` 实际上是在 [OpenZeppelin ERC-20 合约](/developers/tutorials/erc20-annotated-code/#the-_mint-and-_burn-functions-_mint-and-_burn)中定义的。 +该合约只是没有将它们暴露在外部,因为铸造和销毁代币的条件与 ERC-20 使用方式的数量一样多变。 -## 第二层链桥代码 {#l2-bridge-code} +## L2 链桥代码 {#l2-bridge-code} -这是在乐观解决方案上运行链桥的代码。 [此合约源自此处](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/messaging/L2StandardBridge.sol)。 +这是在 Optimism 上运行链桥的代码。 +[此合约的源代码在此处](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/messaging/L2StandardBridge.sol)。 ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.9; -/* Interface Imports */ +/* 接口导入 */ import { IL1StandardBridge } from "../../L1/messaging/IL1StandardBridge.sol"; import { IL1ERC20Bridge } from "../../L1/messaging/IL1ERC20Bridge.sol"; import { IL2ERC20Bridge } from "./IL2ERC20Bridge.sol"; ``` -[IL2ERC20Bridge](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/messaging/IL2ERC20Bridge.sol) 接口与我们上面看到的[第一层等效](#IL1ERC20Bridge)接口非常相似。 有两个明显区别: +[IL2ERC20Bridge](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/messaging/IL2ERC20Bridge.sol) 接口与我们上面看到的 [L1 等效接口](#IL1ERC20Bridge)非常相似。 +有两个明显区别: -1. 在第一层上你发起存款并完成提款。 在此处你发起提款并完成存款。 -2. 在第一层上,有必要区分以太币和 ERC-20 代币。 在第二层上,我们可以对两者使用相同的函数,因为在乐观解决方案上的以太币余额会作为地址为 [0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000](https://optimistic.etherscan.io/address/0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000) 的 ERC-20 代币在内部处理。 +1. 在 L1 上你发起存款并完成取款。 + 在此处你发起取款并完成存款。 +2. 在 L1 上,有必要区分 ETH 和 ERC-20 代币。 + 在 L2 上,我们可以对两者使用相同的函数,因为在内部,Optimism 上的 ETH 余额被当作一个地址为 [0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000](https://explorer.optimism.io/address/0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000) 的 ERC-20 代币来处理。 ```solidity -/* Library Imports */ +/* 库导入 */ import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; import { CrossDomainEnabled } from "../../libraries/bridge/CrossDomainEnabled.sol"; import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol"; -/* Contract Imports */ +/* 合约导入 */ import { IL2StandardERC20 } from "../../standards/IL2StandardERC20.sol"; /** * @title L2StandardBridge - * @dev The L2 Standard bridge is a contract which works together with the L1 Standard bridge to - * enable ETH and ERC20 transitions between L1 and L2. - * This contract acts as a minter for new tokens when it hears about deposits into the L1 Standard - * bridge. - * This contract also acts as a burner of the tokens intended for withdrawal, informing the L1 - * bridge to release L1 funds. + * @dev L2 标准链桥是一个与 L1 标准链桥协同工作的合约, + * 用于在 L1 和 L2 之间实现 ETH 和 ERC20 的转换。 + * 当该合约监听到 L1 标准 + * 链桥的存款时,它将充当新代币的铸造者。 + * 该合约还充当用于取款的代币的销毁者,通知 L1 + * 链桥释放 L1 资金。 */ contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled { /******************************** - * External Contract References * + * 外部合约引用 * ********************************/ address public l1TokenBridge; ``` -跟踪第一层链桥的地址。 请注意,与第一层对应项相比,此处我们_需要_该变量。 第一层链桥的地址事先不为人知。 +跟踪 L1 链桥的地址。 +请注意,与 L1 对应项相比,此处我们需要该变量。 +L1 链桥的地址事先不为人知。 ```solidity /*************** - * Constructor * + * 构造函数 * ***************/ /** - * @param _l2CrossDomainMessenger Cross-domain messenger used by this contract. - * @param _l1TokenBridge Address of the L1 bridge deployed to the main chain. + * @param _l2CrossDomainMessenger 此合约使用的跨域信使。 + * @param _l1TokenBridge 部署到主链的 L1 链桥地址。 */ constructor(address _l2CrossDomainMessenger, address _l1TokenBridge) CrossDomainEnabled(_l2CrossDomainMessenger) @@ -1079,7 +1150,7 @@ contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled { } /*************** - * Withdrawing * + * 取款 * ***************/ /** @@ -1108,21 +1179,23 @@ contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled { } ``` -这两个函数发起提款。 请注意,无需指定第一层代币地址。 第二层代币需要告诉我们第一层代币的地址。 +这两个函数发起取款。 +请注意,无需指定 L1 代币地址。 +L2 代币需要告诉我们 L1 代币的地址。 ```solidity /** - * @dev Performs the logic for withdrawals by burning the token and informing - * the L1 token Gateway of the withdrawal. - * @param _l2Token Address of L2 token where withdrawal is initiated. - * @param _from Account to pull the withdrawal from on L2. - * @param _to Account to give the withdrawal to on L1. - * @param _amount Amount of the token to withdraw. - * @param _l1Gas Unused, but included for potential forward compatibility considerations. - * @param _data Optional data to forward to L1. This data is provided - * solely as a convenience for external contracts. Aside from enforcing a maximum - * length, these contracts provide no guarantees about its content. + * @dev 通过销毁代币并通知 + * L1 代币网关取款来执行取款逻辑。 + * @param _l2Token 发起取款的 L2 代币地址。 + * @param _from 在 L2 上提取取款的帐户。 + * @param _to 在 L1 上给予取款的帐户。 + * @param _amount 要取款的代币数量。 + * @param _l1Gas 未使用,但为潜在的向前兼容性考虑而包含。 + * @param _data 要转发到 L1 的可选数据。此数据 + * 仅为方便外部合约而提供。除了强制执行最大 + * 长度外,这些合约对其内容不提供任何保证。 */ function _initiateWithdrawal( address _l2Token, @@ -1132,17 +1205,17 @@ contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled { uint32 _l1Gas, bytes calldata _data ) internal { - // When a withdrawal is initiated, we burn the withdrawer's funds to prevent subsequent L2 - // usage + // 当发起取款时,我们销毁取款人的资金以防止后续的 L2 + // 使用 // slither-disable-next-line reentrancy-events IL2StandardERC20(_l2Token).burn(msg.sender, _amount); ``` -请注意,我们_不_依赖 `_from` 参数,而是依赖更难伪造的 `msg.sender`(据我所知它无法伪造)。 +请注意,我们不依赖 `_from` 参数,而是依赖更难伪造的 `msg.sender`(据我所知它无法伪造)。 ```solidity - // Construct calldata for l1TokenBridge.finalizeERC20Withdrawal(_to, _amount) + // 为 l1TokenBridge.finalizeERC20Withdrawal(_to, _amount) 构建 calldata // slither-disable-next-line reentrancy-events address l1Token = IL2StandardERC20(_l2Token).l1Token(); bytes memory message; @@ -1150,7 +1223,7 @@ contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled { if (_l2Token == Lib_PredeployAddresses.OVM_ETH) { ``` -在第一层上,有必要区分以太币和 ERC-20。 +在 L1 上,有必要区分 ETH 和 ERC-20。 ```solidity message = abi.encodeWithSelector( @@ -1172,7 +1245,7 @@ contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled { ); } - // Send message up to L1 bridge + // 将消息发送到 L1 链桥 // slither-disable-next-line reentrancy-events sendCrossDomainMessage(l1TokenBridge, _l1Gas, message); @@ -1181,7 +1254,7 @@ contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled { } /************************************ - * Cross-chain Function: Depositing * + * 跨链函数:存款 * ************************************/ /** @@ -1202,11 +1275,12 @@ contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled { ) external virtual onlyFromCrossDomainAccount(l1TokenBridge) { ``` -确保信息来源是合法的。 这很重要,因为此函数调用 `_mint` 并且可用于提供链桥在第一层所拥有代币范围外的代币。 +确保消息来源是合法的。 +这很重要,因为此函数调用 `_mint` 并且可用于提供链桥在 L1 所拥有代币范围外的代币。 ```solidity - // Check the target token is compliant and - // verify the deposited token on L1 matches the L2 deposited token representation here + // 检查目标代币是否合规且 + // 验证 L1 上的存款代币与此处的 L2 存款代币表示匹配 if ( // slither-disable-next-line reentrancy-events ERC165Checker.supportsInterface(_l2Token, 0x1d1d8b63) && @@ -1216,12 +1290,12 @@ contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled { 完整性检查: 1. 支持正确的接口 -2. 第二层 ERC-20 合约的第一层地址与第一层的代币来源相符 +2. L2 ERC-20 合约的 L1 地址与 L1 的代币来源相符 ```solidity ) { - // When a deposit is finalized, we credit the account on L2 with the same amount of - // tokens. + // 当存款最终确定时,我们会在 L2 上为该帐户记入相同数量的 + // 代币。 // slither-disable-next-line reentrancy-events IL2StandardERC20(_l2Token).mint(_to, _amount); // slither-disable-next-line reentrancy-events @@ -1235,30 +1309,31 @@ contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled { ```solidity } else { - // Either the L2 token which is being deposited-into disagrees about the correct address - // of its L1 token, or does not support the correct interface. - // This should only happen if there is a malicious L2 token, or if a user somehow - // specified the wrong L2 token address to deposit into. - // In either case, we stop the process here and construct a withdrawal - // message so that users can get their funds out in some cases. - // There is no way to prevent malicious token contracts altogether, but this does limit - // user error and mitigate some forms of malicious contract behavior. + // 存入的 L2 代币要么不同意其 L1 代币的正确地址 + //,要么不支持正确的接口。 + // 这只应在存在恶意的 L2 代币,或者用户以某种方式 + // 指定了错误的 L2 代币地址进行存款时发生。 + // 在任何一种情况下,我们都在此停止该过程并构建一条取款 + // 消息,以便用户在某些情况下可以取回他们的资金。 + // 完全防止恶意代币合约是不可能的,但这确实限制了 + // 用户错误并减轻了某些形式的恶意合约行为。 ``` -如果用户由于使用错误的第二层代币地址犯了可检测到的错误,我们希望取消存款并在第一层上返还代币。 在第二层我们可以做到这一点的唯一方法是等到缺陷质询期到来后发送一条信息,但对用户来说这要比永久失去代币好得多。 +如果用户由于使用错误的 L2 代币地址犯了可检测到的错误,我们希望取消存款并在 L1 上返还代币。 +在 L2 我们可以做到这一点的唯一方法是等到故障挑战期到来后发送一条消息,但对用户来说这要比永久失去代币好得多。 ```solidity bytes memory message = abi.encodeWithSelector( IL1ERC20Bridge.finalizeERC20Withdrawal.selector, _l1Token, _l2Token, - _to, // switched the _to and _from here to bounce back the deposit to the sender + _to, // 在这里切换了 _to 和 _from 以将存款退回给发送者 _from, _amount, _data ); - // Send message up to L1 bridge + // 将消息发送到 L1 链桥 // slither-disable-next-line reentrancy-events sendCrossDomainMessage(l1TokenBridge, 0, message); // slither-disable-next-line reentrancy-events @@ -1268,10 +1343,15 @@ contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled { } ``` -## 总结 {#conclusion} +## 结论 {#conclusion} + +标准链桥是最灵活的资产转移机制。 +然而,由于它非常通用,因而并非总是可供使用的最简便机制。 +特别是对于取款,大多数用户喜欢使用[第三方链桥](https://optimism.io/apps#bridge),这些链桥不用等待挑战期并且不需要进行默克尔证明就能完成取款。 -标准链桥是最灵活的资产转移机制。 然而,由于它非常笼统,因而并非总是可供使用的最简便机制。 特别是对于提款,大多数用户喜欢使用[第三方链桥](https://optimism.io/apps#bridge),这些链桥不用等待质询期并且不需要进行默克尔证明就能完成提款。 +通常,这些链桥的工作方式是在 L1 上拥有资产,而且它们会立即为这些资产提供一小笔费用(通常少于标准链桥取款的燃料费用)。 +当链桥(或运行链桥的人)预计 L1 资产短缺时,它将从 L2 转移足够的资产。 由于这些取款的数额非常庞大,大笔的取款费用经分期摊销后,所占百分比要小得多。 -通常,这些链桥的工作方式是在第一层上拥有资产,而且它们会立即为这些资产提供一小笔费用(通常少于标准链桥提款的燃料费用)。 当链桥(或运行链桥的人)预计第一层资产短缺时,它将从第二层转移足够的资产。 由于这些提款的数额非常庞大,大笔的提款费用经分期摊销后,所占百分比要小得多。 +希望本文能帮助你更多地了解第 2 层如何工作以及如何编写清晰安全的 Solidity 代码。 -希望本文能帮助你更多地了解二层网络如何工作以及如何编写清晰安全的 Solidity 代码。 +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 diff --git a/public/content/translations/zh/developers/tutorials/reverse-engineering-a-contract/index.md b/public/content/translations/zh/developers/tutorials/reverse-engineering-a-contract/index.md index 02f7f9b40ad..b7b2a359e57 100644 --- a/public/content/translations/zh/developers/tutorials/reverse-engineering-a-contract/index.md +++ b/public/content/translations/zh/developers/tutorials/reverse-engineering-a-contract/index.md @@ -1,158 +1,154 @@ --- title: "对合约进行逆向工程" -description: 没有源代码时如何理解合约 +description: "没有源代码时如何理解合约" author: Ori Pomerantz lang: zh -tags: - - "以太坊虚拟机" - - "操作码" - - "逆向工程" - - "反编译器" +tags: [ "evm", "操作码" ] skill: advanced published: 2021-12-30 --- ## 简介 {#introduction} -_区块链上没有秘密_,发生的一切都是持续的、可验证的、公开的。 理想情况下,[应将智能合约的源代码发布到 Etherscan 上进行验证](https://etherscan.io/address/0xb8901acb165ed027e32754e0ffe830802919727f#code)。 然而,[情况并非总是如此](https://etherscan.io/address/0x2510c039cc3b061d79e564b38836da87e31b342f#code)。 在本文中,你将研究一份没有源代码的合约 [`0x2510c039cc3b061d79e564b38836da87e31b342f`](https://etherscan.io/address/0x2510c039cc3b061d79e564b38836da87e31b342f),从而学习如何对合约进行逆向工程。 +_区块链上没有秘密_,发生的一切都是一致、可验证且公开可用的。 理想情况下,[合约的源代码应在 Etherscan 上发布和验证](https://etherscan.io/address/0xb8901acb165ed027e32754e0ffe830802919727f#code)。 然而,[情况并非总是如此](https://etherscan.io/address/0x2510c039cc3b061d79e564b38836da87e31b342f#code)。 在本文中,你将学习如何通过分析一份没有源代码的合约 [`0x2510c039cc3b061d79e564b38836da87e31b342f`](https://etherscan.io/address/0x2510c039cc3b061d79e564b38836da87e31b342f) 来对合约进行逆向工程。 -有一些反编译器,但它们不一定能提供[有用的结果](https://etherscan.io/bytecode-decompiler?a=0x2510c039cc3b061d79e564b38836da87e31b342f)。 在本文中,你将从[操作码](https://github.com/wolflo/evm-opcodes)入手,学习如何对合约手动进行逆向工程并理解合约,以及如何解读反编译器生成的结果。 +反编译器是存在的,但它们并不总能生成[可用的结果](https://etherscan.io/bytecode-decompiler?a=0x2510c039cc3b061d79e564b38836da87e31b342f)。 在本文中,你将学习如何从[操作码](https://github.com/wolflo/evm-opcodes)入手,手动对合约进行逆向工程并理解合约,以及如何解读反编译器的结果。 -为了能够理解本文,你应当已经了解以太坊虚拟机基础知识,并至少对以太坊虚拟机汇编器有几分熟悉。 [点击此处了解这些主题](https://medium.com/mycrypto/the-ethereum-virtual-machine-how-does-it-work-9abac2b7c9e)。 +为了能够理解本文,你应当已经了解 EVM 基础知识,并至少对 EVM 汇编器有几分熟悉。 [你可以在此处阅读关于这些主题的内容](https://medium.com/mycrypto/the-ethereum-virtual-machine-how-does-it-work-9abac2b7c9e)。 ## 准备可执行代码 {#prepare-the-executable-code} -你可以在 Etherscan 上获得合约的操作码,操作如下:点击 **Contract** 选项卡,然后**切换至 Opcodes 视图**。 你将看到每行有一条操作码。 +你可以通过 Etherscan 获取合约的操作码,点击 **Contract** 选项卡,然后点击 **Switch to Opcodes View**。 你将看到每行有一条操作码的视图。 -![Etherscan 上的 Opcode 视图](opcode-view.png) +![Etherscan 的操作码视图](opcode-view.png) -但是,为了能够理解跳转,你需要知道每条操作码在代码中的位置。 为此,一种方式是打开 Google Spreadsheet 并把操作码粘贴到 C 列。[你可以创建这个已制作好的电子表格的副本,从而跳过以下步骤](https://docs.google.com/spreadsheets/d/1tKmTJiNjUwHbW64wCKOSJxHjmh0bAUapt6btUYE7kDA/edit?usp=sharing)。 +但是,为了能够理解跳转,你需要知道每条操作码在代码中的位置。 为此,一种方法是打开一个 Google 电子表格并将操作码粘贴到 C 列。[你可以创建这个已准备好的电子表格的副本,从而跳过以下步骤](https://docs.google.com/spreadsheets/d/1tKmTJiNjUwHbW64wCKOSJxHjmh0bAUapt6btUYE7kDA/edit?usp=sharing)。 -下一步是获得正确的操作码位置,以便我们能够理解跳转。 我们将操作码大小放入 B 列,操作码位置(十六进制形式)放入 A 列。在单元格 `B1` 中输入下面的函数,然后复制并粘贴到 B 列其余单元格中,直到代码结束。 完成后,你就可以隐藏 B 列。 +下一步是获得正确的代码位置,以便我们能够理解跳转。 我们将操作码大小放入 B 列,位置(十六进制形式)放入 A 列。在单元格 `B1` 中输入此函数,然后复制并粘贴到 B 列的其余单元格中,直到代码结束。 完成后,你就可以隐藏 B 列。 ``` =1+IF(REGEXMATCH(C1,"PUSH"),REGEXEXTRACT(C1,"PUSH(\d+)"),0) ``` -首先该函数给操作码增加一个字节,然后查找 `PUSH` 操作码。 Push 操作码比较特殊,因为它们需要额外的字节表示压入的值。 如果操作码是 `PUSH`,我们提取该字节的数值并在函数中增加相应的值。 +首先,该函数为操作码本身添加一个字节,然后查找 `PUSH`。 PUSH 操作码比较特殊,因为它们需要额外的字节表示压入的值。 如果操作码是 `PUSH`,我们就提取字节数并将其加上。 -在 `A1` 单元格中输入第一个偏移量 0。 然后在 `A2` 单元格中,输入下面的函数,并再次将它复制粘贴到 A 列其余他单元格中: +在 `A1` 单元格中输入第一个偏移量,零。 然后在 `A2` 单元格中,输入此函数,并再次将它复制粘贴到 A 列其余单元格中: ``` =dec2hex(hex2dec(A1)+B1) ``` -我们需要此函数提供十六进制值,因为跳转(`JUMP` 和 `JUMPI`)之前压入的值也是十六进制的。 +我们需要此函数来提供十六进制值,因为在跳转(`JUMP` 和 `JUMPI`)之前压入的值是以十六进制形式给出的。 ## 入口点 (0x00) {#the-entry-point-0x00} -智能合约总会从第一个字节开始执行。 下面是代码的开始部分: +合约总会从第一个字节开始执行。 下面是代码的初始部分: -| 偏移量 | 操作码 | 堆栈(在操作码之后) | -| -----: | ------------ | -------------------- | -| 0 | PUSH1 0x80 | 0x80 | -| 2 | PUSH1 0x40 | 0x40, 0x80 | -| 4 | MSTORE | 空 | -| 5 | PUSH1 0x04 | 0x04 | -| 7 | CALLDATASIZE | CALLDATASIZE 0x04 | -| 8 | LT | CALLDATASIZE\<4 | -| 9 | PUSH2 0x005e | 0x5E CALLDATASIZE\<4 | -| C | JUMPI | 空 | +| 偏移量 | 操作码 | 堆栈(在操作码之后) | +| --: | ------------ | ---------------------------------------------- | +| 0 | PUSH1 0x80 | 0x80 | +| 2 | PUSH1 0x40 | 0x40, 0x80 | +| 4 | MSTORE | 空 | +| 5 | PUSH1 0x04 | 0x04 | +| 7 | CALLDATASIZE | CALLDATASIZE 0x04 | +| 8 | LT | CALLDATASIZE\<4 | +| 9 | PUSH2 0x005e | 0x5E CALLDATASIZE\<4 | +| C | JUMPI | 空 | 这段代码执行了两项操作: 1. 将 0x80 作为一个 32 字节的值写入内存地址 0x40-0x5F(0x80 存储在 0x5F,而 0x40-0x5E 全部都是零)。 -2. 读取 calldata 长度。 通常,以太坊合约的调用数据遵循[应用程序二进制接口](https://docs.soliditylang.org/en/v0.8.10/abi-spec.html),该接口至少需要四个字节用于函数选择器。 如果调用数据长度小于四个字节,将跳转至 0x5E。 +2. 读取 calldata 大小。 通常,以太坊合约的调用数据遵循[应用二进制接口 (ABI)](https://docs.soliditylang.org/en/v0.8.10/abi-spec.html),该接口最少需要四个字节的函数选择器。 如果调用数据大小小于四个字节,将跳转至 0x5E。 -![这部分代码的流程图](flowchart-entry.png) +![此部分的流程图](flowchart-entry.png) -### 0x5E 处的处理程序(用于非应用程序二进制接口数据调用) {#the-handler-at-0x5e-for-non-abi-call-data} +### 0x5E 处的处理程序(用于非 ABI 调用数据){#the-handler-at-0x5e-for-non-abi-call-data} -| 偏移量 | 操作码 | -| -----: | ------------ | -| 5E | JUMPDEST | -| 5F | CALLDATASIZE | -| 60 | PUSH2 0x007c | -| 63 | JUMPI | +| 偏移量 | 操作码 | +| --: | ------------ | +| 5E | JUMPDEST | +| 5F | CALLDATASIZE | +| 60 | PUSH2 0x007c | +| 63 | JUMPI | -此代码片段以 `JUMPDEST` 开头。 如果跳转到的操作码不是 `JUMPDEST`,以太坊虚拟机程序会抛出异常。 然后它查看 CALLDATASIZE,如果为“true”(即非零),则跳转到 0x7C。 我们将在下面讨论。 +此代码片段以 `JUMPDEST` 开头。 如果跳转到的操作码不是 `JUMPDEST`,以太坊虚拟机 (EVM) 程序会抛出异常。 然后它查看 CALLDATASIZE,如果为“true”(即非零),则跳转到 0x7C。 我们将在下面讨论。 -| 偏移量 | 操作码 | 堆栈(在操作码之后) | -| -----: | ---------- | ----------------------------------------------------------------- | -| 64 | CALLVALUE | 调用提供的 [Wei](/glossary/#wei)。 在 Solidity 中称为 `msg.value` | -| 65 | PUSH1 0x06 | 6 CALLVALUE | -| 67 | PUSH1 0x00 | 0 6 CALLVALUE | -| 69 | DUP3 | CALLVALUE 0 6 CALLVALUE | -| 6A | DUP3 | 6 CALLVALUE 0 6 CALLVALUE | -| 6B | SLOAD | Storage[6] CALLVALUE 0 6 CALLVALUE | +| 偏移量 | 操作码 | 堆栈(在操作码之后) | +| --: | ---------- | -------------------------------------------------------------------------------------- | +| 64 | CALLVALUE | 调用提供的 [Wei](/glossary/#wei)。 在 Solidity 中称为 `msg.value` | +| 65 | PUSH1 0x06 | 6 CALLVALUE | +| 67 | PUSH1 0x00 | 0 6 CALLVALUE | +| 69 | DUP3 | CALLVALUE 0 6 CALLVALUE | +| 6A | DUP3 | 6 CALLVALUE 0 6 CALLVALUE | +| 6B | SLOAD | Storage[6] CALLVALUE 0 6 CALLVALUE | -因此,当没有调用数据时,我们读取 Storage [6] 中的值。 我们还不知道这个值是什么,但我们可以查找合约收到的没有调用数据的交易。 仅转账以太币而没有任何调用数据(因此没有方法)的交易在 Etherscan 中具有方法 `Transfer`。 事实上,[合约收到的第一笔交易](https://etherscan.io/tx/0xeec75287a583c36bcc7ca87685ab41603494516a0f5986d18de96c8e630762e7)就是转账。 +因此,当没有调用数据时,我们读取 Storage[6] 中的值。 我们还不知道这个值是什么,但我们可以查找合约收到的没有调用数据的交易。 仅转账 ETH 而没有任何调用数据(因此没有方法)的交易在 Etherscan 中的方法为“`Transfer`”。 事实上,[该合约收到的第一笔交易](https://etherscan.io/tx/0xeec75287a583c36bcc7ca87685ab41603494516a0f5986d18de96c8e630762e7)是一笔转账。 -如果我们查看该交易并点击 **Click to see More**,我们会看到调用数据(称为输入数据)实际上是空的 (`0x`)。 另请注意,值为 1.559 ETH,稍后将介绍。 +如果我们查看该交易并点击\*\*“Click to see More”\*\*(点击查看更多),我们会看到调用数据(称为输入数据)实际上是空的 (`0x`)。 另请注意,值为 1.559 ETH,这与稍后内容有关。 -![调用数据是空的](calldata-empty.png) +![调用数据为空](calldata-empty.png) -接下来,点击 **State** 选项卡并展开我们正在进行逆向工程的合约 (0x2510...)。 可以看到在交易过程中 `Storage[6]` 确实发生了变化,如果你将十六进制更改为**数值**,就会看到该值变成了 1,559,000,000,000,000,000(为了清楚起见,这里添加了逗号),即转账数额(以 wei 为单位),对应于下一个合约价值。 +接下来,点击\*\*“State”**(状态)选项卡并展开我们正在进行逆向工程的合约 (0x2510...)。 可以看到在交易过程中 `Storage[6]` 确实发生了变化,如果你将“Hex”更改为**“Number”\*\*(数值),就会看到该值变成了 1,559,000,000,000,000,000,即转账数额(以 wei 为单位,我为了清楚起见添加了逗号),对应于下一个合约价值。 ![Storage[6] 中的变化](storage6.png) -如果我们查看同一段时间内[其他 `Transfer` 交易](https://etherscan.io/tx/0xf708d306de39c422472f43cb975d97b66fd5d6a6863db627067167cbf93d84d1#statechange)引起的状态变化,就会发现 `Storage[6]` 跟踪一段时间内的合约价值。 现在,我们将其称为 `Value*`。 星号 (`*`) 提醒我们,我们还不*知道*这个变量的作用,但它不会只是跟踪合约价值,因为当你可以使用 `ADDRESS BALANCE` 获取帐户余额时,无需使用非常昂贵的存储。 第一个操作码压入合约地址。 第二个操作码读取堆栈顶部的地址并将其替换为该地址的余额。 +如果我们在[同一时期的其他 `Transfer` 交易](https://etherscan.io/tx/0xf708d306de39c422472f43cb975d97b66fd5d6a6863db627067167cbf93d84d1#statechange)引起的状态变化中查看,会发现 `Storage[6]` 在一段时间内跟踪了合约的价值。 现在,我们将其称为 Value\*。 星号 (\*) 提醒我们,我们还_不_知道这个变量的作用,但它不会只是跟踪合约价值,因为当你可以使用 `ADDRESS BALANCE` 获取帐户余额时,无需使用非常昂贵的存储。 第一个操作码压入合约自己的地址。 第二个操作码读取堆栈顶部的地址并将其替换为该地址的余额。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | ------------------------------------------- | -| 6C | PUSH2 0x0075 | 0x75 Value\* CALLVALUE 0 6 CALLVALUE | -| 6F | SWAP2 | CALLVALUE Value\* 0x75 0 6 CALLVALUE | -| 70 | SWAP1 | Value\* CALLVALUE 0x75 0 6 CALLVALUE | -| 71 | PUSH2 0x01a7 | 0x01A7 Value\* CALLVALUE 0x75 0 6 CALLVALUE | -| 74 | JUMP | | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------ | ------------------------------------------- | +| 6C | PUSH2 0x0075 | 0x75 Value\* CALLVALUE 0 6 CALLVALUE | +| 6F | SWAP2 | CALLVALUE Value\* 0x75 0 6 CALLVALUE | +| 70 | SWAP1 | Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 71 | PUSH2 0x01a7 | 0x01A7 Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 74 | JUMP | | 我们将继续在跳转目标处跟踪此代码。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ---------- | ----------------------------------------------------------- | -| 1A7 | JUMPDEST | Value\* CALLVALUE 0x75 0 6 CALLVALUE | -| 1A8 | PUSH1 0x00 | 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | -| 1AA | DUP3 | CALLVALUE 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | -| 1AB | NOT | 2^256-CALLVALUE-1 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 偏移量 | 操作码 | 堆栈 | +| --: | ---------- | ----------------------------------------------------------- | +| 1A7 | JUMPDEST | Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 1A8 | PUSH1 0x00 | 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 1AA | DUP3 | CALLVALUE 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 1AB | NOT | 2^256-CALLVALUE-1 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | `NOT` 是按位运算符,因此它反转调用值中每一位的值。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | --------------------------------------------------------------------------- | -| 1AC | DUP3 | Value\* 2^256-CALLVALUE-1 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | -| 1AD | GT | Value\*>2^256-CALLVALUE-1 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | -| 1AE | ISZERO | Value\*\<=2^256-CALLVALUE-1 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | -| 1AF | PUSH2 0x01df | 0x01DF Value\*\<=2^256-CALLVALUE-1 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | -| 1B2 | JUMPI | | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------ | ------------------------------------------------------------------------------------------------------ | +| 1AC | DUP3 | Value\* 2^256-CALLVALUE-1 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 1AD | GT | Value\*>2^256-CALLVALUE-1 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 1AE | ISZERO | Value\*\<=2^256-CALLVALUE-1 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 1AF | PUSH2 0x01df | 0x01DF Value\*\<=2^256-CALLVALUE-1 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 1B2 | JUMPI | | -如果 `Value*` 小于 2^256-CALLVALUE-1 或等于它,则跳转。 这看起来像是防止溢出的逻辑。 事实上,我们看到在偏移量 0x01DE 处进行了一些无意义的操作(例如,写入内存后马上删除)后,如果检测到溢出,合约将回滚,这是正常行为。 +如果 `Value*` 小于或等于 2^256-CALLVALUE-1,则跳转。 这看起来像是防止溢出的逻辑。 事实上,我们看到在偏移量 0x01DE 处进行了一些无意义的操作(例如,写入内存后马上删除)后,如果检测到溢出,合约将回滚,这是正常行为。 -请注意,这种溢出极不可能发生,因为它需要调用值加上 `Value*`,与 2^256 wei 相当,大约 10^59 个以太币。 [在撰写本文时,以太币的总供应量不到两亿个](https://etherscan.io/stat/supply)。 +请注意,这种溢出极不可能发生,因为它需要调用值加上 `Value*`,与 2^256 wei 相当,大约 10^59 个 ETH。 [在撰写本文时,ETH 的总供应量不到两亿个](https://etherscan.io/stat/supply)。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | -------- | ----------------------------------------- | -| 1DF | JUMPDEST | 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | -| 1E0 | POP | Value\* CALLVALUE 0x75 0 6 CALLVALUE | -| 1E1 | ADD | Value\*+CALLVALUE 0x75 0 6 CALLVALUE | -| 1E2 | SWAP1 | 0x75 Value\*+CALLVALUE 0 6 CALLVALUE | -| 1E3 | JUMP | | +| 偏移量 | 操作码 | 堆栈 | +| --: | -------- | ----------------------------------------- | +| 1DF | JUMPDEST | 0x00 Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 1E0 | POP | Value\* CALLVALUE 0x75 0 6 CALLVALUE | +| 1E1 | ADD | Value\*+CALLVALUE 0x75 0 6 CALLVALUE | +| 1E2 | SWAP1 | 0x75 Value\*+CALLVALUE 0 6 CALLVALUE | +| 1E3 | JUMP | | 如果执行到此处,获取 `Value* + CALLVALUE` 并跳转到偏移量 0x75 处。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | -------- | ------------------------------- | -| 75 | JUMPDEST | Value\*+CALLVALUE 0 6 CALLVALUE | -| 76 | SWAP1 | 0 Value\*+CALLVALUE 6 CALLVALUE | -| 77 | SWAP2 | 6 Value\*+CALLVALUE 0 CALLVALUE | -| 78 | SSTORE | 0 CALLVALUE | +| 偏移量 | 操作码 | 堆栈 | +| --: | -------- | ------------------------------- | +| 75 | JUMPDEST | Value\*+CALLVALUE 0 6 CALLVALUE | +| 76 | SWAP1 | 0 Value\*+CALLVALUE 6 CALLVALUE | +| 77 | SWAP2 | 6 Value\*+CALLVALUE 0 CALLVALUE | +| 78 | SSTORE | 0 CALLVALUE | -如果执行到此处(要求调用数据为空),我们将调用值添加到 `Value*`。 这与我们所说的 `Transfer` 交易的操作是一致的。 +如果执行到此处(要求调用数据为空),我们将调用值添加到 `Value*`。 这与我们所说的 `Transfer` 交易所做的事情是一致的。 -| 偏移量 | 操作码 | -| -----: | ------ | -| 79 | POP | -| 7A | POP | -| 7B | STOP | +| 偏移量 | 操作码 | +| --: | ---- | +| 79 | POP | +| 7A | POP | +| 7B | STOP | 最后,清除堆栈(并非必需)并表明交易成功结束。 @@ -160,7 +156,7 @@ _区块链上没有秘密_,发生的一切都是持续的、可验证的、公 ![入口点流程图](flowchart-entry.png) -## 0x7C 的处理程序 {#the-handler-at-0x7c} +## 0x7C 处的处理程序 {#the-handler-at-0x7c} 我特意没有将此处理程序的作用写入标题中。 重点不是教你这个特定的合约如何运作,而是如何对合约进行逆向工程。 你和我一样,都通过观察代码了解该合约的作用。 @@ -169,86 +165,86 @@ _区块链上没有秘密_,发生的一切都是持续的、可验证的、公 - 如果调用数据包含 1、2 或 3 个字节(从偏移量 0x63 处开始) - 如果方法签名未知(从偏移量 0x42 和 0x5D 处开始) -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | -------------------- | -| 7C | JUMPDEST | | -| 7D | PUSH1 0x00 | 0x00 | -| 7F | PUSH2 0x009d | 0x9D 0x00 | -| 82 | PUSH1 0x03 | 0x03 0x9D 0x00 | -| 84 | SLOAD | Storage[3] 0x9D 0x00 | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------ | ------------------------------------------------------------------------ | +| 7C | JUMPDEST | | +| 7D | PUSH1 0x00 | 0x00 | +| 7F | PUSH2 0x009d | 0x9D 0x00 | +| 82 | PUSH1 0x03 | 0x03 0x9D 0x00 | +| 84 | SLOAD | Storage[3] 0x9D 0x00 | 这是另一个存储单元,我在任何交易中都找不到它,所以很难知道它的含义。 下面的代码将使其更明确。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------------------------------------------- | ------------------------------- | -| 85 | PUSH20 0xffffffffffffffffffffffffffffffffffffffff | 0xff....ff Storage[3] 0x9D 0x00 | -| 9A | AND | Storage[3]-as-address 0x9D 0x00 | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| 85 | PUSH20 0xffffffffffffffffffffffffffffffffffffffff | 0xff....ff Storage[3] 0x9D 0x00 | +| 9A | AND | Storage[3]-as-address 0x9D 0x00 | 上面的操作码将我们从 Storage[3] 读取的值截断为 160 位,即以太坊地址的长度。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------ | ------------------------------- | -| 9B | SWAP1 | 0x9D Storage[3]-as-address 0x00 | -| 9C | JUMP | Storage[3]-as-address 0x00 | +| 偏移量 | 操作码 | 堆栈 | +| --: | ----- | ----------------------------------------------------------------------------------- | +| 9B | SWAP1 | 0x9D Storage[3]-as-address 0x00 | +| 9C | JUMP | Storage[3]-as-address 0x00 | 上面的跳转是多余的,因为我们要执行下一个操作码。 这个代码远不如它本应该的那样具有燃料效率。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ---------- | ------------------------------- | -| 9D | JUMPDEST | Storage[3]-as-address 0x00 | -| 9E | SWAP1 | 0x00 Storage[3]-as-address | -| 9F | POP | Storage[3]-as-address | -| A0 | PUSH1 0x40 | 0x40 Storage[3]-as-address | -| A2 | MLOAD | Mem[0x40] Storage[3]-as-address | +| 偏移量 | 操作码 | 堆栈 | +| --: | ---------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| 9D | JUMPDEST | Storage[3]-as-address 0x00 | +| 9E | SWAP1 | 0x00 Storage[3]-as-address | +| 9F | POP | Storage[3]-as-address | +| A0 | PUSH1 0x40 | 0x40 Storage[3]-as-address | +| A2 | MLOAD | Mem[0x40] Storage[3]-as-address | 在代码的最开始,我们将 Mem[0x40] 设置为 0x80。 如果我们在后面部分查找 0x40,会发现我们没有更改它 - 所以我们可以假设它是 0x80。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | ------------------------------------------------- | -| A3 | CALLDATASIZE | CALLDATASIZE 0x80 Storage[3]-as-address | -| A4 | PUSH1 0x00 | 0x00 CALLDATASIZE 0x80 Storage[3]-as-address | -| A6 | DUP3 | 0x80 0x00 CALLDATASIZE 0x80 Storage[3]-as-address | -| A7 | CALLDATACOPY | 0x80 Storage[3]-as-address | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------ | ----------------------------------------------------------------------------------------------------- | +| A3 | CALLDATASIZE | CALLDATASIZE 0x80 Storage[3]-as-address | +| A4 | PUSH1 0x00 | 0x00 CALLDATASIZE 0x80 Storage[3]-as-address | +| A6 | DUP3 | 0x80 0x00 CALLDATASIZE 0x80 Storage[3]-as-address | +| A7 | CALLDATACOPY | 0x80 Storage[3]-as-address | 将所有调用数据复制到内存,从 0x80 处开始。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------- | -------------------------------------------------------------------------------- | -| A8 | PUSH1 0x00 | 0x00 0x80 Storage[3]-as-address | -| AA | DUP1 | 0x00 0x00 0x80 Storage[3]-as-address | -| AB | CALLDATASIZE | CALLDATASIZE 0x00 0x00 0x80 Storage[3]-as-address | -| AC | DUP4 | 0x80 CALLDATASIZE 0x00 0x00 0x80 Storage[3]-as-address | -| AD | DUP6 | Storage[3]-as-address 0x80 CALLDATASIZE 0x00 0x00 0x80 Storage[3]-as-address | -| AE | GAS | GAS Storage[3]-as-address 0x80 CALLDATASIZE 0x00 0x00 0x80 Storage[3]-as-address | -| AF | DELEGATE_CALL | | +| 偏移量 | 操作码 | 堆栈 | +| --: | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| A8 | PUSH1 0x00 | 0x00 0x80 Storage[3]-as-address | +| AA | DUP1 | 0x00 0x00 0x80 Storage[3]-as-address | +| AB | CALLDATASIZE | CALLDATASIZE 0x00 0x00 0x80 Storage[3]-as-address | +| AC | DUP4 | 0x80 CALLDATASIZE 0x00 0x00 0x80 Storage[3]-as-address | +| AD | DUP6 | Storage[3]-as-address 0x80 CALLDATASIZE 0x00 0x00 0x80 Storage[3]-as-address | +| AE | GAS | GAS Storage[3]-as-address 0x80 CALLDATASIZE 0x00 0x00 0x80 Storage[3]-as-address | +| AF | DELEGATE_CALL | | 现在事情清楚了很多。 此合约可以作为[代理](https://blog.openzeppelin.com/proxy-patterns/),调用 Storage[3] 中的地址来完成真实的工作。 `DELEGATE_CALL` 调用另一个合约,但它保存在同一个存储中。 这意味着我们代理的受委托合约访问相同的存储空间。 调用的参数如下: - _燃料_:所有剩余的燃料 - _调用地址_:Storage[3] 做为地址 - _调用数据_:从 0x80 开始的 CALLDATASIZE 字节数,0x80 是我们存入初始调用数据的位置 -- _返回数据_:None (0x00 - 0x00) 我们将通过其他方式获取返回数据(见下文) +- _返回数据_:无 (0x00 - 0x00) 我们将通过其他方式获取返回数据(见下文) -| 偏移量 | 操作码 | 堆栈 | -| -----: | -------------- | --------------------------------------------------------------------------------------------- | -| B0 | RETURNDATASIZE | RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| B1 | DUP1 | RETURNDATASIZE RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| B2 | PUSH1 0x00 | 0x00 RETURNDATASIZE RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| B4 | DUP5 | 0x80 0x00 RETURNDATASIZE RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| B5 | RETURNDATACOPY | RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| 偏移量 | 操作码 | 堆栈 | +| --: | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| B0 | RETURNDATASIZE | RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| B1 | DUP1 | RETURNDATASIZE RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| B2 | PUSH1 0x00 | 0x00 RETURNDATASIZE RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| B4 | DUP5 | 0x80 0x00 RETURNDATASIZE RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| B5 | RETURNDATACOPY | RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | 此处,我们将所有返回数据复制到从 0x80 开始的内存缓冲区。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | ---------------------------------------------------------------------------------------------------------------------------- | -| B6 | DUP2 | (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| B7 | DUP1 | (((call success/failure))) (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| B8 | ISZERO | (((did the call fail))) (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| B9 | PUSH2 0x00c0 | 0xC0 (((did the call fail))) (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| BC | JUMPI | (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| BD | DUP2 | RETURNDATASIZE (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| BE | DUP5 | 0x80 RETURNDATASIZE (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| BF | RETURN | | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| B6 | DUP2 | (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| B7 | DUP1 | (((call success/failure))) (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| B8 | ISZERO | (((did the call fail))) (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| B9 | PUSH2 0x00c0 | 0xC0 (((did the call fail))) (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| BC | JUMPI | (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| BD | DUP2 | RETURNDATASIZE (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| BE | DUP5 | 0x80 RETURNDATASIZE (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| BF | RETURN | | 因此在调用之后,我们将返回数据复制到缓冲区 0x80 - 0x80+RETURNDATASIZE,如果调用成功,我们将准确地 `RETURN` 该缓冲区。 @@ -256,106 +252,106 @@ _区块链上没有秘密_,发生的一切都是持续的、可验证的、公 如果执行到此处,即到达 0xC0,意味着我们调用的合约已回滚。 由于我们只是该合约的代理,我们希望返回相同的数据并且也回滚。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | -------- | ------------------------------------------------------------------------------------------------------------------- | -| C0 | JUMPDEST | (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| C1 | DUP2 | RETURNDATASIZE (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| C2 | DUP5 | 0x80 RETURNDATASIZE (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | -| C3 | REVERT | | +| 偏移量 | 操作码 | 堆栈 | +| --: | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| C0 | JUMPDEST | (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| C1 | DUP2 | RETURNDATASIZE (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| C2 | DUP5 | 0x80 RETURNDATASIZE (((call success/failure))) RETURNDATASIZE (((call success/failure))) 0x80 Storage[3]-as-address | +| C3 | REVERT | | 所以我们 `REVERT` 至我们之前用于 `RETURN` 的相同缓冲区:0x80 - 0x80+RETURNDATASIZE ![调用代理流程图](flowchart-proxy.png) -## 应用程序二进制接口调用 {#abi-calls} +## ABI 调用 {#abi-calls} -如果调用数据长度为四个字节或更多,这可能是一个有效的应用程序二进制接口调用。 +如果调用数据大小为四个字节或更多,这可能是一个有效的 ABI 调用。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | ------------------------------------------------- | -| D | PUSH1 0x00 | 0x00 | -| F | CALLDATALOAD | (((First word (256 bits) of the call data))) | -| 10 | PUSH1 0xe0 | 0xE0 (((First word (256 bits) of the call data))) | -| 12 | SHR | (((first 32 bits (4 bytes) of the call data))) | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------ | -------------------------------------------------------------------------------------------------------- | +| D | PUSH1 0x00 | 0x00 | +| F | CALLDATALOAD | (((调用数据的第一个字 (256 位)))) | +| 10 | PUSH1 0xe0 | 0xE0 (((调用数据的第一个字 (256 位)))) | +| 12 | SHR | (((调用数据的前 32 位 (4 字节)))) | -Etherscan 指出 `1C` 是一个未知操作码,因为[它是在 Etherscan 编写此功能后添加的](https://eips.ethereum.org/EIPS/eip-145)并且还没有更新。 [最新操作码表](https://github.com/wolflo/evm-opcodes)告诉我们这是右移操作。 +Etherscan 指出 `1C` 是一个未知操作码,因为它是在 Etherscan 编写此功能[之后添加的](https://eips.ethereum.org/EIPS/eip-145)并且他们还没有更新。 [最新的操作码表](https://github.com/wolflo/evm-opcodes)显示这是右移 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ---------------- | -------------------------------------------------------------------------------------------------------- | -| 13 | DUP1 | (((呼叫数据的前 32 位(4 字节))))(((呼叫数据的前 32 位(4 字节)))) | -| 14 | PUSH4 0x3cd8045e | 0x3CD8045E (((first 32 bits (4 bytes) of the call data))) (((first 32 bits (4 bytes) of the call data))) | -| 19 | GT | 0x3CD8045E>first-32-bits-of-the-call-data (((first 32 bits (4 bytes) of the call data))) | -| 1A | PUSH2 0x0043 | 0x43 0x3CD8045E>first-32-bits-of-the-call-data (((first 32 bits (4 bytes) of the call data))) | -| 1D | JUMPI | (((first 32 bits (4 bytes) of the call data))) | +| 偏移量 | 操作码 | 堆栈 | +| --: | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 13 | DUP1 | (((调用数据的前 32 位 (4 字节)))) (((调用数据的前 32 位 (4 字节)))) | +| 14 | PUSH4 0x3cd8045e | 0x3CD8045E (((调用数据的前 32 位 (4 字节)))) (((调用数据的前 32 位 (4 字节)))) | +| 19 | GT | 0x3CD8045E>first-32-bits-of-the-call-data (((调用数据的前 32 位 (4 字节)))) | +| 1A | PUSH2 0x0043 | 0x43 0x3CD8045E>first-32-bits-of-the-call-data (((调用数据的前 32 位 (4 字节)))) | +| 1D | JUMPI | (((调用数据的前 32 位 (4 字节)))) | -通过像这样将方法签名匹配测试一分为二,平均可以省去一半的测试。 紧随其后的代码和 0x43 处的代码遵循相同的模式:`DUP1` 调用数据的前 32 位,`PUSH4 (((method signature> `,运行 `EQ` 检查是否相等,然后如果方法签名匹配,`JUMPI`。 以下是方法签名、它们的地址以及[相应的方法定义](https://www.4byte.directory/)(如果已知): +通过像这样将方法签名匹配测试一分为二,平均可以省去一半的测试。 紧随其后的代码和 0x43 处的代码遵循相同的模式:`DUP1` 调用数据的前 32 位,`PUSH4 (((方法签名))`,运行 `EQ` 检查是否相等,然后如果方法签名匹配,`JUMPI`。 以下是方法签名、它们的地址以及[相应的方法定义](https://www.4byte.directory/)(如果已知): -| 方法 | 方法签名 | 跳转到的偏移量 | -| -------------------------------------------------------------------------------------- | ---------- | -------------- | -| [splitter()](https://www.4byte.directory/signatures/?bytes4_signature=0x3cd8045e) | 0x3cd8045e | 0x0103 | -| ??? | 0x81e580d3 | 0x0138 | -| [currentWindow()](https://www.4byte.directory/signatures/?bytes4_signature=0xba0bafb4) | 0xba0bafb4 | 0x0158 | -| ??? | 0x1f135823 | 0x00C4 | -| [merkleRoot()](https://www.4byte.directory/signatures/?bytes4_signature=0x2eb4a7ab) | 0x2eb4a7ab | 0x00ED | +| 方法 | 方法签名 | 跳转到的偏移量 | +| --------------------------------------------------------------------------------------------------------- | ---------- | ------- | +| [splitter()](https://www.4byte.directory/signatures/?bytes4_signature=0x3cd8045e) | 0x3cd8045e | 0x0103 | +| ??? | 0x81e580d3 | 0x0138 | +| [currentWindow()](https://www.4byte.directory/signatures/?bytes4_signature=0xba0bafb4) | 0xba0bafb4 | 0x0158 | +| ??? | 0x1f135823 | 0x00C4 | +| [merkleRoot()](https://www.4byte.directory/signatures/?bytes4_signature=0x2eb4a7ab) | 0x2eb4a7ab | 0x00ED | -如果没有找到匹配项,代码跳转到 [0x7C 处的代理处理程序](#the-handler-at-0x7c),指望我们作为代理的合约有匹配项。 +如果没有找到匹配项,代码会跳转到[位于 0x7C 的代理处理程序](#the-handler-at-0x7c),寄希望于我们所代理的合约有匹配项。 -![应用程序二进制接口调用流程图](flowchart-abi.png) +![ABI 调用流程图](flowchart-abi.png) ## splitter() {#splitter} -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | ----------------------------- | -| 103 | JUMPDEST | | -| 104 | CALLVALUE | CALLVALUE | -| 105 | DUP1 | CALLVALUE CALLVALUE | -| 106 | ISZERO | CALLVALUE 0 CALLVALUE | -| 107 | PUSH2 0x01df | 0x010F CALLVALUE==0 CALLVALUE | -| 10A | JUMPI | CALLVALUE | -| 10B | PUSH1 0x00 | 0x00 CALLVALUE | -| 10D | DUP1 | 0x00 0x00 CALLValUE | -| 10E | REVERT | | - -此函数首先检查调用没有发送任何以太币。 此函数不是 [`payable`](https://solidity-by-example.org/payable/)。 如果有人向我们发送了以太币,而那肯定是误发,我们希望 `REVERT` 以避免将此以太币放入他们无法取回的位置。 - -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------------------------------------------- | --------------------------------------------------------------------------- | -| 10F | JUMPDEST | | -| 110 | POP | | -| 111 | PUSH1 0x03 | 0x03 | -| 113 | SLOAD | (((Storage[3] a.k.a the contract for which we are a proxy))) | -| 114 | PUSH1 0x40 | 0x40 (((Storage[3] a.k.a the contract for which we are a proxy))) | -| 116 | MLOAD | 0x80 (((Storage[3] a.k.a the contract for which we are a proxy))) | -| 117 | PUSH20 0xffffffffffffffffffffffffffffffffffffffff | 0xFF...FF 0x80 (((Storage[3] a.k.a the contract for which we are a proxy))) | -| 12C | SWAP1 | 0x80 0xFF...FF (((Storage[3] a.k.a the contract for which we are a proxy))) | -| 12D | SWAP2 | (((Storage[3] a.k.a the contract for which we are a proxy))) 0xFF...FF 0x80 | -| 12E | AND | ProxyAddr 0x80 | -| 12F | DUP2 | 0x80 ProxyAddr 0x80 | -| 130 | MSTORE | 0x80 | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------ | ----------------------------- | +| 103 | JUMPDEST | | +| 104 | CALLVALUE | CALLVALUE | +| 105 | DUP1 | CALLVALUE CALLVALUE | +| 106 | ISZERO | CALLVALUE==0 CALLVALUE | +| 107 | PUSH2 0x010f | 0x010F CALLVALUE==0 CALLVALUE | +| 10A | JUMPI | CALLVALUE | +| 10B | PUSH1 0x00 | 0x00 CALLVALUE | +| 10D | DUP1 | 0x00 0x00 CALLVALUE | +| 10E | REVERT | | + +此函数首先检查调用没有发送任何 ETH。 此函数不是 [`payable`](https://solidity-by-example.org/payable/)。 如果有人向我们发送了 ETH,而那肯定是误发,我们希望 `REVERT` 以避免将此 ETH 放入他们无法取回的位置。 + +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 10F | JUMPDEST | | +| 110 | POP | | +| 111 | PUSH1 0x03 | 0x03 | +| 113 | SLOAD | (((Storage[3] 又名我们作为代理的合约))) | +| 114 | PUSH1 0x40 | 0x40 (((Storage[3] 又名我们作为代理的合约))) | +| 116 | MLOAD | 0x80 (((Storage[3] 又名我们作为代理的合约))) | +| 117 | PUSH20 0xffffffffffffffffffffffffffffffffffffffff | 0xFF...FF 0x80 (((Storage[3] 又名我们作为代理的合约))) | +| 12C | SWAP1 | 0x80 0xFF...FF (((Storage[3] 又名我们作为代理的合约))) | +| 12D | SWAP2 | (((Storage[3] 又名我们作为代理的合约))) 0xFF...FF 0x80 | +| 12E | AND | ProxyAddr 0x80 | +| 12F | DUP2 | 0x80 ProxyAddr 0x80 | +| 130 | MSTORE | 0x80 | 0x80 现在包含代理地址 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | --------- | -| 131 | PUSH1 0x20 | 0x20 0x80 | -| 133 | ADD | 0xA0 | -| 134 | PUSH2 0x00e4 | 0xE4 0xA0 | -| 137 | JUMP | 0xA0 | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------ | --------- | +| 131 | PUSH1 0x20 | 0x20 0x80 | +| 133 | ADD | 0xA0 | +| 134 | PUSH2 0x00e4 | 0xE4 0xA0 | +| 137 | JUMP | 0xA0 | ### E4 代码 {#the-e4-code} 这是我们第一次看到这些行,但它们与其他方法是共享的(见下文)。 所以我们将调用堆栈 X 中的值,记住在 `splitter()` 中此 X 的值是 0xA0。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ---------- | ----------- | -| E4 | JUMPDEST | X | -| E5 | PUSH1 0x40 | 0x40 X | -| E7 | MLOAD | 0x80 X | -| E8 | DUP1 | 0x80 0x80 X | -| E9 | SWAP2 | X 0x80 0x80 | -| EA | SUB | X-0x80 0x80 | -| EB | SWAP1 | 0x80 X-0x80 | -| EC | RETURN | | +| 偏移量 | 操作码 | 堆栈 | +| --: | ---------- | ----------- | +| E4 | JUMPDEST | X | +| E5 | PUSH1 0x40 | 0x40 X | +| E7 | MLOAD | 0x80 X | +| E8 | DUP1 | 0x80 0x80 X | +| E9 | SWAP2 | X 0x80 0x80 | +| EA | SUB | X-0x80 0x80 | +| EB | SWAP1 | 0x80 X-0x80 | +| EC | RETURN | | 因此,此代码接收堆栈 (X) 中一个内存指针,并导致合约 `RETURN` 缓冲区 0x80 - X。 @@ -363,224 +359,224 @@ Etherscan 指出 `1C` 是一个未知操作码,因为[它是在 Etherscan 编 ## currentWindow() {#currentwindow} -偏移量 0x158-0x163 中的代码与我们在 `splitter()` 中看到的 0x103-0x10E 中的代码相同(除 `JUMPI` 目标地址外),因此我们知道 `currentWindow ()` 也不是 `payable`。 +偏移量 0x158-0x163 中的代码与我们在 `splitter()` 中看到的 0x103-0x10E 中的代码相同(除 `JUMPI` 目标地址外),因此我们知道 `currentWindow()` 也不是 `payable`。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | -------------------- | -| 164 | JUMPDEST | | -| 165 | POP | | -| 166 | PUSH2 0x00da | 0xDA | -| 169 | PUSH1 0x01 | 0x01 0xDA | -| 16B | SLOAD | Storage[1] 0xDA | -| 16C | DUP2 | 0xDA Storage[1] 0xDA | -| 16D | JUMP | Storage[1] 0xDA | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------ | ------------------------------------------------------------------------ | +| 164 | JUMPDEST | | +| 165 | POP | | +| 166 | PUSH2 0x00da | 0xDA | +| 169 | PUSH1 0x01 | 0x01 0xDA | +| 16B | SLOAD | Storage[1] 0xDA | +| 16C | DUP2 | 0xDA Storage[1] 0xDA | +| 16D | JUMP | Storage[1] 0xDA | ### DA 代码 {#the-da-code} 此代码也与其他方法共享。 所以我们将调用堆栈 Y 中的值,并且记住在 `currentWindow()` 中这个 Y 的值是 Storage[1]。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ---------- | ---------------- | -| DA | JUMPDEST | Y 0xDA | -| DB | PUSH1 0x40 | 0x40 Y 0xDA | -| DD | MLOAD | 0x80 Y 0xDA | -| DE | SWAP1 | Y 0x80 0xDA | -| DF | DUP2 | 0x80 Y 0x80 0xDA | -| E0 | MSTORE | 0x80 Y 0xDA | +| 偏移量 | 操作码 | 堆栈 | +| --: | ---------- | ---------------- | +| DA | JUMPDEST | Y 0xDA | +| DB | PUSH1 0x40 | 0x40 Y 0xDA | +| DD | MLOAD | 0x80 Y 0xDA | +| DE | SWAP1 | Y 0x80 0xDA | +| DF | DUP2 | 0x80 Y 0x80 0xDA | +| E0 | MSTORE | 0x80 0xDA | 将 Y 写入 0x80-0x9F。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ---------- | -------------- | -| E1 | PUSH1 0x20 | 0x20 0x80 0xDA | -| E3 | ADD | 0xA0 0xDA | +| 偏移量 | 操作码 | 堆栈 | +| --: | ---------- | -------------- | +| E1 | PUSH1 0x20 | 0x20 0x80 0xDA | +| E3 | ADD | 0xA0 0xDA | 其余部分已在[上面](#the-e4-code)解释过。 所以跳转到 0xDA,将栈顶 (Y) 的值写入 0x80-0x9F,并返回该值。 对于 `currentWindow()` 方法,返回 Storage[1]。 ## merkleRoot() {#merkleroot} -偏移量 0xED-0xF8 中的代码与我们在 `splitter()` 中看到的 0x103-0x10E 中的代码相同(除 `JUMPI` 目标地址外),因此我们知道 `merkleRoot ()` 也不是 `payable`。 +偏移量 0xED-0xF8 中的代码与我们在 `splitter()` 中看到的 0x103-0x10E 中的代码相同(除 `JUMPI` 目标地址外),因此我们知道 `merkleRoot()` 也不是 `payable`。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | -------------------- | -| F9 | JUMPDEST | | -| FA | POP | | -| FB | PUSH2 0x00da | 0xDA | -| FE | PUSH1 0x00 | 0x00 0xDA | -| 100 | SLOAD | Storage[0] 0xDA | -| 101 | DUP2 | 0xDA Storage[0] 0xDA | -| 102 | JUMP | Storage[0] 0xDA | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------ | ------------------------------------------------------------------------ | +| F9 | JUMPDEST | | +| FA | POP | | +| FB | PUSH2 0x00da | 0xDA | +| FE | PUSH1 0x00 | 0x00 0xDA | +| 100 | SLOAD | Storage[0] 0xDA | +| 101 | DUP2 | 0xDA Storage[0] 0xDA | +| 102 | JUMP | Storage[0] 0xDA | -[我们已经弄清楚了](#the-da-code)跳转后会发生什么。 嗯,`merkleRoot()` 返回 Storage[0]。 +我们已经弄清楚了[跳转后会发生什么](#the-da-code)。 所以,`merkleRoot()` 返回 Storage[0]。 ## 0x81e580d3 {#0x81e580d3} 偏移量 0x138-0x143 中的代码与我们在 `splitter()` 中看到的 0x103-0x10E 中的代码相同(除 `JUMPI` 目标地址外),因此我们知道此函数也不是 `payable`。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | ------------------------------------------------------------ | -| 144 | JUMPDEST | | -| 145 | POP | | -| 146 | PUSH2 0x00da | 0xDA | -| 149 | PUSH2 0x0153 | 0x0153 0xDA | -| 14C | CALLDATASIZE | CALLDATASIZE 0x0153 0xDA | -| 14D | PUSH1 0x04 | 0x04 CALLDATASIZE 0x0153 0xDA | -| 14F | PUSH2 0x018f | 0x018F 0x04 CALLDATASIZE 0x0153 0xDA | -| 152 | JUMP | 0x04 CALLDATASIZE 0x0153 0xDA | -| 18F | JUMPDEST | 0x04 CALLDATASIZE 0x0153 0xDA | -| 190 | PUSH1 0x00 | 0x00 0x04 CALLDATASIZE 0x0153 0xDA | -| 192 | PUSH1 0x20 | 0x20 0x00 0x04 CALLDATASIZE 0x0153 0xDA | -| 194 | DUP3 | 0x04 0x20 0x00 0x04 CALLDATASIZE 0x0153 0xDA | -| 195 | DUP5 | CALLDATASIZE 0x04 0x20 0x00 0x04 CALLDATASIZE 0x0153 0xDA | -| 196 | SUB | CALLDATASIZE-4 0x20 0x00 0x04 CALLDATASIZE 0x0153 0xDA | -| 197 | SLT | CALLDATASIZE-4\<32 0x00 0x04 CALLDATASIZE 0x0153 0xDA | -| 198 | ISZERO | CALLDATASIZE-4>=32 0x00 0x04 CALLDATASIZE 0x0153 0xDA | -| 199 | PUSH2 0x01a0 | 0x01A0 CALLDATASIZE-4>=32 0x00 0x04 CALLDATASIZE 0x0153 0xDA | -| 19C | JUMPI | 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------------ | ------------------------------------------------------------------------------- | +| 144 | JUMPDEST | | +| 145 | POP | | +| 146 | PUSH2 0x00da | 0xDA | +| 149 | PUSH2 0x0153 | 0x0153 0xDA | +| 14C | CALLDATASIZE | CALLDATASIZE 0x0153 0xDA | +| 14D | PUSH1 0x04 | 0x04 CALLDATASIZE 0x0153 0xDA | +| 14F | PUSH2 0x018f | 0x018F 0x04 CALLDATASIZE 0x0153 0xDA | +| 152 | JUMP | 0x04 CALLDATASIZE 0x0153 0xDA | +| 18F | JUMPDEST | 0x04 CALLDATASIZE 0x0153 0xDA | +| 190 | PUSH1 0x00 | 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 192 | PUSH1 0x20 | 0x20 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 194 | DUP3 | 0x04 0x20 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 195 | DUP5 | CALLDATASIZE 0x04 0x20 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 196 | SUB | CALLDATASIZE-4 0x20 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 197 | SLT | CALLDATASIZE-4\<32 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 198 | ISZERO | CALLDATASIZE-4>=32 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 199 | PUSH2 0x01a0 | 0x01A0 CALLDATASIZE-4>=32 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 19C | JUMPI | 0x00 0x04 CALLDATASIZE 0x0153 0xDA | 看起来此函数至少使用调用数据的 32 个字节(一个字)。 -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------ | -------------------------------------------- | -| 19D | DUP1 | 0x00 0x00 0x04 CALLDATASIZE 0x0153 0xDA | -| 19E | DUP2 | 0x00 0x00 0x00 0x04 CALLDATASIZE 0x0153 0xDA | -| 19F | REVERT | | +| 偏移量 | 操作码 | 堆栈 | +| --: | ------ | -------------------------------------------- | +| 19D | DUP1 | 0x00 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 19E | DUP2 | 0x00 0x00 0x00 0x04 CALLDATASIZE 0x0153 0xDA | +| 19F | REVERT | | 如果此函数没有获得调用数据,则交易将回滚且不会任何返回数据。 -我们来看看,如果此函数*确实*获得了它需要的调用数据,会出现什么情况。 - -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | ---------------------------------------- | -| 1A0 | JUMPDEST | 0x00 0x04 CALLDATASIZE 0x0153 0xD | -| 1A1 | POP | 0x04 CALLDATASIZE 0x0153 0xDA | -| 1A2 | CALLDATALOAD | calldataload(4) CALLDATASIZE 0x0153 0xDA | - -`calldataload(4)` 是在方法签名*之后*调用数据的第一个字 - -| 偏移量 | 操作码 | 堆栈 | -| -----: | ------------ | ---------------------------------------------------------------------------- | -| 1A3 | SWAP2 | 0x0153 CALLDATASIZE calldataload(4) 0xDA | -| 1A4 | SWAP1 | CALLDATASIZE 0x0153 calldataload(4) 0xDA | -| 1A5 | POP | 0x0153 calldataload(4) 0xDA | -| 1A6 | JUMP | calldataload(4) 0xDA | -| 153 | JUMPDEST | calldataload(4) 0xDA | -| 154 | PUSH2 0x016e | 0x016E calldataload(4) 0xDA | -| 157 | JUMP | calldataload(4) 0xDA | -| 16E | JUMPDEST | calldataload(4) 0xDA | -| 16F | PUSH1 0x04 | 0x04 calldataload(4) 0xDA | -| 171 | DUP2 | calldataload(4) 0x04 calldataload(4) 0xDA | -| 172 | DUP2 | 0x04 calldataload(4) 0x04 calldataload(4) 0xDA | -| 173 | SLOAD | Storage[4] calldataload(4) 0x04 calldataload(4) 0xDA | -| 174 | DUP2 | calldataload(4) Storage[4] calldataload(4) 0x04 calldataload(4) 0xDA | -| 175 | LT | calldataload(4)\)`,另一个是`isClaimed()`,所以此合约看起来像一个空投合约。 我们可以[尝试使用反编译器](https://etherscan.io/bytecode-decompiler?a=0x2f81e57ff4f4d83b40a9f719fd892d8e806e0761),而不是逐个操作码查看其余代码,反编译器会为此合约中的以下三个函数生成有用的结果。 其他合约的逆向工程留给读者作为练习。 +在剩下方法中,其中一个是 `claim()`,另一个是 `isClaimed()`,所以此合约看起来像一个空投合约。 我们可以[尝试使用反编译器](https://etherscan.io/bytecode-decompiler?a=0x2f81e57ff4f4d83b40a9f719fd892d8e806e0761),而不是逐个操作码查看其余代码,反编译器会为此合约中的三个函数生成有用的结果。 其他合约的逆向工程留给读者作为练习。 ### scaleAmountByPercentage {#scaleamountbypercentage} @@ -588,7 +584,7 @@ Etherscan 指出 `1C` 是一个未知操作码,因为[它是在 Etherscan 编 ```python def unknown8ffb5c97(uint256 _param1, uint256 _param2) payable: - require calldata.size - 4 >=′ 64 + require calldata.size - 4 >= 64 if _param1 and _param2 > -1 / _param1: revert with 0, 17 return (_param1 * _param2 / 100 * 10^6) @@ -610,18 +606,18 @@ def unknown2e7ba6ef(uint256 _param1, uint256 _param2, uint256 _param3, array _pa require _param2 == addr(_param2) ... if currentWindow <= _param1: - revert with 0, 'cannot claim for a future window' + revert with 0, '不能为未来的窗口申领' ``` 我们在这里看到两件重要的事情: -- `_param2`,虽然被声明为 `uint256`,但实际上是一个地址 +- `_param2` 虽然被声明为 `uint256`,但实际上是一个地址 - `_param1` 是被声明的窗口,它必须是 `currentWindow` 或更早。 ```python ... if stor5[_claimWindow][addr(_claimFor)]: - revert with 0, 'Account already claimed the given window' + revert with 0, '帐户已申领指定窗口' ``` 所以现在我们知道 Storage[5] 是一个窗口和地址数组,并知道该地址是否申领了此窗口内奖励。 @@ -641,10 +637,10 @@ def unknown2e7ba6ef(uint256 _param1, uint256 _param2, uint256 _param3, array _pa s = sha3(mem[_66 + 32 len mem[_66]]) continue if unknown2eb4a7ab != s: - revert with 0, 'Invalid proof' + revert with 0, '无效证明' ``` -我们知道 `unknown2eb4a7ab` 实际上是函数 `merkleRoot()`,所以此代码看起来像是在验证一个[默克尔证明](https://medium.com/crypto-0-nite/merkle-proofs-explained-6dd429623dc5)。 这意味着 `_param4` 是默克尔证明。 +我们知道 `unknown2eb4a7ab` 实际上是 `merkleRoot()` 函数,所以这段代码看起来像是在验证[默克尔证明](https://medium.com/crypto-0-nite/merkle-proofs-explained-6dd429623dc5)。 这意味着 `_param4` 是默克尔证明。 ```python call addr(_param2) with: @@ -652,7 +648,7 @@ def unknown2e7ba6ef(uint256 _param1, uint256 _param2, uint256 _param3, array _pa gas 30000 wei ``` -这就是合约将自己的以太币转账到另一个地址(合约地址或外部地址)的方式。 它使用一个值来调用该函数,该值是要转账的金额。 因此,该合约看起来像是一次以太币空投。 +这就是合约将自己的 ETH 转账到另一个地址(合约地址或外部地址)的方式。 它使用一个值来调用该函数,该值是要转账的金额。 因此,该合约看起来像是一次 ETH 空投。 ```python if not return_data.size: @@ -662,22 +658,22 @@ def unknown2e7ba6ef(uint256 _param1, uint256 _param2, uint256 _param3, array _pa value unknown81e580d3[_param1] * _param3 / 100 * 10^6 wei ``` -下面两行表明 Storage[2] 也是我们调用的合约。 如果我们[查阅构造函数交易](https://etherscan.io/tx/0xa1ea0549fb349eb7d3aff90e1d6ce7469fdfdcd59a2fd9b8d1f5e420c0d05b58#statechange),就会看到此合约是 [0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2](https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2),即一个封装的以太币合约,[其源代码已经上传到 Etherscan](https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#code)。 +下面两行表明 Storage[2] 也是我们调用的合约。 如果[查看构造函数交易](https://etherscan.io/tx/0xa1ea0549fb349eb7d3aff90e1d6ce7469fdfdcd59a2fd9b8d1f5e420c0d05b58#statechange),会发现此合约是 [0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2](https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2),一个封装以太币合约,其[源代码已上传到 Etherscan](https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#code)。 -是的,看起来这些合约试图将以太币发送到 `_param2`。 如果它可以做到,那就太好了。 如果做不到,它会尝试发送 [WETH](https://weth.tkn.eth.limo/)。 如果 `_param2` 是外部帐户(EOA),那么它总是可以收到以太币,但合约帐户可以拒绝接收以太币。 但是,WETH 是 ERC-20,合约不能拒绝接受。 +所以看起来这些合约试图将 ETH 发送到 `_param2`。 如果可以,那就太好了。 如果不行,它会尝试发送 [WETH](https://weth.tkn.eth.limo/)。 如果 `_param2` 是外部帐户 (EOA),那么它总是可以收到 ETH,但合约帐户可以拒绝接收 ETH。 但是,WETH 是 ERC-20,合约不能拒绝接受。 ```python ... log 0xdbd5389f: addr(_param2), unknown81e580d3[_param1] * _param3 / 100 * 10^6, bool(ext_call.success) ``` -在此函数结束时,我们看到正在生成一个日志项。 [查看生成的日志项](https://etherscan.io/address/0x2510c039cc3b061d79e564b38836da87e31b342f#events)并筛选以 `0xdbd5...` 开头的主题。 如果[点击生成此类项的其中一个交易](https://etherscan.io/tx/0xe7d3b7e00f645af17dfbbd010478ef4af235896c65b6548def1fe95b3b7d2274),我们会看到它确实看起来像一个声明 - 该帐户向我们进行逆向工程的合约发送一条消息并获得了以太币。 +在此函数结束时,我们看到正在生成一个日志项。 [查看生成的日志条目](https://etherscan.io/address/0x2510c039cc3b061d79e564b38836da87e31b342f#events)并以 `0xdbd5...` 开头的主题进行筛选。 如果[点击生成此类条目的其中一个交易](https://etherscan.io/tx/0xe7d3b7e00f645af17dfbbd010478ef4af235896c65b6548def1fe95b3b7d2274),我们会看到它确实看起来像一个申领 - 该帐户向我们进行逆向工程的合约发送一条消息并获得了 ETH。 -![声明交易](claim-tx.png) +![一个申领交易](claim-tx.png) ### 1e7df9d3 {#1e7df9d3} -此函数和上面的 [`claim`](#claim) 非常相似。 它也检查默克尔证明,尝试将以太币转账到第一个参数,并生成相同类型的日志项。 +此函数和上面的 [`claim`](#claim) 非常相似。 它也检查默克尔证明,尝试将 ETH 转账到第一个参数,并生成相同类型的日志项。 ```python def unknown1e7df9d3(uint256 _param1, uint256 _param2, array _param3) payable: @@ -695,7 +691,7 @@ def unknown1e7df9d3(uint256 _param1, uint256 _param2, array _param3) payable: mem[mem[64] + 32] = s + sha3(mem[(32 * _param3.length) + 160 len mem[(32 * _param3.length) + 128]]) ... if unknown2eb4a7ab != s: - revert with 0, 'Invalid proof' + revert with 0, '无效证明' ... call addr(_param1) with: value s wei @@ -710,7 +706,7 @@ def unknown1e7df9d3(uint256 _param1, uint256 _param2, array _param3) payable: log 0xdbd5389f: addr(_param1), s, bool(ext_call.success) ``` -主要区别在于第一个参数,即要提款的窗口,不存在。 相反,所有可以声明的窗口都有一个循环。 +主要区别在于第一个参数,即要取款的窗口,不存在。 相反,所有可以申领的窗口都有一个循环。 ```python idx = 0 @@ -739,8 +735,10 @@ def unknown1e7df9d3(uint256 _param1, uint256 _param2, array _param3) payable: continue ``` -所以它看起来像一个声明所有窗口的 `claim` 变体。 +所以它看起来像一个申领所有窗口的 `claim` 变体。 -## 总结 {#conclusion} +## 结论 {#conclusion} -现在,你应该知道如何通过操作码或反编译器(当它有效时)理解没有源代码的智能合约。 从本文的篇幅明显可以看出,对合约进行逆向工程并非易事,但在安全性至关重要的系统中,能够验证合约是否按承诺运作是一项重要技能。 +现在,你应该知道如何通过操作码或反编译器(当它有效时)来理解源代码不可用的合约。 从本文的篇幅明显可以看出,对合约进行逆向工程并非易事,但在安全性至关重要的系统中,能够验证合约是否按承诺运作是一项重要技能。 + +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 diff --git a/public/content/translations/zh/developers/tutorials/run-node-raspberry-pi/index.md b/public/content/translations/zh/developers/tutorials/run-node-raspberry-pi/index.md index b2b89fdfd40..577a50c046d 100644 --- a/public/content/translations/zh/developers/tutorials/run-node-raspberry-pi/index.md +++ b/public/content/translations/zh/developers/tutorials/run-node-raspberry-pi/index.md @@ -1,150 +1,169 @@ --- -title: 如何通过刷写MicroSD卡将您的Raspberry Pi 4变为一个节点 -description: 刷写树莓派 4,插入以太网电缆,连接固态硬盘并打开设备电源,将树莓派 4 变为以太坊全节点 + 验证者。 +title: "在树莓派 4 上运行以太坊节点" +description: "刷写你的树莓派 4,插入网线,连接固态硬盘并启动设备,将树莓派 4 变成一个完整的以太坊节点 + 验证者。" author: "EthereumOnArm" -tags: - - "客户端" - - "执行层" - - "共识层" - - "节点" +tags: [ "客户端", "执行层", "共识层", "节点" ] lang: zh -skill: advanced +skill: intermediate published: 2022-06-10 source: Ethereum on ARM -sourceUrl: https://ethereum-on-arm-documentation.readthedocs.io/en/latest/kiln/kiln-testnet.html +sourceUrl: https://ethereum-on-arm-documentation.readthedocs.io/en/latest/ --- -**Ethereum on Arm 是一个定制 Linux 映像,它可以将树莓派转变成以太坊节点。** +**Ethereum on Arm 是一个自定义的 Linux 镜像,可将树莓派转变为以太坊节点。** -为了使用 Ethereum on Arm 将树莓派转变成以太坊节点,推荐使用以下硬件: +要使用 Ethereum on Arm 将树莓派转变为以太坊节点,推荐使用以下硬件: -- 树莓派 4(B 型,8 GB) -- MicroSD 卡(最小 16 GB,Class 10) -- 最小 2TB 的 USB3.0 固态硬盘或使用 USB3.0 转 SATA 转接盒的固态硬盘 +- 树莓派 4(B 型 8GB)、Odroid M1 或 Rock 5B(8GB/16GB RAM)板 +- MicroSD 卡(最低 16 GB,Class 10) +- 最低 2 TB 的 USB 3.0 固态硬盘,或带有 USB 转 SATA 硬盘盒的固态硬盘。 - 电源 - 以太网电缆 -- 端口转发(详情请查看客户端) +- 端口转发(更多信息请参见客户端) - 带散热片和风扇的外壳 -- USB 键盘、显示器和 HDMI 数据线(微型 HDMI)(可选) +- USB 键盘、显示器和 HDMI 线(micro-HDMI)(可选) ## 为什么要在 ARM 上运行以太坊? {#why-run-ethereum-on-arm} -ARM 单板机是一种便宜、灵活的小型计算机。 它们价格低廉、效率高、可配置成将全部资源专用于节点、能耗低、体积小,可以很顺利地安装在任何家庭中,因此成为运行以太坊节点的不二之选。 启动节点也非常容易,因为树莓派的 MicroSD 卡可以简单地使用预建映像刷写,无需下载或构建软件。 +ARM 单板机是非常实惠、灵活的小型计算机。 它们是运行以太坊节点的理想选择,因为它们价格低廉,可配置为将所有资源专用于节点,从而提高效率,而且功耗低、体积小,可以不引人注目地放置在任何家庭中。 启动节点也非常容易,因为树莓派的 MicroSD 卡只需用预构建的镜像刷写即可,无需下载或构建软件。 ## 工作原理 {#how-does-it-work} -使用预先构建的映像刷写树莓派的内存卡。 此映像包含了运行以太坊节点所需的一切。 在刷写完内存卡后,用户只需要启动树莓派即可。 运行节点所需的所有进程自动启动。 这是可行的,因为内存卡中有基于 Linux 的操作系统,系统级进程在此操作系统上自动运行,将树莓派转变成以太坊节点。 +使用预构建的镜像刷写树莓派的存储卡。 此镜像包含运行以太坊节点所需的一切。 刷好卡后,用户只需启动树莓派即可。 运行节点所需的所有进程都会自动启动。 这是可行的,因为存储卡中包含一个基于 Linux 的操作系统 (OS),系统级进程在其上自动运行,从而将该设备转变为以太坊节点。 -以太坊不能在流行的树莓派 Linux 操作系统“Raspbian”下运行,因为 Raspbian 还在使用 32 位指令集架构,这会给以太坊用户带来内存问题,而且共识客户端也不支持 32 位二进制文件。 为了解决这一问题,Ethereum on Arm 团队迁移到原生 64 位操作系统“Armbian”。 +以太坊无法在使用流行的树莓派 Linux 操作系统“Raspbian”上运行,因为 Raspbian 仍使用 32 位架构,这会导致以太坊用户遇到内存问题,并且共识客户端不支持 32 位二进制文件。 为了克服这个问题,Ethereum on Arm 团队迁移到了一个名为“Armbian”的原生 64 位操作系统。 -**映像负责处理所有必要的步骤**,包括从设置环境和格式化固态磁盘,到安装和运行以太坊软件,以及启动区块链同步。 +**镜像会处理所有必要的步骤**,从设置环境和格式化固态硬盘,到安装和运行以太坊软件,以及启动区块链同步。 -## 执行客户端和共识客户端说明 {#note-on-execution-and-consensus-clients} +## 关于执行客户端和共识客户端的说明 {#note-on-execution-and-consensus-clients} -Ethereum on Arm 相关文档解释了如何设置执行客户端*或*共识客户端,两个以太坊测试网(Kiln 和 Ropsten)除外。 这种可选性只有在以太坊从工作量证明过渡到权益证明(称为[合并](/roadmap/merge))之前才有可能。 +Ethereum on Arm 镜像包含作为服务预构建的执行客户端和共识客户端。 以太坊节点需要两个客户端都已同步并正在运行。 您只需下载并刷写镜像,然后启动服务。 该镜像预装了以下执行客户端: - -合并后,将无法单独运行执行客户端和共识客户端 — 它们必须成对运行。 因此,在本教程中,我们将在以太坊测试网 (Kiln) 上运行一对执行客户端和共识客户端。 - +- Geth +- Nethermind +- Besu -## Kiln 树莓派 4 映像 {#the-kiln-raspberry-pi-4-image} +以及以下共识客户端: -Kiln 是一个专门用于测试合并的公共测试网。 Ethereum on Arm 团队开发了一个映像,让用户可以在这个合并测试网上快速启动一对以太坊客户端。 Kiln 合并已经发生,但该网络仍在运行,因此可用于本教程。 Kiln 上的以太币没有实际价值。 +- Lighthouse +- Nimbus +- Prysm +- Teku -Kiln 树莓派 4 映像是一种“即插即用”映像,它会自动安装和设置执行客户端与共识客户端,配置它们相互通信并连接到 Kiln 网络。 用户需要做的就是使用一个简单的命令启动他们的进程。 该映像包含四种执行客户端(Geth、Nethermind、Besu 和 Erigon)和四种共识客户端(Lighthouse、Prysm、Nimbus、Teku),可供用户选择。 +您应该各选择一个来运行——所有执行客户端都与所有共识客户端兼容。 如果您没有明确选择客户端,节点将回退到其默认设置——Geth 和 Lighthouse,并在单板机通电时自动运行它们。 您必须在路由器上打开 30303 端口,以便 Geth 能够找到并连接到对等节点。 -从 [Ethereum on Arm](https://ethereumonarm-my.sharepoint.com/:u:/p/dlosada/ES56R_SuvaVFkiMO1Tgnf6kB7lEbBfla5c2c18E3WQRJzA?download=1) 下载树莓派映像并验证 SHA256 哈希: +## 下载镜像 {#downloading-the-image} + +树莓派 4 以太坊镜像是“即插即用”镜像,它会自动安装并设置执行客户端和共识客户端,配置它们相互通信并连接到以太坊网络。 用户所要做的就是使用一个简单的命令来启动其进程。 + +从 [Ethereum on Arm](https://ethereumonarm-my.sharepoint.com/:u:/p/dlosada/Ec_VmUvr80VFjf3RYSU-NzkBmj2JOteDECj8Bibde929Gw?download=1) 下载树莓派镜像,并验证 SHA256 哈希值: ```sh -# From directory containing the downloaded image -shasum -a 256 ethonarm_kiln_22.03.01.img.zip -# Hash should output: 485cf36128ca60a41b5de82b5fee3ee46b7c479d0fc5dfa5b9341764414c4c57 +# 从包含已下载镜像的目录中 +shasum -a 256 ethonarm_22.04.00.img.zip +# 哈希值应输出:fb497e8f8a7388b62d6e1efbc406b9558bee7ef46ec7e53083630029c117444f ``` -请注意,对于没有树莓派但有 AWS 帐户的用户,提供的 ARM 实例可以运行相同的映像。 说明和 AWS 映像可从 Ethereum on Arm (https://ethereum-on-arm-documentation.readthedocs.io/en/latest/kiln/kiln-testnet.html) 下载。 +请注意,Rock 5B 和 Odroid M1 单板机的镜像可在 Ethereum-on-Arm [下载页面](https://ethereum-on-arm-documentation.readthedocs.io/en/latest/quick-guide/download-and-install.html)获取。 -## 刷写 MicroSD 卡 {#flashing-the-microsd} +## 刷写 MicroSD {#flashing-the-microsd} -首先,应将用于树莓派的 MicroSD 卡插入台式机或笔记本电脑中,以便可以刷写。 接着,在终端执行以下命令,将下载的映像刷写到 SD 卡中: +应首先将用于树莓派的 MicroSD 卡插入台式机或笔记本电脑,以便进行刷写。 然后,使用以下终端命令将下载的镜像刷写到 SD 卡上: ```shell -# 检查 Micro SD 卡名 -sudo fdisk -I +# 检查 MicroSD 卡名称 +sudo fdisk -l >> sdxxx ``` -正确的 SD 卡名称非常重要,因为下一条命令中的指令 `dd` 会在写入映像前彻底清除 SD 卡上的全部已有内容。 接下来,导航到包含压缩映像文件的目录: +正确获取名称非常重要,因为下一个命令包含 `dd`,它会在将镜像写入卡上之前完全擦除卡上的现有内容。 要继续,请导航到包含压缩镜像的目录: ```shell -# 解压并烧录镜像 -unzip ethonarm_kiln_22.03.01.img.zip -sudo dd bs=1M if=ethonarm_kiln_22.03.01.img of=/dev/mmcblk0 conv=fdatasync status=progress +# 解压缩并刷写镜像 +unzip ethonarm_22.04.00.img.zip +sudo dd bs=1M if=ethonarm_22.04.00.img of=/dev/ conv=fdatasync status=progress ``` -现在 SD 卡已刷写完成,可以将其插入树莓派中了。 +现在卡已刷写完毕,可以将其插入树莓派了。 ## 启动节点 {#start-the-node} -将 SD 卡插入树莓派后,连接以太网电缆和固态硬盘,然后打开电源。 操作系统将启动并自动执行预先配置好的任务,包括安装和构建客户端软件,从而将树莓派转变成以太坊节点。 此过程大约需要 10-15 分钟。 +将 SD 卡插入树莓派后,连接以太网电缆和固态硬盘,然后打开电源。 操作系统将启动并自动开始执行预配置的任务,将树莓派转变为以太坊节点,包括安装和构建客户端软件。 这可能需要 10-15 分钟。 -所有安装和配置完成后,通过安全外壳连接登录设备,或者如果单板机已经连接了键盘和显示器,也可以直接使用终端。 使用 `ethereum` 帐户登录,因为此帐户有启动节点所需的权限。 +一旦所有内容都安装和配置完毕,请通过 ssh 连接登录设备,或者如果单板机连接了显示器和键盘,则直接使用终端。 使用 `ethereum` 帐户登录,因为该帐户具有启动节点所需的权限。 ```shell -User: ethereum -Password: ethereum +用户:ethereum +密码:ethereum ``` -然后,用户可以选择他们希望运行的执行客户端和共识客户端组合,并按如下方式启动他们的 systemctl 进程(示例中运行 Geth 和 Lighthouse): +默认的执行客户端 Geth 将自动启动。 您可以通过使用以下终端命令检查日志来确认这一点: -```shell -sudo systemctl start geth-lh -sudo systemctl start lh-geth-beacon +```sh +sudo journalctl -u geth -f ``` -可以使用以下指令检查日志 +共识客户端需要显式启动。 为此,请先在路由器上打开 9000 端口,以便 Lighthouse 能够找到并连接到对等节点。 然后启用并启动 lighthouse 服务: -```shell -# logs for Geth -sudo journalctl -u geth-lh -f -#logs for lighthouse -sudo journalctl -u lh-geth-beacon -f +```sh +sudo systemctl enable lighthouse-beacon +sudo systemctl start lighthouse-beacon ``` -[Ethereum on Arm 相关文档](https://ethereum-on-arm-documentation.readthedocs.io/en/latest/kiln/kiln-testnet.html#id2)中提供有每一对客户端组合的特定服务名称。 它们可用于更新此处提供的命令,以用于任何客户端组合。 +使用日志检查客户端: + +```sh +sudo journalctl -u lighthouse-beacon +``` + +请注意,共识客户端将在几分钟内同步,因为它使用检查点同步。 执行客户端将需要更长的时间——可能需要几个小时,并且在共识客户端完成同步之前它不会启动(这是因为执行客户端需要一个同步目标,而同步后的共识客户端会提供这个目标)。 + +随着 Geth 和 Lighthouse 服务运行并同步,您的树莓派现在就是一个以太坊节点了! 与以太坊网络交互最常见的方式是使用 Geth 的 Javascript 控制台,它可以附加到端口 8545 上的 Geth 客户端。 也可以使用像 Curl 这样的请求工具,以 JSON 对象格式提交命令。 在 [Geth 文档](https://geth.ethereum.org/)中查看更多信息。 + +Geth 预先配置为将指标报告到一个 Grafana 仪表板,该仪表板可以在浏览器中查看。 更高级的用户可能希望通过导航到 `ipaddress:3000`,并传递 `user: admin` 和 `passwd: ethereum`,来使用此功能监控其节点的健康状况。 ## 验证者 {#validators} -为了运行验证者,必须首先访问 32 个测试网以太币,它们必须存入 Kiln 存款合约。 这可以按照 [Kiln 启动板](https://kiln.launchpad.ethereum.org/en/)上的分步指南来完成。 在台式机/笔记本电脑上执行此操作,但不要生成密钥 — 密钥生成可以直接在树莓派上完成。 +也可以选择性地将验证者添加到共识客户端。 验证者软件允许您的节点积极参与共识,并为网络提供加密经济安全保障。 您会因为这项工作获得 ETH 奖励。 要运行验证者,您必须首先拥有 32 ETH,这些 ETH 必须存入存款合约中。 您可以按照 [Launchpad](https://launchpad.ethereum.org/) 上的分步指南进行存款。 请在台式机/笔记本电脑上执行此操作,但不要生成密钥——这可以直接在树莓派上完成。 -在树莓派上打开一个终端并运行以下命令来生成存款密钥: +在树莓派上打开一个终端,并运行以下命令以生成存款密钥: ``` -cd && deposit new-mnemonic --num_validators 1 --chain kiln +sudo apt-get update +sudo apt-get install staking-deposit-cli +cd && deposit new-mnemonic --num_validators 1 ``` -保持助记词安全! 上面的命令在节点的密钥库中生成了两个文件:验证者密钥和存款数据文件。 存款数据需要上传到启动板,因此必须要从树莓派复制到台式机/笔记本电脑。 这可以使用安全外壳连接或任何其他复制/粘贴方法来完成。 +(或者下载 [staking-deposit-cli](https://github.com/ethereum/staking-deposit-cli) 在离线计算机上运行,并运行 `deposit new-mnemnonic` 命令) -在存款数据文件在运行启动板的计算机上可用后,就可以将其拖放到启动板界面上的 `+` 上。 按照屏幕上的说明将交易发送到存款合约。 +请妥善保管助记词! 上面的命令在节点的密钥库中生成了两个文件:验证者密钥和存款数据文件。 存款数据需要上传到 Launchpad,因此必须从树莓派复制到台式机/笔记本电脑。 这可以通过 ssh 连接或任何其他复制/粘贴方法完成。 -返回树莓派,可以启动验证者。 这需要导入验证者密钥,设置领取奖励的地址,然后启动预先配置好的验证者进程。 以下示例适用于 Lighthouse — 其他共识客户端的说明见 [Ethereum on Arm 相关文档](https://ethereum-on-arm-documentation.readthedocs.io/en/latest/kiln/kiln-testnet.html#lighthouse): +一旦存款数据文件在运行 Launchpad 的计算机上可用,就可以将其拖放到 Launchpad 屏幕上的 `+` 号上。 按照屏幕上的说明向存款合约发送一笔交易。 + +回到树莓派上,可以启动一个验证者。 这需要导入验证者密钥,设置领取奖励的地址,然后启动预配置的验证者进程。 下面的示例适用于 Lighthouse——其他共识客户端的说明可在 [Ethereum on Arm 文档](https://ethereum-on-arm-documentation.readthedocs.io/en/latest/)中找到: ```shell -#导入验证器密钥 -lighthouse-kl account validator import --directory=/home/ethereum/validator_keys --datadir=/home/ethereum/.lh-geth/kiln/testnet-lh +# 导入验证者密钥 +lighthouse account validator import --directory=/home/ethereum/validator_keys -#设置收款地址地址 -sudo sed -i ‘’ /etc/ethereum/kiln/lh-geth-validator.conf +# 设置奖励地址 +sudo sed -i 's/' /etc/ethereum/lighthouse-validator.conf -#启动验证器 -sudo systemctl start lh-geth-validator +# 启动验证者 +sudo systemctl start lighthouse-validator ``` -恭喜,你现在拥有运行在树莓派上的以太坊全节点和验证者! +恭喜,您现在有了一个在树莓派上运行的完整以太坊节点和验证者! + +## 更多详细信息 {#more-details} + +本页概述了如何使用树莓派设置 Geth-Lighthouse 节点和验证者。 更详细的说明可在 [Ethereum-on-Arm 网站](https://ethereum-on-arm-documentation.readthedocs.io/en/latest/index.html)上找到。 -## 感谢反馈 {#feedback-appreciated} +## 感谢您的反馈 {#feedback-appreciated} -我们知道树莓派拥有庞大的用户群体,能对以太坊网络的健康产生非常积极的影响。 请深入了解本教程中的详细信息,尝试在其他测试网甚至以太坊主网上运行,查看 Ethereum on Arm GitHub,提供反馈,提出问题并拉取请求,并帮助改进技术和相关文档! +我们知道树莓派拥有庞大的用户群,可以对以太坊网络的健康产生非常积极的影响。 +请深入研究本教程中的详细信息,尝试在测试网上运行,查看 Ethereum on Arm GitHub,提供反馈、提出问题和拉取请求,并帮助改进技术和文档! ## 参考文献 {#references} diff --git a/public/content/translations/zh/developers/tutorials/scam-token-tricks/index.md b/public/content/translations/zh/developers/tutorials/scam-token-tricks/index.md new file mode 100644 index 00000000000..1ae7d7b590c --- /dev/null +++ b/public/content/translations/zh/developers/tutorials/scam-token-tricks/index.md @@ -0,0 +1,470 @@ +--- +title: "诈骗代币使用的一些伎俩以及如何检测它们" +description: "在本教程中,我们将剖析一个诈骗代币,了解诈骗者使用的一些伎俩、他们如何实施这些伎俩,以及我们如何检测它们。" +author: Ori Pomerantz +tags: + [ + "诈骗", + "Solidity", + "erc-20", + "javascript", + "typescript" + ] +skill: intermediate +published: 2023-09-15 +lang: zh +--- + +在本教程中,我们将剖析[一个诈骗代币](https://etherscan.io/token/0xb047c8032b99841713b8e3872f06cf32beb27b82#code),了解诈骗者使用的一些伎俩以及他们如何实施这些伎俩。 在本教程结束时,你将对 ERC-20 代币合约、其功能以及为何有必要保持怀疑态度有更全面的了解。 然后,我们查看该诈骗代币发出的事件,并了解如何自动识别它不是合法代币。 + +## 诈骗代币——它们是什么、人们为什么发行诈骗代币,以及如何避免它们 {#scam-tokens} + +以太坊最常见的用途之一是由一个团队来打造一种可以交易的代币,在某种意义上是他们自己的货币。 然而,任何存在可以带来价值的合法使用场景的地方,就会有试图窃取那些价值的犯罪分子。 + +你可以从用户角度在 [ethereum.org 的其他地方](/guides/how-to-id-scam-tokens/)阅读更多关于此主题的内容。 本教程重点剖析一个诈骗代币,了解它是如何制作的以及如何被检测出来。 + +### 我如何知道 wARB 是个骗局? {#warb-scam} + +我们剖析的代币是 [wARB](https://etherscan.io/token/0xb047c8032b99841713b8e3872f06cf32beb27b82#code),它伪装成与合法的 [ARB 代币](https://etherscan.io/token/0xb50721bcf8d664c30412cfbc6cf7a15145234ad1)等价。 + +知道哪个是合法代币的最简单方法是查看其发行组织 [Arbitrum](https://arbitrum.foundation/)。 合法地址已在[他们的相关文档](https://docs.arbitrum.foundation/deployment-addresses#token)中指定。 + +### 为什么源代码是可用的? {#why-source} + +通常,我们期望试图诈骗他人的人会保密,事实上,许多诈骗代币的代码都不可用(例如,[这个](https://optimistic.etherscan.io/token/0x15992f382d8c46d667b10dc8456dc36651af1452#code)和[这个](https://optimistic.etherscan.io/token/0x026b623eb4aada7de37ef25256854f9235207178#code))。 + +然而,合法代币通常会公布其源代码,因此为了显得合法,诈骗代币的作者有时也会这样做。 [wARB](https://etherscan.io/token/0xb047c8032b99841713b8e3872f06cf32beb27b82#code) 是那些源代码可用的代币之一,这使得理解它变得更容易。 + +虽然合约部署者可以选择是否公布源代码,但他们_不能_公布错误的源代码。 区块浏览器独立编译提供的源代码,如果得不到完全相同的字节码,它就会拒绝该源代码。 [你可以在 Etherscan 网站上阅读更多相关内容](https://etherscan.io/verifyContract)。 + +## 与合法 ERC-20 代币的比较 {#compare-legit-erc20} + +我们将把这个代币与合法的 ERC-20 代币进行比较。 如果你不熟悉合法 ERC-20 代币通常是如何编写的,请[参阅本教程](/developers/tutorials/erc20-annotated-code/)。 + +### 特权地址的常量 {#constants-for-privileged-addresses} + +合约有时需要特权地址。 为长期使用而设计的合约允许一些特权地址更改这些地址,例如,为了能够使用新的多签合约。 有几种方法可以做到这一点。 + +[`HOP` 代币合约](https://etherscan.io/address/0xc5102fe9359fd9a28f877a67e36b0f050d81a3cc#code) 使用 [`Ownable`](https://docs.openzeppelin.com/contracts/2.x/access-control#ownership-and-ownable) 模式。 特权地址保存在存储中,在一个名为 `_owner` 的字段中(参见第三个文件 `Ownable.sol`)。 + +```solidity +abstract contract Ownable is Context { + address private _owner; + . + . + . +} +``` + +[`ARB` 代币合约](https://etherscan.io/address/0xad0c361ef902a7d9851ca7dcc85535da2d3c6fc7#code)没有直接的特权地址。 然而,它不需要一个。 它位于[地址 `0xb50721bcf8d664c30412cfbc6cf7a15145234ad1`](https://etherscan.io/address/0xb50721bcf8d664c30412cfbc6cf7a15145234ad1#code) 的一个 [`proxy`](https://docs.openzeppelin.com/contracts/5.x/api/proxy) 之后。 该合约有一个特权地址(参见第四个文件 `ERC1967Upgrade.sol`),可用于升级。 + +```solidity + /** + * @dev 在 EIP1967 管理员时隙中存储一个新地址。 + */ + function _setAdmin(address newAdmin) private { + require(newAdmin != address(0), "ERC1967: new admin is the zero address"); + StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; + } +``` + +相比之下,`wARB` 合约有一个硬编码的 `contract_owner`。 + +```solidity +contract WrappedArbitrum is Context, IERC20 { + . + . + . + address deployer = 0xB50721BCf8d664c30412Cfbc6cf7a15145234ad1; + address public contract_owner = 0xb40dE7b1beE84Ff2dc22B70a049A07A13a411A33; + . + . + . +} +``` + +[此合约所有者](https://etherscan.io/address/0xb40dE7b1beE84Ff2dc22B70a049A07A13a411A33)不是一个可以在不同时间由不同帐户控制的合约,而是一个[外部所有的帐户](/developers/docs/accounts/#externally-owned-accounts-and-key-pairs)。 这意味着它可能是为个人短期使用而设计的,而不是作为控制一个将保持有价值的 ERC-20 的长期解决方案。 + +事实上,如果我们查看 Etherscan,我们会发现诈骗者在 2023 年 5 月 19 日期间仅使用了该合约 12 小时(从[第一笔交易](https://etherscan.io/tx/0xf49136198c3f925fcb401870a669d43cecb537bde36eb8b41df77f06d5f6fbc2)到[最后一笔交易](https://etherscan.io/tx/0xdfd6e717157354e64bbd5d6adf16761e5a5b3f914b1948d3545d39633244d47b))。 + +### 虚假的 `_transfer` 函数 {#the-fake-transfer-function} + +标准做法是使用[一个内部的 `_transfer` 函数](/developers/tutorials/erc20-annotated-code/#the-_transfer-function-_transfer)来进行实际的转账。 + +在 `wARB` 中,这个函数看起来几乎是合法的: + +```solidity + function _transfer(address sender, address recipient, uint256 amount) internal virtual{ + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(sender, recipient, amount); + + _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); + _balances[recipient] = _balances[recipient].add(amount); + if (sender == contract_owner){ + sender = deployer; + } + emit Transfer(sender, recipient, amount); + } +``` + +可疑的部分是: + +```solidity + if (sender == contract_owner){ + sender = deployer; + } + emit Transfer(sender, recipient, amount); +``` + +如果合约所有者发送代币,为什么 `Transfer` 事件显示它们来自 `deployer`? + +然而,还有一个更重要的问题。 谁调用这个 `_transfer` 函数? 它不能从外部调用,它被标记为 `internal`。 而且我们拥有的代码不包含任何对 `_transfer` 的调用。 很明显,它在这里只是个诱饵。 + +```solidity + function transfer(address recipient, uint256 amount) public virtual override returns (bool) { + _f_(_msgSender(), recipient, amount); + return true; + } + + function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { + _f_(sender, recipient, amount); + _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); + return true; + } +``` + +当我们查看用于转账代币的函数 `transfer` 和 `transferFrom` 时,我们看到它们调用了一个完全不同的函数 `_f_`。 + +### 真正的 `_f_` 函数 {#the-real-f-function} + +```solidity + function _f_(address sender, address recipient, uint256 amount) internal _mod_(sender,recipient,amount) virtual { + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(sender, recipient, amount); + + _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); + _balances[recipient] = _balances[recipient].add(amount); + if (sender == contract_owner){ + + sender = deployer; + } + emit Transfer(sender, recipient, amount); + } +``` + +这个函数中有两个潜在的危险信号。 + +- 使用了[函数修饰符](https://www.tutorialspoint.com/solidity/solidity_function_modifiers.htm) `_mod_`。 然而,当我们查看源代码时,我们发现 `_mod_` 实际上是无害的。 + + ```solidity + modifier _mod_(address sender, address recipient, uint256 amount){ + _; + } + ``` + +- 我们在 `_transfer` 中看到的同样问题,即当 `contract_owner` 发送代币时,它们似乎来自 `deployer`。 + +### 虚假事件函数 `dropNewTokens` {#the-fake-events-function-dropNewTokens} + +现在我们来看一个看起来像真正骗局的东西。 为了便于阅读,我对函数做了一些编辑,但功能上是等效的。 + +```solidity +function dropNewTokens(address uPool, + address[] memory eReceiver, + uint256[] memory eAmounts) public auth() +``` + +这个函数有 `auth()` 修饰符,这意味着它只能由合约所有者调用。 + +```solidity +modifier auth() { + require(msg.sender == contract_owner, "Not allowed to interact"); + _; +} +``` + +这个限制完全合理,因为我们不希望随机帐户分发代币。 然而,函数的其余部分是可疑的。 + +```solidity +{ + for (uint256 i = 0; i < eReceiver.length; i++) { + emit Transfer(uPool, eReceiver[i], eAmounts[i]); + } +} +``` + +一个将资金从池子帐户转账到一个接收者数组(包含金额数组)的函数是完全合理的。 在许多用例中,你会希望将代币从单一来源分发到多个目的地,例如工资发放、空投等。 在单笔交易中完成比发行多笔交易更便宜(在燃料方面),甚至比在同一笔交易中从不同的合约多次调用 ERC-20 更便宜。 + +然而,`dropNewTokens` 并没有这样做。 它会发出 [`Transfer` 事件](https://eips.ethereum.org/EIPS/eip-20#transfer-1),但实际上并不转账任何代币。 没有正当理由通过告知脱链应用一笔并未真正发生的转账来迷惑它们。 + +### 销毁 `Approve` 函数 {#the-burning-approve-function} + +ERC-20 合约应该有一个用于授权的 [`approve` 函数](/developers/tutorials/erc20-annotated-code/#approve),我们的诈骗代币确实有这样一个函数,而且它甚至是正确的。 然而,由于 Solidity 源于 C,它是区分大小写的。 “Approve”和“approve”是不同的字符串。 + +此外,该功能与 `approve` 无关。 + +```solidity + function Approve( + address[] memory holders) +``` + +此函数被调用时,会传入一个代币持有者的地址数组。 + +```solidity + public approver() { +``` + +`approver()` 修饰符确保只有 `contract_owner` 可以调用此函数(见下文)。 + +```solidity + for (uint256 i = 0; i < holders.length; i++) { + uint256 amount = _balances[holders[i]]; + _beforeTokenTransfer(holders[i], 0x0000000000000000000000000000000000000001, amount); + _balances[holders[i]] = _balances[holders[i]].sub(amount, + "ERC20: burn amount exceeds balance"); + _balances[0x0000000000000000000000000000000000000001] = + _balances[0x0000000000000000000000000000000000000001].add(amount); + } + } + +``` + +对于每个持有者地址,该函数将持有者的全部余额转移到地址 `0x00...01`,从而有效地销毁它(标准中的实际 `burn` 也会更改总供应量,并将代币转账到 `0x00...00`)。 这意味着 `contract_owner` 可以移除任何用户的资产。 这看起来不像是你希望在治理代币中拥有的功能。 + +### 代码质量问题 {#code-quality-issues} + +这些代码质量问题并不能_证明_这个代码是骗局,但它们让它看起来很可疑。 像 Arbitrum 这样的有组织的公司通常不会发布这么糟糕的代码。 + +#### `mount` 函数 {#the-mount-function} + +虽然[标准](https://eips.ethereum.org/EIPS/eip-20)中没有规定,但一般来说,创建新代币的函数被称为 [`mint`](https://ethereum.org/el/developers/tutorials/erc20-annotated-code/#the-_mint-and-_burn-functions-_mint-and-_burn)。 + +如果我们查看 `wARB` 的构造函数,我们会发现 mint 函数由于某种原因被重命名为 `mount`,并且被调用五次,每次使用初始供应量的五分之一,而不是为了效率一次性处理全部数量。 + +```solidity + constructor () public { + + _name = "Wrapped Arbitrum"; + _symbol = "wARB"; + _decimals = 18; + uint256 initialSupply = 1000000000000; + + mount(deployer, initialSupply*(10**18)/5); + mount(deployer, initialSupply*(10**18)/5); + mount(deployer, initialSupply*(10**18)/5); + mount(deployer, initialSupply*(10**18)/5); + mount(deployer, initialSupply*(10**18)/5); + } +``` + +`mount` 函数本身也很可疑。 + +```solidity + function mount(address account, uint256 amount) public { + require(msg.sender == contract_owner, "ERC20: mint to the zero address"); +``` + +查看 `require`,我们发现只有合约所有者被允许铸币。 这是合法的。 但是错误信息应该是_只有所有者才能铸币_或类似的东西。 相反,它使用了不相关的 _ERC20: mint to the zero address_。 检查是否铸币到零地址的正确测试是 `require(account != address(0), "")`,但该合约从未费心去检查。 + +```solidity + _totalSupply = _totalSupply.add(amount); + _balances[contract_owner] = _balances[contract_owner].add(amount); + emit Transfer(address(0), account, amount); + } +``` + +还有两个与铸币直接相关的可疑事实: + +- 有一个 `account` 参数,大概是应该接收铸币数量的帐户。 但增加的余额实际上是 `contract_owner` 的。 + +- 虽然增加的余额属于 `contract_owner`,但发出的事件却显示了一笔向 `account` 的转账。 + +### 为什么同时有 `auth` 和 `approver`? 为什么 `mod` 什么都不做? {#why-both-autho-and-approver-why-the-mod-that-does-nothing} + +这个合约包含三个修饰符:`_mod_`、`auth` 和 `approver`。 + +```solidity + modifier _mod_(address sender, address recipient, uint256 amount){ + _; + } +``` + +`_mod_` 接收三个参数,但不对它们做任何处理。 为什么要有它? + +```solidity + modifier auth() { + require(msg.sender == contract_owner, "Not allowed to interact"); + _; + } + + modifier approver() { + require(msg.sender == contract_owner, "Not allowed to interact"); + _; + } +``` + +`auth` 和 `approver` 更合理,因为它们检查合约是否由 `contract_owner` 调用。 我们期望某些特权操作,例如铸币,仅限于该帐户。 然而,设置两个功能_完全相同的_独立函数有什么意义呢? + +## 我们可以自动检测到什么? {#what-can-we-detect-automatically} + +通过查看 Etherscan,我们可以看到 `wARB` 是一个诈骗代币。 然而,这是一个中心化的解决方案。 理论上,Etherscan 可能会被颠覆或黑客攻击。 最好能够独立判断一个代币是否合法。 + +我们可以通过查看它们发出的事件来使用一些技巧来识别一个 ERC-20 代币是否可疑(无论是骗局还是写得非常糟糕)。 + +## 可疑的 `Approval` 事件 {#suspicious-approval-events} + +[`Approval` 事件](https://eips.ethereum.org/EIPS/eip-20#approval)只应在直接请求下发生(与 [`Transfer` 事件](https://eips.ethereum.org/EIPS/eip-20#transfer-1) 不同,后者可能因授权而发生)。 关于此问题的详细解释以及为何请求需要是直接的,而不是由合约介导,请参阅 [Solidity 文档](https://docs.soliditylang.org/en/v0.8.20/security-considerations.html#tx-origin)。 + +这意味着批准从[外部所有的帐户](/developers/docs/accounts/#types-of-account)支出的 `Approval` 事件必须来自源于该帐户且目的地为 ERC-20 合约的交易。 来自外部所有的帐户的任何其他类型的批准都是可疑的。 + +这里有一个[识别这类事件的程序](https://github.com/qbzzt/20230915-scam-token-detection),它使用了 [viem](https://viem.sh/) 和 [TypeScript](https://www.typescriptlang.org/docs/),这是一种具有类型安全的 JavaScript 变体。 要运行它: + +1. 将 `.env.example` 复制到 `.env`。 +2. 编辑 `.env` 以提供以太坊主网节点的 URL。 +3. 运行 `pnpm install` 以安装必要的包。 +4. 运行 `pnpm susApproval` 以查找可疑的批准。 + +下面是逐行解释: + +```typescript +import { + Address, + TransactionReceipt, + createPublicClient, + http, + parseAbiItem, +} from "viem" +import { mainnet } from "viem/chains" +``` + +从 `viem` 导入类型定义、函数和链定义。 + +```typescript +import { config } from "dotenv" +config() +``` + +读取 `.env` 以获取 URL。 + +```typescript +const client = createPublicClient({ + chain: mainnet, + transport: http(process.env.URL), +}) +``` + +创建一个 Viem 客户端。 我们只需要从区块链读取数据,所以这个客户端不需要私钥。 + +```typescript +const testedAddress = "0xb047c8032b99841713b8e3872f06cf32beb27b82" +const fromBlock = 16859812n +const toBlock = 16873372n +``` + +可疑 ERC-20 合约的地址,以及我们将在其中查找事件的区块。 节点提供商通常会限制我们读取事件的能力,因为带宽可能会变得昂贵。 幸运的是,`wARB` 在 18 小时内没有被使用,所以我们可以查找所有事件(总共只有 13 个)。 + +```typescript +const approvalEvents = await client.getLogs({ + address: testedAddress, + fromBlock, + toBlock, + event: parseAbiItem( + "event Approval(address indexed _owner, address indexed _spender, uint256 _value)" + ), +}) +``` + +这是向 Viem 请求事件信息的方式。 当我们向它提供确切的事件签名,包括字段名称时,它会为我们解析事件。 + +```typescript +const isContract = async (addr: Address): boolean => + await client.getBytecode({ address: addr }) +``` + +我们的算法仅适用于外部所有的帐户。 如果 `client.getBytecode` 返回任何字节码,这意味着这是一个合约,我们应该直接跳过它。 + +如果你以前没有使用过 TypeScript,函数定义可能看起来有点奇怪。 我们不仅告诉它第一个(也是唯一的)参数叫做 `addr`,还告诉它类型是 `Address`。 同样,`: boolean` 部分告诉 TypeScript 该函数的返回值是布尔值。 + +```typescript +const getEventTxn = async (ev: Event): TransactionReceipt => + await client.getTransactionReceipt({ hash: ev.transactionHash }) +``` + +这个函数从一个事件中获取交易收据。 我们需要收据来确保我们知道交易的目的地是什么。 + +```typescript +const suspiciousApprovalEvent = async (ev : Event) : (Event | null) => { +``` + +这是最重要的函数,它实际决定了一个事件是否可疑。 返回类型 `(Event | null)` 告诉 TypeScript 这个函数可以返回一个 `Event` 或 `null`。 如果事件不可疑,我们返回 `null`。 + +```typescript +const owner = ev.args._owner +``` + +Viem 有字段名称,所以它为我们解析了事件。 `_owner` 是要花费的代币的所有者。 + +```typescript +// 合约的批准不可疑 +if (await isContract(owner)) return null +``` + +如果所有者是合约,则假定此批准不可疑。 要检查合约的批准是否可疑,我们需要追踪交易的完整执行过程,看它是否到达了所有者合约,以及该合约是否直接调用了 ERC-20 合约。 这比我们想做的要消耗更多资源。 + +```typescript +const txn = await getEventTxn(ev) +``` + +如果批准来自外部所有的帐户,获取导致它的交易。 + +```typescript +// 如果批准来自不是交易 `from` 的 EOA 所有者,则该批准是可疑的 +if (owner.toLowerCase() != txn.from.toLowerCase()) return ev +``` + +我们不能只检查字符串是否相等,因为地址是十六进制的,所以它们包含字母。 有时,例如在 `txn.from` 中,这些字母都是小写的。 在其他情况下,例如 `ev.args._owner`,地址是[用于错误识别的混合大小写](https://eips.ethereum.org/EIPS/eip-55)。 + +但是如果交易不是来自所有者,并且该所有者是外部所有的,那么我们就有一个可疑的交易。 + +```typescript +// 如果交易目的地不是我们正在 +// 调查的 ERC-20 合约,那也是可疑的 +if (txn.to.toLowerCase() != testedAddress) return ev +``` + +同样,如果交易的 `to` 地址,即第一个被调用的合约,不是正在调查的 ERC-20 合约,那么它就是可疑的。 + +```typescript + // 如果没有理由怀疑,则返回 null。 + return null +} +``` + +如果两个条件都不成立,那么 `Approval` 事件就不可疑。 + +```typescript +const testPromises = approvalEvents.map((ev) => suspiciousApprovalEvent(ev)) +const testResults = (await Promise.all(testPromises)).filter((x) => x != null) + +console.log(testResults) +``` + +[`async` 函数](https://www.w3schools.com/js/js_async.asp)返回一个 `Promise` 对象。 使用常见语法 `await x()`,我们在继续处理之前等待该 `Promise` 完成。 这在编程和理解上很简单,但效率也很低。 在等待特定事件的 `Promise` 完成时,我们已经可以开始处理下一个事件了。 + +这里我们使用 [`map`](https://www.w3schools.com/jsref/jsref_map.asp) 来创建一个 `Promise` 对象数组。 然后我们使用 [`Promise.all`](https://www.javascripttutorial.net/es6/javascript-promise-all/) 等待所有这些 promise 完成。 然后我们 [`filter`](https://www.w3schools.com/jsref/jsref_filter.asp) 这些结果以移除不可疑的事件。 + +### 可疑的 `Transfer` 事件 {#suspicious-transfer-events} + +另一种识别诈骗代币的可能方法是查看它们是否有任何可疑的转账。 例如,从没有那么多代币的帐户进行的转账。 你可以看到[如何实现这个测试](https://github.com/qbzzt/20230915-scam-token-detection/blob/main/susTransfer.ts),但 `wARB` 没有这个问题。 + +## 结论 {#conclusion} + +ERC-20 诈骗的自动检测存在[假阴性](https://en.wikipedia.org/wiki/False_positives_and_false_negatives#False_negative_error)问题,因为骗局可以使用一个完全正常的 ERC-20 代币合约,而这个合约只是不代表任何真实的东西。 所以你应该总是尝试_从可信来源获取代币地址_。 + +自动检测在某些情况下可以提供帮助,例如在 DeFi 组件中,那里有许多代币,需要自动处理。 但一如既往,[买家自负](https://www.investopedia.com/terms/c/caveatemptor.asp),自己做研究,并鼓励你的用户也这样做。 + +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 diff --git a/public/content/translations/zh/developers/tutorials/secret-state/index.md b/public/content/translations/zh/developers/tutorials/secret-state/index.md new file mode 100644 index 00000000000..fc98817c210 --- /dev/null +++ b/public/content/translations/zh/developers/tutorials/secret-state/index.md @@ -0,0 +1,589 @@ +--- +title: "为保密状态使用零知识" +description: "链上游戏受到限制,因为它们无法保留任何隐藏信息。 阅读本教程后,读者将能够结合零知识证明和服务器组件,创建具有脱链保密状态组件的可验证游戏。 我们将通过创建一个扫雷游戏来演示实现此目标的技术。" +author: Ori Pomerantz +tags: [ "服务器", "链下", "中心化", "零知识", "zokrates", "mud" ] +skill: advanced +lang: zh +published: 2025-03-15 +--- + +_区块链上没有秘密_。 发布在区块链上的所有内容都对所有人开放阅读。 这是必要的,因为区块链的基础是任何人都能对其进行验证。 然而,游戏通常依赖于保密状态。 例如,如果可以去区块链浏览器上查看地图,那么[扫雷](https://en.wikipedia.org/wiki/Minesweeper_\(video_game\))游戏就毫无意义。 + +最简单的解决方案是使用[服务器组件](/developers/tutorials/server-components/)来保存保密状态。 然而,我们使用区块链的原因是防止游戏开发者作弊。 我们需要确保服务器组件的诚实性。 服务器可以提供状态的哈希,并使用[零知识证明](/zero-knowledge-proofs/#why-zero-knowledge-proofs-are-important)来证明用于计算移动结果的状态是正确的。 + +阅读本文后,你将了解如何创建这种保存保密状态的服务器、用于显示状态的客户端以及用于两者之间通信的链上组件。 我们使用的主要工具将是: + +| 工具 | 目的 | 已在版本上验证 | +| --------------------------------------------- | ------------ | --------------------------------------: | +| [Zokrates](https://zokrates.github.io/) | 零知识证明及其验证 | 1.1.9 | +| [Typescript](https://www.typescriptlang.org/) | 服务器和客户端的编程语言 | 5.4.2 | +| [Node](https://nodejs.org/en) | 运行服务器 | 20.18.2 | +| [Viem](https://viem.sh/) | 与区块链通信 | 2.9.20 | +| [MUD](https://mud.dev/) | 链上数据管理 | 2.0.12 | +| [React](https://react.dev/) | 客户端用户界面 | 18.2.0 | +| [Vite](https://vitejs.dev/) | 提供客户端代码 | 4.2.1 | + +## 扫雷示例 {#minesweeper} + +[扫雷](https://en.wikipedia.org/wiki/Minesweeper_\(video_game\)) 是一款包含带雷区秘密地图的游戏。 玩家选择在特定位置挖掘。 如果该位置有地雷,游戏结束。 否则,玩家会得到该位置周围八个方格中的地雷数量。 + +此应用程序使用 [MUD](https://mud.dev/) 编写,这是一个允许我们使用[键值数据库](https://aws.amazon.com/nosql/key-value/)在链上存储数据并自动与脱链组件同步该数据的框架。 除了同步之外,MUD 还可以轻松地提供访问控制,并让其他用户无需许可即可[扩展](https://mud.dev/guides/extending-a-world)我们的应用程序。 + +### 运行扫雷示例 {#running-minesweeper-example} + +要运行扫雷示例: + +1. 确保你已[安装先决条件](https://mud.dev/quickstart#prerequisites):[Node](https://mud.dev/quickstart#prerequisites)、[Foundry](https://book.getfoundry.sh/getting-started/installation)、[`git`](https://git-scm.com/downloads)、[`pnpm`](https://git-scm.com/downloads) 和 [`mprocs`](https://github.com/pvolok/mprocs)。 + +2. 克隆存储库。 + + ```sh copy + git clone https://github.com/qbzzt/20240901-secret-state.git + ``` + +3. 安装软件包。 + + ```sh copy + cd 20240901-secret-state/\npnpm install\nnpm install -g mprocs + ``` + + 如果 Foundry 是作为 `pnpm install` 的一部分安装的,你需要重新启动命令行 shell。 + +4. 编译合约 + + ```sh copy + cd packages/contracts\nforge build\ncd ../.. + ``` + +5. 启动程序(包括 [anvil](https://book.getfoundry.sh/anvil/) 区块链)并等待。 + + ```sh copy + mprocs + ``` + + 请注意,启动需要很长时间。 要查看进度,首先使用向下箭头滚动到 _contracts_ 选项卡,查看正在部署的 MUD 合约。 当收到 _Waiting for file changes…_ 信息时,合约已部署,进一步的进度将在 _server_ 选项卡中进行。 在那里,等待直到收到信息 _Verifier address: 0x...._。 + + 如果此步骤成功,你将看到 `mprocs` 屏幕,左侧是不同的进程,右侧是当前选定进程的控制台输出。 + + ![mprocs 屏幕](./mprocs.png) + + 如果 `mprocs` 出现问题,你可以在各自的命令行窗口中手动运行四个进程: + + - **Anvil** + + ```sh + cd packages/contracts\nanvil --base-fee 0 --block-time 2 + ``` + + - **合约** + + ```sh + cd packages/contracts\npnpm mud dev-contracts --rpc http://127.0.0.1:8545 + ``` + + - **服务器** + + ```sh + cd packages/server\npnpm start + ``` + + - **客户端** + + ```sh + cd packages/client\npnpm run dev + ``` + +6. 现在你可以浏览到[客户端](http://localhost:3000),点击**新游戏**,然后开始玩。 + +### 表 {#tables} + +我们需要在链上创建[多个表](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/mud.config.ts)。 + +- `Configuration`:此表是单例,没有键,只有一条记录。 它用于保存游戏配置信息: + - `height`:雷区的高度 + - `width`:雷区的宽度 + - `numberOfBombs`:每个雷区中的炸弹数量 + +- `VerifierAddress`:此表也是单例。 它用于保存配置的一部分,即验证者合约 (`verifier`) 的地址。 我们可以将此信息放在 `Configuration` 表中,但它是由不同的组件(服务器)设置的,因此将其放在单独的表中更容易。 + +- `PlayerGame`:键是玩家的地址。 数据为: + + - `gameId`:32 字节的值,是玩家正在玩的地图的哈希(游戏标识符)。 + - `win`:一个布尔值,表示玩家是否赢得游戏。 + - `lose`:一个布尔值,表示玩家是否输掉游戏。 + - `digNumber`:游戏中成功挖掘的次数。 + +- `GamePlayer`:此表保存反向映射,从 `gameId` 到玩家地址。 + +- `Map`:键是包含三个值的元组: + + - `gameId`:32 字节的值,是玩家正在玩的地图的哈希(游戏标识符)。 + - `x` 坐标 + - `y` 坐标 + + 值是一个数字。 如果检测到炸弹,则为 255。 否则,它是该位置周围的炸弹数量加一。 我们不能只使用炸弹的数量,因为默认情况下 EVM 中的所有存储和 MUD 中的所有行值都为零。 我们需要区分“玩家还没有在这里挖掘”和“玩家在这里挖掘了,发现周围没有炸弹”。 + +此外,客户端和服务器之间的通信通过链上组件进行。 这也是使用表实现的。 + +- `PendingGame`:未处理的开始新游戏的请求。 +- `PendingDig`:未处理的在特定游戏中特定位置挖掘的请求。 这是一个[脱链表](https://mud.dev/store/tables#types-of-tables),意味着它不会写入 EVM 存储,只能使用事件在脱链上读取。 + +### 执行和数据流 {#execution-data-flows} + +这些流程协调客户端、链上组件和服务器之间的执行。 + +#### 初始化 {#initialization-flow} + +当你运行 `mprocs` 时,会发生以下步骤: + +1. [`mprocs`](https://github.com/pvolok/mprocs) 运行四个组件: + + - [Anvil](https://book.getfoundry.sh/anvil/),运行本地区块链 + - [Contracts](https://github.com/qbzzt/20240901-secret-state/tree/main/packages/contracts),它会编译(如果需要)和部署 MUD 的合约 + - [Client](https://github.com/qbzzt/20240901-secret-state/tree/main/packages/client),它运行 [Vite](https://vitejs.dev/) 来为网络浏览器提供 UI 和客户端代码。 + - [Server](https://github.com/qbzzt/20240901-secret-state/tree/main/packages/server),它执行服务器操作 + +2. `contracts` 包部署 MUD 合约,然后运行[ `PostDeploy.s.sol` 脚本](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/script/PostDeploy.s.sol)。 此脚本设置配置。 来自 github 的代码指定了[一个 10x5 的雷区,其中有 8 个地雷](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/script/PostDeploy.s.sol#L23)。 + +3. [服务器](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts) 通过[设置 MUD](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L6) 来启动。 除此之外,这会激活数据同步,以便在服务器内存中存在相关表的副本。 + +4. 服务器订阅一个函数,该函数在 [`Configuration` 表更改时](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L23)执行。 `PostDeploy.s.sol` 执行并修改表后,会调用[此函数](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L24-L168)。 + +5. 当服务器初始化函数获取配置后,[它会调用 `zkFunctions`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L34-L35)来初始化[服务器的零知识部分](#using-zokrates-from-typescript)。 这只有在我们获得配置后才能发生,因为零知识函数必须将雷区的宽度和高度作为常量。 + +6. 服务器的零知识部分初始化后,下一步是[将零知识验证合约部署到区块链](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L42-L53)并在 MUD 中设置被验证者地址。 + +7. 最后,我们订阅更新,这样当玩家请求[开始新游戏](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L55-L71)或[在现有游戏中挖掘](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L73-L108)时,我们就能看到。 + +#### 新游戏 {#new-game-flow} + +这是当玩家请求新游戏时发生的情况。 + +1. 如果此玩家没有进行中的游戏,或者有一个但 gameId 为零的游戏,客户端会显示一个[新游戏按钮](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/App.tsx#L175)。 当用户按下此按钮时,[React 会运行 `newGame` 函数](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/App.tsx#L96)。 + +2. [`newGame`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/mud/createSystemCalls.ts#L43-L46) 是一个 `System` 调用。 在 MUD 中,所有调用都通过 `World` 合约路由,在大多数情况下,你调用 `__`。 在这种情况下,调用的是 `app__newGame`,然后 MUD 将其路由到 [`GameSystem` 中的 `newGame`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/GameSystem.sol#L16-L22)。 + +3. 链上函数检查玩家是否没有进行中的游戏,如果没有,则[将请求添加到 `PendingGame` 表](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/GameSystem.sol#L21)。 + +4. 服务器检测到 `PendingGame` 中的更改并[运行订阅的函数](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L55-L71)。 此函数调用 [`newGame`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L110-L114),后者又调用 [`createGame`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L116-L144)。 + +5. `createGame` 做的第一件事是[创建一个包含适当数量地雷的随机地图](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L120-L135)。 然后,它调用 [`makeMapBorders`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L147-L166) 来创建一张带有空白边框的地图,这对于 Zokrates 是必需的。 最后,`createGame`调用 [`calculateMapHash`](#calculateMapHash),以获取地图的哈希,该哈希用作游戏 ID。 + +6. `newGame` 函数将新游戏添加到 `gamesInProgress`。 + +7. 服务器做的最后一件事是调用 [`app__newGameResponse`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L38-L43),这是链上操作。 此函数位于不同的 `System` 中,即 [`ServerSystem`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol),以启用访问控制。 访问控制在 [MUD 配置文件](https://mud.dev/config) [`mud.config.ts`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/mud.config.ts#L67-L72) 中定义。 + + 访问列表只允许单个地址调用 `System`。 这将服务器功能的访问权限限制为单个地址,因此没有人可以冒充服务器。 + +8. 链上组件更新相关表: + + - 在 `PlayerGame` 中创建游戏。 + - 在 `GamePlayer` 中设置反向映射。 + - 从 `PendingGame` 中删除请求。 + +9. 服务器识别到 `PendingGame` 中的变化,但由于 [`wantsGame`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L58-L60) 为 false,因此不执行任何操作。 + +10. 在客户端,[`gameRecord`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/App.tsx#L143-L148) 被设置为玩家地址的 `PlayerGame` 条目。 当 `PlayerGame` 改变时,`gameRecord` 也会改变。 + +11. 如果 `gameRecord` 中有值,并且游戏尚未分出胜负,客户端会[显示地图](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/App.tsx#L175-L190)。 + +#### 挖掘 {#dig-flow} + +1. 玩家[点击地图单元格的按钮](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/App.tsx#L188),这会调用 [`dig` 函数](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/mud/createSystemCalls.ts#L33-L36)。 此函数在链上调用 [`dig`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/GameSystem.sol#L24-L32)。 + +2. 链上组件[执行多项健全性检查](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/GameSystem.sol#L25-L30),如果成功,则将挖掘请求添加到 [`PendingDig`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/GameSystem.sol#L31)。 + +3. 服务器[检测到 `PendingDig` 中的变化](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L73)。 [如果有效](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L75-L84),它会[调用零知识代码](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L86-L95)(如下所述)来生成结果和证明其有效的证据。 + +4. [服务器](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L97-L107) 在链上调用 [`digResponse`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L45-L64)。 + +5. `digResponse` 做两件事。 首先,它检查[零知识证明](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L47-L61)。 然后,如果证明通过,它会调用 [`processDigResult`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L67-L86) 来实际处理结果。 + +6. `processDigResult` 检查游戏是否[失败](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L76-L78)或[获胜](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L83-L86),并[更新 `Map`(链上地图)](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol#L80)。 + +7. 客户端会自动获取更新并[更新显示给玩家的地图](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/client/src/App.tsx#L175-L190),并在适用时告知玩家是赢是输。 + +## 使用 Zokrates {#using-zokrates} + +在上面解释的流程中,我们跳过了零知识部分,将其视为一个黑匣子。 现在让我们打开它,看看这段代码是如何编写的。 + +### 对地图进行哈希 {#hashing-map} + +我们可以使用[此 JavaScript 代码](https://github.com/ZK-Plus/ICBC24_Tutorial_Compute-Offchain-Verify-onchain/tree/solutions/exercise) 来实现我们使用的 Zokrates 哈希函数 [Poseidon](https://www.poseidon-hash.info)。 然而,虽然这样做会更快,但也会比仅仅使用 Zokrates 哈希函数来做要复杂得多。 这是一个教程,因此代码为简单性而非性能进行了优化。 因此,我们需要两个不同的 Zokrates 程序,一个仅用于计算地图的哈希(`hash`),另一个用于实际创建地图上某个位置挖掘结果的零知识证明(`dig`)。 + +### 哈希函数 {#hash-function} + +这是计算地图哈希的函数。 我们将逐行分析这段代码。 + +``` +import "hashes/poseidon/poseidon.zok" as poseidon;\nimport "utils/pack/bool/pack128.zok" as pack128; +``` + +这两行从 [Zokrates 标准程序库](https://zokrates.github.io/toolbox/stdlib.html)中导入两个函数。 [第一个函数](https://github.com/Zokrates/ZoKrates/blob/latest/zokrates_stdlib/stdlib/hashes/poseidon/poseidon.zok)是 [Poseidon 哈希](https://www.poseidon-hash.info/)。 它接受一个 [`field` 元素](https://zokrates.github.io/language/types.html#field)数组并返回一个 `field`。 + +Zokrates 中的字段元素通常小于 256 位,但相差不大。 为了简化代码,我们将地图限制为最多 512 位,并对一个包含四个字段的数组进行哈希,每个字段我们只使用 128 位。 为此,[`pack128` 函数](https://github.com/Zokrates/ZoKrates/blob/latest/zokrates_stdlib/stdlib/utils/pack/bool/pack128.zok)将一个 128 位数组转换为一个 `field`。 + +``` + def hashMap(bool[${width+2}][${height+2}] map) -> field { +``` + +这一行开始了一个函数定义。 `hashMap` 接受一个名为 `map` 的参数,它是一个二维 `bool`(ean) 数组。 地图的尺寸是 `width+2` 乘以 `height+2`,原因[在下面解释](#why-map-border)。 + +我们可以使用 `${width+2}` 和 `${height+2}`,因为 Zokrates 程序在此应用程序中作为[模板字符串](https://www.w3schools.com/js/js_string_templates.asp)存储。 `${` 和 `}` 之间的代码由 JavaScript 评估,这样程序就可以用于不同的地图大小。 地图参数周围有一个单位宽度的无炸弹边框,这就是我们需要将宽度和高度加二的原因。 + +返回值是一个包含哈希的 `field`。 + +``` + bool[512] mut map1d = [false; 512]; +``` + +地图是二维的。 然而,`pack128` 函数不适用于二维数组。 所以我们首先使用 `map1d` 将地图展平为一个 512 字节的数组。 默认情况下,Zokrates 变量是常量,但我们需要在循环中为这个数组赋值,所以我们将其定义为 [`mut`](https://zokrates.github.io/language/variables.html#mutability)。 + +我们需要初始化数组,因为 Zokrates 没有 `undefined`。 `[false; 512]` 表达式表示[一个包含 512 个 `false` 值的数组](https://zokrates.github.io/language/types.html#declaration-and-initialization)。 + +``` + u32 mut counter = 0; +``` + +我们还需要一个计数器来区分我们在 `map1d` 中已经填充的位和尚未填充的位。 + +``` + for u32 x in 0..${width+2} { +``` + +这是在 Zokrates 中声明 [`for` 循环](https://zokrates.github.io/language/control_flow.html#for-loops)的方式。 Zokrates 的 `for` 循环必须有固定的边界,因为虽然它看起来像一个循环,但编译器实际上会“展开”它。 表达式 `${width+2}` 是一个编译时常量,因为 `width` 是在 TypeScript 代码调用编译器之前设置的。 + +``` + for u32 y in 0..${height+2} {\n map1d[counter] = map[x][y];\n counter = counter+1;\n }\n } +``` + +对于地图中的每个位置,将该值放入 `map1d` 数组并增加计数器。 + +``` + field[4] hashMe = [\n pack128(map1d[0..128]),\n pack128(map1d[128..256]),\n pack128(map1d[256..384]),\n pack128(map1d[384..512])\n ]; +``` + +`pack128` 用于从 `map1d` 创建一个包含四个 `field` 值的数组。 在 Zokrates 中,`array[a..b]` 表示从 `a` 开始到 `b-1` 结束的数组切片。 + +``` + return poseidon(hashMe);\n} +``` + +使用 `poseidon` 将此数组转换为哈希。 + +### 哈希程序 {#hash-program} + +服务器需要直接调用 `hashMap` 来创建游戏标识符。 然而,Zokrates 只能调用程序上的 `main` 函数来启动,所以我们创建了一个带有 `main` 的程序,该程序调用哈希函数。 + +``` +${hashFragment}\n\ndef main(bool[${width+2}][${height+2}] map) -> field {\n return hashMap(map);\n} +``` + +### 挖掘程序 {#dig-program} + +这是应用程序零知识部分的核心,我们在这里生成用于验证挖掘结果的证明。 + +``` +${hashFragment}\n\n// (x,y) 位置的地雷数量\ndef map2mineCount(bool[${width+2}][${height+2}] map, u32 x, u32 y) -> u8 {\n return if map[x+1][y+1] { 1 } else { 0 };\n} +``` + +#### 为何需要地图边框 {#why-map-border} + +零知识证明使用[算术电路](https://medium.com/web3studio/simple-explanations-of-arithmetic-circuits-and-zero-knowledge-proofs-806e59a79785),它没有 `if` 语句的简单等价物。 相反,它们使用[条件运算符](https://en.wikipedia.org/wiki/Ternary_conditional_operator)的等价物。 如果 `a` 可以是零或一,你可以将 `if a { b } else { c }` 计算为 `ab+(1-a)c`。 + +因此,Zokrates 的 `if` 语句总是会评估两个分支。 例如,如果你有以下代码: + +``` +bool[5] arr = [false; 5];\nu32 index=10;\nreturn if index>4 { 0 } else { arr[index] } +``` + +它会出错,因为它需要计算 `arr[10]`,即使该值稍后会乘以零。 + +这就是为什么我们需要在地图周围设置一个单位宽度的边框。 我们需要计算一个位置周围的地雷总数,这意味着我们需要看到我们正在挖掘的位置的上方一行、下方一行、左边和右边的位置。 这意味着这些位置必须存在于提供给 Zokrates 的地图数组中。 + +``` +def main(private bool[${width+2}][${height+2}] map, u32 x, u32 y) -> (field, u8) { +``` + +默认情况下,Zokrates 证明包含其输入。 知道一个地点周围有五个地雷是没有用的,除非你真的知道是哪个地点(而且你不能仅仅将它与你的请求匹配,因为那样证明者可能会使用不同的值而不会告诉你)。 然而,我们需要在将地图提供给 Zokrates 的同时保持其保密。 解决方案是使用一个 `private` 参数,一个_不_被证明揭示的参数。 + +这为滥用开辟了另一条途径。 证明者可以使用正确的坐标,但在该位置周围创建一个包含任意数量地雷的地图,甚至可能在该位置本身创建地雷。 为防止这种滥用,我们让零知识证明包含地图的哈希,即游戏标识符。 + +``` + return (hashMap(map), +``` + +这里的返回值是一个元组,包括地图哈希数组和挖掘结果。 + +``` + if map2mineCount(map, x, y) > 0 { 0xFF } else { +``` + +如果该位置本身有炸弹,我们使用 255 作为特殊值。 + +``` + map2mineCount(map, x-1, y-1) + map2mineCount(map, x, y-1) + map2mineCount(map, x+1, y-1) +\n map2mineCount(map, x-1, y) + map2mineCount(map, x+1, y) +\n map2mineCount(map, x-1, y+1) + map2mineCount(map, x, y+1) + map2mineCount(map, x+1, y+1)\n }\n );\n} +``` + +如果玩家没有踩到地雷,则将该位置周围区域的地雷数量相加并返回。 + +### 在 TypeScript 中使用 Zokrates {#using-zokrates-from-typescript} + +Zokrates 有一个命令行界面,但在这个程序中,我们在 [TypeScript 代码](https://zokrates.github.io/toolbox/zokrates_js.html)中使用它。 + +包含 Zokrates 定义的程序库名为 [`zero-knowledge.ts`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts)。 + +```typescript +import { initialize as zokratesInitialize } from "zokrates-js" +``` + +导入 [Zokrates JavaScript 绑定](https://zokrates.github.io/toolbox/zokrates_js.html)。 我们只需要 [`initialize`](https://zokrates.github.io/toolbox/zokrates_js.html#initialize) 函数,因为它返回一个解析为所有 Zokrates 定义的 promise。 + +```typescript +export const zkFunctions = async (width: number, height: number) : Promise => { +``` + +与 Zokrates 本身类似,我们也只导出一个函数,该函数也是[异步的](https://www.w3schools.com/js/js_async.asp)。 当它最终返回时,它提供了几个函数,如下所示。 + +```typescript +const zokrates = await zokratesInitialize() +``` + +初始化 Zokrates,从程序库中获取我们需要的一切。 + +```typescript +const hashFragment = `\n import "utils/pack/bool/pack128.zok" as pack128;\n import "hashes/poseidon/poseidon.zok" as poseidon;\n .\n .\n .\n }\n `\n\nconst hashProgram = `\n ${hashFragment}\n .\n .\n .\n `\n\nconst digProgram = `\n ${hashFragment}\n .\n .\n .\n ` +``` + +接下来是我们上面看到的哈希函数和两个 Zokrates 程序。 + +```typescript +const digCompiled = zokrates.compile(digProgram)\nconst hashCompiled = zokrates.compile(hashProgram) +``` + +这里我们编译这些程序。 + +```typescript +// 为零知识验证创建密钥。\n// 在生产系统上,您需要使用设置仪式。\n// (https://zokrates.github.io/toolbox/trusted_setup.html#initializing-a-phase-2-ceremony)。\nconst keySetupResults = zokrates.setup(digCompiled.program, "")\nconst verifierKey = keySetupResults.vk\nconst proverKey = keySetupResults.pk +``` + +在生产系统上,我们可能会使用更复杂的[设置仪式](https://zokrates.github.io/toolbox/trusted_setup.html#initializing-a-phase-2-ceremony),但对于演示来说,这已经足够了。 用户知道证明者密钥不是问题 - 他们仍然不能用它来证明事情,除非它们是真实的。 因为我们指定了熵(第二个参数,`""`),所以结果总是相同的。 + +\*\*注意:\*\*Zokrates 程序的编译和密钥创建是缓慢的过程。 不需要每次都重复它们,只需在地图大小改变时重复即可。 在生产系统上,你只需执行一次,然后存储输出。 我在这里不这样做只是为了简单起见。 + +#### `calculateMapHash` {#calculateMapHash} + +```typescript +const calculateMapHash = function (hashMe: boolean[][]): string {\n return (\n "0x" +\n BigInt(zokrates.computeWitness(hashCompiled, [hashMe]).output.slice(1, -1))\n .toString(16)\n .padStart(64, "0")\n )\n} +``` + +[`computeWitness`](https://zokrates.github.io/toolbox/zokrates_js.html#computewitnessartifacts-args-options) 函数实际上运行 Zokrates 程序。 它返回一个包含两个字段的结构:`output`,即程序的输出(作为 JSON 字符串),和 `witness`,即创建结果的零知识证明所需的信息。 在这里,我们只需要输出。 + +输出是一个形如 `"31337"` 的字符串,即一个用引号括起来的十进制数。 但我们需要的 `viem` 输出是形如 `0x60A7` 的十六进制数。 所以我们使用 `.slice(1,-1)` 去掉引号,然后用 `BigInt` 将剩余的字符串(一个十进制数)转换成一个 [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)。 `.toString(16)` 将这个 `BigInt` 转换成一个十六进制字符串,`"0x"+` 添加了十六进制数的标记。 + +```typescript +// 挖掘并返回结果的零知识证明\n// (服务器端代码) +``` + +零知识证明包括公共输入(`x` 和 `y`)和结果(地图的哈希和炸弹数量)。 + +```typescript + const zkDig = function(map: boolean[][], x: number, y: number) : any {\n if (x<0 || x>=width || y<0 || y>=height)\n throw new Error("Trying to dig outside the map") +``` + +在 Zokrates 中检查索引是否越界是个问题,所以我们在这里做。 + +```typescript +const runResults = zokrates.computeWitness(digCompiled, [map, `${x}`, `${y}`]) +``` + +执行挖掘程序。 + +```typescript + const proof = zokrates.generateProof(\n digCompiled.program,\n runResults.witness,\n proverKey)\n\n return proof\n } +``` + +使用 [`generateProof`](https://zokrates.github.io/toolbox/zokrates_js.html#generateproofprogram-witness-provingkey-entropy) 并返回证明。 + +```typescript +const solidityVerifier = `\n // 地图尺寸: ${width} x ${height}\n \n${zokrates.exportSolidityVerifier(verifierKey)}\n ` +``` + +一个 Solidity 验证者,这是一个我们可以部署到区块链并用于验证 `digCompiled.program` 生成的证明的智能合约。 + +```typescript + return {\n zkDig,\n calculateMapHash,\n solidityVerifier,\n }\n} +``` + +最后,返回其他代码可能需要的所有内容。 + +## 安全测试 {#security-tests} + +安全测试很重要,因为功能性漏洞最终会暴露出来。 但如果应用程序不安全,那么在有人作弊并窃取他人资源而被揭露之前,这种不安全性很可能会隐藏很长一段时间。 + +### 权限 {#permissions} + +这个游戏中有一个特权实体,即服务器。 它是唯一允许调用 [`ServerSystem`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol) 中函数的用户。 我们可以使用 [`cast`](https://book.getfoundry.sh/cast/) 来验证对有权限函数的调用是否只允许作为服务器帐户进行。 + +[服务器的私钥位于 `setupNetwork.ts`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/mud/setupNetwork.ts#L52)。 + +1. 在运行 `anvil`(区块链)的计算机上,设置这些环境变量。 + + ```sh copy + WORLD_ADDRESS=0x8d8b6b8414e1e3dcfd4168561b9be6bd3bf6ec4b\nUNAUTHORIZED_KEY=0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a\nAUTHORIZED_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d + ``` + +2. 使用 `cast` 尝试将验证者地址设置为未经授权的地址。 + + ```sh copy + cast send $WORLD_ADDRESS 'app__setVerifier(address)' `cast address-zero` --private-key $UNAUTHORIZED_KEY + ``` + + 不仅 `cast` 会报告失败,你还可以在浏览器中的游戏中打开 **MUD 开发工具**,点击**表格**,然后选择 **app\_\_VerifierAddress**。 看到地址不为零。 + +3. 将验证者地址设置为服务器的地址。 + + ```sh copy + cast send $WORLD_ADDRESS 'app__setVerifier(address)' `cast address-zero` --private-key $AUTHORIZED_KEY + ``` + + **app\_\_VerifiedAddress** 中的地址现在应该为零。 + +同一 `System` 中的所有 MUD 函数都经过相同的访问控制,因此我认为此测试已足够。 如果你不这么认为,可以检查 [`ServerSystem`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/contracts/src/systems/ServerSystem.sol) 中的其他函数。 + +### 零知识滥用 {#zero-knowledge-abuses} + +验证 Zokrates 的数学超出了本教程的范围(也超出了我的能力)。 然而,我们可以对零知识代码运行各种检查,以验证如果操作不正确,它会失败。 所有这些测试都将要求我们更改 [`zero-knowledge.ts`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts) 并重新启动整个应用程序。 仅仅重新启动服务器进程是不够的,因为它会将应用程序置于一种不可能的状态(玩家正在进行游戏,但服务器不再可用该游戏)。 + +#### 错误答案 {#wrong-answer} + +最简单的可能性是在零知识证明中提供错误的答案。 为此,我们进入 `zkDig` 内部并[修改第 91 行](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts#L91): + +```ts +proof.inputs[3] = "0x" + "1".padStart(64, "0") +``` + +这意味着无论正确答案是什么,我们总是声称只有一个炸弹。 尝试玩这个版本,你会在 `pnpm dev` 屏幕的**服务器**选项卡中看到这个错误: + +``` + cause: {\n code: 3,\n message: 'execution reverted: revert: Zero knowledge verification fail',\n data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000\n000000000000000000000000000000000000000000000000205a65726f206b6e6f776c6564676520766572696669636174696f6\ne206661696c'\n }, +``` + +所以这种作弊会失败。 + +#### 错误的证明 {#wrong-proof} + +如果我们提供正确的信息,但只有错误的证明数据,会发生什么? 现在,将第 91 行替换为: + +```ts +proof.proof = {\n a: ["0x" + "1".padStart(64, "0"), "0x" + "2".padStart(64, "0")],\n b: [\n ["0x" + "1".padStart(64, "0"), "0x" + "2".padStart(64, "0")],\n ["0x" + "1".padStart(64, "0"), "0x" + "2".padStart(64, "0")],\n ],\n c: ["0x" + "1".padStart(64, "0"), "0x" + "2".padStart(64, "0")],\n} +``` + +它仍然失败,但现在它失败时没有给出原因,因为它是在验证者调用期间发生的。 + +### 用户如何验证零信任代码? {#user-verify-zero-trust} + +智能合约相对容易验证。 通常,开发者会将源代码发布到区块浏览器,区块浏览器会验证源代码确实能编译成[合约部署交易](/developers/docs/smart-contracts/deploying/)中的代码。 在 MUD `System` 的情况下,这[稍微复杂一些](https://mud.dev/cli/verify),但相差不大。 + +对于零知识来说,这更难。 验证者包含一些常量并对它们进行一些计算。 这并不能告诉你正在证明什么。 + +```solidity + function verifyingKey() pure internal returns (VerifyingKey memory vk) {\n vk.alpha = Pairing.G1Point(uint256(0x0f43f4fe7b5c2326fed4ac6ed2f4003ab9ab4ea6f667c2bdd77afb068617ee16), uint256(0x25a77832283f9726935219b5f4678842cda465631e72dbb24708a97ba5d0ce6f));\n vk.beta = Pairing.G2Point([uint256(0x2cebd0fbd21aca01910581537b21ae4fed46bc0e524c055059aa164ba0a6b62b), uint256(0x18fd4a7bc386cf03a95af7163d5359165acc4e7961cb46519e6d9ee4a1e2b7e9)], [uint256(0x11449dee0199ef6d8eebfe43b548e875c69e7ce37705ee9a00c81fe52f11a009), uint256(0x066d0c83b32800d3f335bb9e8ed5e2924cf00e77e6ec28178592eac9898e1a00)]); +``` + +解决方案是,至少在区块浏览器将 Zokrates 验证添加到其用户界面之前,应用程序开发者应提供 Zokrates 程序,并且至少有一些用户使用适当的验证密钥自行编译它们。 + +要做到这一点: + +1. [安装 Zokrates](https://zokrates.github.io/gettingstarted.html)。 + +2. 创建一个文件 `dig.zok`,包含 Zokrates 程序。 下面的代码假设你保留了原始地图尺寸 10x5。 + + ```zokrates + import "utils/pack/bool/pack128.zok" as pack128;\n import "hashes/poseidon/poseidon.zok" as poseidon;\n\n def hashMap(bool[12][7] map) -> field {\n bool[512] mut map1d = [false; 512];\n u32 mut counter = 0;\n\n for u32 x in 0..12 {\n for u32 y in 0..7 {\n map1d[counter] = map[x][y];\n counter = counter+1;\n }\n }\n\n field[4] hashMe = [\n pack128(map1d[0..128]),\n pack128(map1d[128..256]),\n pack128(map1d[256..384]),\n pack128(map1d[384..512])\n ];\n\n return poseidon(hashMe);\n }\n\n\n // (x,y) 位置的地雷数量\n def map2mineCount(bool[12][7] map, u32 x, u32 y) -> u8 {\n return if map[x+1][y+1] { 1 } else { 0 };\n }\n\n def main(private bool[12][7] map, u32 x, u32 y) -> (field, u8) {\n return (hashMap(map) ,\n if map2mineCount(map, x, y) > 0 { 0xFF } else {\n map2mineCount(map, x-1, y-1) + map2mineCount(map, x, y-1) + map2mineCount(map, x+1, y-1) +\n map2mineCount(map, x-1, y) + map2mineCount(map, x+1, y) +\n map2mineCount(map, x-1, y+1) + map2mineCount(map, x, y+1) + map2mineCount(map, x+1, y+1)\n }\n );\n } + ``` + +3. 编译 Zokrates 代码并创建验证密钥。 验证密钥必须使用与原始服务器相同的熵来创建,[在这种情况下为空字符串](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts#L67)。 + + ```sh copy + zokrates compile --input dig.zok\nzokrates setup -e "" + ``` + +4. 自己创建 Solidity 验证者,并验证其功能与区块链上的验证者相同(服务器添加了一条注释,但这不重要)。 + + ```sh copy + zokrates export-verifier\ndiff verifier.sol ~/20240901-secret-state/packages/contracts/src/verifier.sol + ``` + +## 设计决策 {#design} + +在任何足够复杂的应用程序中,都存在需要权衡取舍的相互竞争的设计目标。 让我们看看一些权衡取舍,以及为什么当前的解决方案比其他选项更可取。 + +### 为何使用零知识 {#why-zero-knowledge} + +对于扫雷游戏,你并不真正需要零知识。 服务器可以一直持有地图,然后在游戏结束时才全部揭示。 然后,在游戏结束时,智能合约可以计算地图哈希,验证其是否匹配,如果不匹配,则惩罚服务器或完全忽略该游戏。 + +我没有使用这个更简单的解决方案,因为它只适用于具有明确定义的结束状态的短时游戏。 当一个游戏可能是无限的(例如[自治世界](https://0xparc.org/blog/autonomous-worlds)),你需要一个在_不_揭示状态的情况下证明其状态的解决方案。 + +作为一篇教程,本文需要一个易于理解的短时游戏,但这项技术对于较长的游戏最为有用。 + +### 为何选择 Zokrates? {#why-zokrates} + +[Zokrates](https://zokrates.github.io/) 不是唯一可用的零知识程序库,但它类似于一种普通的[命令式](https://en.wikipedia.org/wiki/Imperative_programming)编程语言,并支持布尔变量。 + +对于你的应用程序,如果有不同的需求,你可能更愿意使用 [Circum](https://docs.circom.io/getting-started/installation/) 或 [Cairo](https://www.cairo-lang.org/tutorials/getting-started-with-cairo/)。 + +### 何时编译 Zokrates {#when-compile-zokrates} + +在这个程序中,我们[每次服务器启动时](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts#L60-L61)都会编译 Zokrates 程序。 这显然是浪费资源,但这是一个教程,为简单性而优化。 + +如果我正在编写一个生产级应用程序,我会检查是否有一个包含此雷区大小的已编译 Zokrates 程序的文件,如果有,就使用它。 在链上部署验证者合约也是如此。 + +### 创建验证者和证明者密钥 {#key-creation} + +[密钥创建](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts#L63-L69)是另一个纯计算,对于给定的雷区大小,不需要执行多次。 同样,为了简单起见,它只执行一次。 + +此外,我们可以使用[一个设置仪式](https://zokrates.github.io/toolbox/trusted_setup.html#initializing-a-phase-2-ceremony)。 设置仪式的优点是,你需要每个参与者的熵或一些中间结果才能在零知识证明上作弊。 如果至少有一名仪式参与者是诚实的并删除了该信息,那么零知识证明就可以免受某些攻击。 然而,_没有机制_可以验证信息已从所有地方删除。 如果零知识证明至关重要,你应参与设置仪式。 + +在这里,我们依赖于[perpetual powers of tau](https://github.com/privacy-scaling-explorations/perpetualpowersoftau),它有数十名参与者。 这可能足够安全,而且简单得多。 我们也不在密钥创建期间添加熵,这使得用户更容易[验证零知识配置](#user-verify-zero-trust)。 + +### 在哪里验证 {#where-verification} + +我们可以在链上(需要消耗燃料)或客户端(使用 [`verify`](https://zokrates.github.io/toolbox/zokrates_js.html#verifyverificationkey-proof))验证零知识证明。 我选择了第一种,因为这让你可以[验证验证者](#user-verify-zero-trust)一次,然后只要其合约地址保持不变,就可以信任它不会改变。 如果在客户端进行验证,你每次下载客户端时都必须验证收到的代码。 + +此外,虽然这个游戏是单人游戏,但许多区块链游戏是多人游戏。 链上验证意味着你只需验证一次零知识证明。 在客户端进行验证将需要每个客户端独立验证。 + +### 在 TypeScript 还是 Zokrates 中展平地图? {#where-flatten} + +总的来说,当处理可以在 TypeScript 或 Zokrates 中完成时,最好在 TypeScript 中完成,因为它速度快得多,并且不需要零知识证明。 例如,这就是我们不向 Zokrates 提供哈希并让其验证其正确性的原因。 哈希必须在 Zokrates 内部完成,但返回的哈希与链上哈希之间的匹配可以在其外部进行。 + +然而,我们仍然在 [Zokrates 中展平地图](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts#L15-L20),而我们本可以在 TypeScript 中完成。 原因是在我看来,其他选择更糟。 + +- 向 Zokrates 代码提供一个一维布尔数组,并使用诸如 `x*(height+2)\n+y` 的表达式来获取二维地图。 这会使[代码](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/zero-knowledge.ts#L44-L47)变得更复杂一些,所以我认为对于一个教程来说,性能提升是不值得的。 + +- 向 Zokrates 发送一维数组和二维数组。 然而,这个解决方案对我们没有任何好处。 Zokrates 代码必须验证提供的一维数组确实是二维数组的正确表示。 所以不会有任何性能提升。 + +- 在 Zokrates 中展平二维数组。 这是最简单的选择,所以我选择了它。 + +### 在哪里存储地图 {#where-store-maps} + +在此应用程序中,[`gamesInProgress`](https://github.com/qbzzt/20240901-secret-state/blob/main/packages/server/src/app.ts#L20) 只是内存中的一个变量。 这意味着如果你的服务器崩溃并需要重新启动,它存储的所有信息都将丢失。 玩家不仅无法继续他们的游戏,甚至无法开始新游戏,因为链上组件认为他们仍在进行游戏。 + +这对于生产系统来说显然是糟糕的设计,在生产系统中,你会将此信息存储在数据库中。 我在这里使用变量的唯一原因是因为这是一个教程,简单性是主要考虑因素。 + +## 结论:在什么条件下这是合适的技术? {#conclusion} + +所以,现在你知道如何编写一个带有服务器的游戏,该服务器存储不属于链上的保密状态。 但在什么情况下你应该这样做呢? 主要有两个考虑因素。 + +- _长期运行的游戏_:[如上所述](#why-zero-knowledge),在短时游戏中,你可以在游戏结束后发布状态,然后对所有内容进行验证。 但当游戏时间很长或不确定,并且状态需要保密时,这就不是一个选项。 + +- _可接受一定的中心化_:零知识证明可以验证完整性,即实体没有伪造结果。 他们不能做的是确保该实体仍然可用并回答信息。 在可用性也需要去中心化的情况下,零知识证明不是一个充分的解决方案,你需要[多方计算](https://en.wikipedia.org/wiki/Secure_multi-party_computation)。 + +[点击此处查看我的更多作品](https://cryptodocguy.pro/)。 + +### 致谢 {#acknowledgements} + +- Alvaro Alonso 阅读了本文的草稿,并澄清了我对 Zokrates 的一些误解。 + +任何剩余的错误都由我负责。 diff --git a/public/content/translations/zh/developers/tutorials/secure-development-workflow/index.md b/public/content/translations/zh/developers/tutorials/secure-development-workflow/index.md index a0e6bdba9bb..eaca9675b65 100644 --- a/public/content/translations/zh/developers/tutorials/secure-development-workflow/index.md +++ b/public/content/translations/zh/developers/tutorials/secure-development-workflow/index.md @@ -1,19 +1,16 @@ --- -title: 智能合约安全清单 -description: 编写安全智能合约的推荐工作流程 +title: "智能合约安全清单" +description: "编写安全智能合约的推荐工作流程" author: "Trailofbits" -tags: - - "智能合约" - - "安全性" - - "solidity" +tags: [ "智能合同", "安全性。", "Solidity" ] skill: intermediate lang: zh published: 2020-09-07 -source: 构建安全的合约 +source: "构建安全的合约" sourceUrl: https://github.com/crytic/building-secure-contracts/blob/master/development-guidelines/workflow.md --- -## 智能合约开发清单 {#smart-contract-development-checklist} +## 智能合约开发核对清单 {#smart-contract-development-checklist} 这是一个高级别的过程,我们建议在你编写智能合约时遵循。 @@ -24,21 +21,21 @@ sourceUrl: https://github.com/crytic/building-secure-contracts/blob/master/devel 考虑你的智能合约的特殊功能: -- 你的合约是否可以升级? 使用 [`slither-check-upgradeability`](https://github.com/crytic/slither/wiki/Upgradeability-Checks) 或 [Crytic](https://blog.trailofbits.com/2020/06/12/upgradeable-contracts-made-safer-with-crytic/) 检查你的可升级代码是否有缺陷。 我们记录了 17 种升级可能出现的问题。 -- 你的合约是否声明符合 ERC 的要求? 使用 [`slither-check-erc`](https://github.com/crytic/slither/wiki/ERC-Conformance) 对它们进行审核。 这个工具能立即识别出六个常见规范的偏差。 -- 你是否与第三方代币集成? 在依赖外部合约之前,请先查看我们的[代币集成清单](/developers/tutorials/token-integration-checklist/)。 +- 你的合约是否可以升级? 使用 [`slither-check-upgradeability`](https://github.com/crytic/slither/wiki/Upgradeability-Checks) 或 [Crytic](https://blog.trailofbits.com/2020/06/12/upgradeable-contracts-made-safer-with-crytic/) 审核可升级代码中的漏洞。 我们记录了 17 种升级可能出现的问题。 +- 你的合约是否声明符合 ERC 的要求? 使用 [`slither-check-erc`](https://github.com/crytic/slither/wiki/ERC-Conformance) 检查它们。 这个工具能立即识别出六个常见规范的偏差。 +- 你是否与第三方代币集成? 在依赖外部合约之前,请查看我们的[代币集成核对清单](/developers/tutorials/token-integration-checklist/)。 目视检查代码的关键安全功能。 -- 查看 Slither 的 [inheritance-graph](https://github.com/trailofbits/slither/wiki/Printer-documentation#inheritance-graph) printer。 避免以外屏蔽和 C3 线性化问题。 -- 查看 Slither 的 [function-summary](https://github.com/trailofbits/slither/wiki/Printer-documentation#function-summary) printer。 它报告功能可见性和访问控制。 -- 查看 Slither 的 [vars-and-auth](https://github.com/trailofbits/slither/wiki/Printer-documentation#variables-written-and-authorization) printer。 它报告了对状态变量的访问控制。 +- 查看 Slither 的 [inheritance-graph](https://github.com/trailofbits/slither/wiki/Printer-documentation#inheritance-graph) 打印机。 避免以外屏蔽和 C3 线性化问题。 +- 查看 Slither 的 [function-summary](https://github.com/trailofbits/slither/wiki/Printer-documentation#function-summary) 打印机。 它报告功能可见性和访问控制。 +- 查看 Slither 的 [vars-and-auth](https://github.com/trailofbits/slither/wiki/Printer-documentation#variables-written-and-authorization) 打印机。 它报告了对状态变量的访问控制。 记录关键安全属性,并使用自动化测试生成器对其进行评估: -- 学习 [记录代码的安全属性](/developers/tutorials/guide-to-smart-contract-security-tools/)。 一开始是艰难的,但它是实现良好结果的最重要的活动。 这也是使用本教程中任何高级技术的先决条件。 -- 在 Solidity 中定义安全属性,用于 [Echidna](https://github.com/crytic/echidna) 和 [Manticore](https://manticore.readthedocs.io/en/latest/verifier.html)。 重点是你的状态机、访问控制、算术运算、外部交互和标准一致性。 -- 使用 [ Slither 的 Python API](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/) 定义安全属性。 重点是继承、变量依赖项、访问控制和其他结构问题。 +- 学习如何[为您的代码记录安全属性](/developers/tutorials/guide-to-smart-contract-security-tools/)。 一开始是艰难的,但它是实现良好结果的最重要的活动。 这也是使用本教程中任何高级技术的先决条件。 +- 在 Solidity 中定义安全属性,以便与 [Echidna](https://github.com/crytic/echidna) 和 [Manticore](https://manticore.readthedocs.io/en/latest/verifier.html) 结合使用。 重点是你的状态机、访问控制、算术运算、外部交互和标准一致性。 +- 使用 [Slither 的 Python API](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/) 定义安全属性。 重点是继承、变量依赖项、访问控制和其他结构问题。 - 在每次提交时,使用 [Crytic](https://crytic.io) 运行你的属性测试。 Crytic 可以使用和评估安全属性测试,因此团队中的每个人都可以轻松地看到他们通过 GitHub。 测试失败会阻止提交。 最后,请注意自动化工具无法轻易找到的问题: @@ -48,8 +45,8 @@ sourceUrl: https://github.com/crytic/building-secure-contracts/blob/master/devel - 加密操作 - 与外部 DeFi 组件的风险互动 -## 寻求帮助 {#ask-for-help} +## 请求帮助 {#ask-for-help} -[以太坊的办公时间](https://calendly.com/dan-trailofbits/office-hours)为每周二下午。 这些 1 小时的 1 对 1 会议是一个机会,你可以向我们询问有关安全的任何问题,使用我们的工具进行故障排除,并获得专家对你当前方法的反馈。 我们将帮助你消化本指南。 +[以太坊答疑时间](https://calendly.com/dan-trailofbits/office-hours)于每周二下午举行。 这些 1 小时的 1 对 1 会议是一个机会,你可以向我们询问有关安全的任何问题,使用我们的工具进行故障排除,并获得专家对你当前方法的反馈。 我们将帮助你消化本指南。 -加入我们的 Slack: [ Empire Hacking](https://join.slack.com/t/empirehacking/shared_invite/zt-h97bbrj8-1jwuiU33nnzg67JcvIciUw)。 如果你有任何问题,可以随时在 #crytic 和 #ethereum 频道上联系我们。 +加入我们的 Slack:[Empire Hacking](https://join.slack.com/t/empirehacking/shared_invite/zt-h97bbrj8-1jwuiU33nnzg67JcvIciUw)。 如果你有任何问题,可以随时在 #crytic 和 #ethereum 频道上联系我们。 diff --git a/public/content/translations/zh/developers/tutorials/send-token-ethersjs/index.md b/public/content/translations/zh/developers/tutorials/send-token-ethersjs/index.md index 649ce0790f5..f3a0e2f2db9 100644 --- a/public/content/translations/zh/developers/tutorials/send-token-ethersjs/index.md +++ b/public/content/translations/zh/developers/tutorials/send-token-ethersjs/index.md @@ -1,27 +1,25 @@ --- -title: 使用 ethers.js 发送代币 -description: 使用 ethers.js 发送代币的初学者入门指南。 +title: "使用 ethers.js 发送代币" +description: "使用 ethers.js 发送代币的初学者友好指南。" author: Kim YongJun -tags: - - "ETHERS.JS" - - "ERC-20" - - "代币" +tags: [ "ETHERS.JS", "ERC-20", "代币" ] skill: beginner lang: zh published: 2021-04-06 --- -## 使用 ethers.js(5.0) 发送代币 {#send-token} +## 使用 ethers.js (5.0) 发送代币 {#send-token} -### 在本教程中,您将学习如何: {#you-learn-about} +### 在本教程中,你将学习如何:{#you-learn-about} - 导入 ethers.js -- 进行代币转账 +- 转账代币 - 根据网络流量情况设置燃料价格 -### 入门指南 {#to-get-started} +### 开始上手 {#to-get-started} -开始前,我们必须先将 ethers.js 库导入我们的 javascript 中 包括 ethers.js(5.0) +开始前,我们必须先将 ethers.js 程序库导入到我们的 javascript 中 +包含 ethers.js (5.0) ### 安装 {#install-ethersjs} @@ -29,16 +27,16 @@ published: 2021-04-06 /home/ricmoo> npm install --save ethers ``` -浏览器版 ES6 +浏览器中的 ES6 ```html ``` -浏览器版 ES3(UMD) +浏览器中的 ES3 (UMD) ```html