了解智能合约:读取、写入和审计了解智能合约:读取、写入和审计

进阶Nov 26, 2023
本文是一则阐释智能合约编程技术(包括其读取、写入和审计)的指南。要使用 Solidity 或其他语言写入智能合约,第一步需要了解智能合约的结构和代码块。考虑到智能合约是去中心化金融(DeFi)和去中心化应用程序(DApp)的核心部分,确保其安全性和完美性至关重要,而智能合约审计在这一方面发挥着重要作用。
了解智能合约:读取、写入和审计了解智能合约:读取、写入和审计

智能合约的读取

智能合约是可编程的代码,仅在满足一组条件时才执行。在现实世界中,与具有法律约束力的合同具有相同含义;只有在这种情况下,代码才是法律。由于智能合约驻留在区块链上,因此它们是不可变的,即无法被篡改。正是这种不变性商数赋予智能合约特殊性。

了解智能合约:基础知识和重要意义

智能合约用于自动化区块链特定的交易。由于它们是特定条件的合约,因此不需要中介机构。智能合约之所以有效,是因为它们在广泛的用例(包括金融服务、供应链管理等)中具有兼容性。与一次性编程的传统代码块不同,智能合约需要高度安全且耗时的策略。

智能合约如何与区块链技术相结合(来源:BeInCrypto)

“流行语“web3”暗含了网络松散、安全性差的编程习惯。当加密货币或智能合约像网页一样编程时,它们就注定会失败。可持续成功的区块链及其应用程序基于更加安全、周密和缓慢的编程方法。”——Nick Szabo,密码学家和计算机科学家发布于Twitter

智能合约可与区块链特定的代币(例如以太坊区块链的 ERC-20)配合使用,从而激励行动并促进交易各处转移。由于涉及代码、条件和成本,您应谨慎读取、写入和审计它们。

智能合约及其意义

智能合约的真正意义在于其本质和定位。对于给定的场景,比如当 A 完成一项服务时,A 将资金转移给 B,区块链节点会保存并执行智能合约的副本。智能合约在链内保存为合约代码。这种多路径验证是一种以区块链为中心的特征,可确保事物的安全。

此外,还存在以次序而发生的智能合约或同步智能合约和异步智能合约,其中任务并行执行。因此,智能合约的类型和用途决定了它的写入、读取甚至审计方式。要明白以下特征:

传统的合同、财产契约、遗嘱等都是私法,即“由私人而不是政客或政府官僚起草”。智能合约就是这种去中心化规则制定的一种新形式。参阅:https://t.co/EU2Y28FznK

— Nick Szabo (@NickSzabo4) 于2018年3月15日发布

让我们考虑一个标准的智能合约管理的流动性池。

想象一下,代币池可用于交易,每次成功进行交易时,总交易价值的0.3%都会发送给流动性提供者,流动性提供者实施交易或为给定的可交易资产增加流动性。所有强调交易场景、交易费用、违规和交易失败的条件都被编码为智能合约,以合约代码的形式存储在链内。

智能合约的特点

如果我们不了解合约的特征,我们就无法深入读取、写入和审计合约。以下是需要明白的标准智能合约特征:

标准智能合约的一些特征(来源:BeInCrypto)

可编程合约

智能合约只是一些代码。您可写入智能合约来根据特定条件执行命令和场景。这就是为什么智能合约开发人员和程序员目前很受大家的青睐,因为大多数 DeFi 领域已经依赖智能合约来处理复杂的实例,例如处理跨流动性池的交易费用、维护 APY 比率等。

去信任的

驻留在区块链上的智能合约无需人为干预。因此,他们是完全去信任的。例如,如果由智能合约管理的特定 DeFi 协议同意在价值低于阈值时清算您的资产,则任何人为干预都不能或不应阻止它。该代码处理支付、性能、管理和规则执行,使整个空间完全去信任化。

自主性

如前所述,智能合约加载了自动执行的指令集。就编码而言,这意味着在样板内构建迭代和循环。这确保了诸如支付、提款、存款、通过削减惩罚验证者等任务以及其他一些任务都是自主处理的。

有担保

最后,由于智能合约是使用密码学来保护的,因此破解它们非常困难。如果没有内置漏洞,绕过智能合约就意味着试图在整个区块链面前公开破坏它。

可验证的

通过智能合约处理的交易是可自我验证的。这意味着执行足以证明交易是首先发生的,因为不涉及人为因素。自我验证机制使智能合约比管理遗留银行设置的传统合约更具优势。

因此,下次您计划读取智能合约时,请确保样板或文档包含所涉及的所有上述特征。


简版智能合约(来源:Reddit

根据特征解读智能合约

这是一个代表托管账户的简单智能合约。用户将资金存入托管机构,然后在特定时间范围过后将资金转移到接收方。

/ SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// Basic Smart Contract Boilerplate

contract SimpleTrustlessEscrow {

// State variables

address public depositor; // Account depositing ether

address payable public beneficiary; // Account receiving ether

uint256 public releaseTime; // Timestamp to release ether

// Events for verifying contract activity

event Deposited(address indexed _from, uint256 _value);

event Released(address indexed _to, uint256 _value);

// The contract constructor initializes the smart contract

constructor(address payable _beneficiary, uint256 _releaseTime) {

    require(_releaseTime > block.timestamp, “Release time must be in the future”);

        // Secure and Trustless: Contract binds depositor and beneficiary

    depositor = msg.sender;

    beneficiary = _beneficiary;

    releaseTime = _releaseTime;

}

// Deposit function – autonomous execution (fallback function)

receive() external payable {

    emit Deposited(msg.sender, msg.value);

}

// Release the ether to the beneficiary

function release() public {

    // Programmable: Can only be executed after releaseTime

    require(block.timestamp >= releaseTime, “Too early to release”);

    // Autonomous: Automatically executes based on condition

    uint256 amount = address(this).balance;

    beneficiary.transfer(amount);

    emit Released(beneficiary, amount);

}

}

虽然我们将详细解读并读取此智能合约,但让我们首先检查它是否具备上述合约特征。

The “programmable” part

Look at the contract closely for this piece of code:

require(block.timestamp >= releaseTime, “Too early to release”);

uint256 amount = address(this).balance;

beneficiary.transfer(amount);

The funds are to be released only when a specific releaseTime condition is met, making these programmable contracts.

“可编程”合约部分

仔细阅读合约中的这段代码:

require(block.timestamp >= releaseTime, “Too early to release”);

uint256 amount = address(this).balance;

beneficiary.transfer(amount);

仅当满足特定的释放时间条件时才会释放资金,从而形成这些可编程合约。

“去信任”部分

让我们快速浏览上面的这个代码片段:

depositor = msg.sender;

beneficiary = _beneficiary;

releaseTime = _releaseTime;

在合约中,从存款人到接收资金的人,每个人都受代码的约束。没有人需要与对方交互或信任对方,因为转移资金的功能受到releaseTime(一种基于代码的参数)的约束。

“自主性”部分

阅读以下代码的“资金释放”部分:

function release() public {

require(block.timestamp >= releaseTime, “Too early to release”);

uint256 amount = address(this).balance;

beneficiary.transfer(amount);

emit Released(beneficiary, amount);

 }

整个过程是自主执行的,因为只有当释放时间满足一定标准时才会释放资金。请注意,代码不是部分可编程的,而是完全自主的。

智能合约代码的其他元素(包括存款功能)也可以完全是自主的,具体取决于您想要包含的功能。例如,每当用户的钱包有超过100美元时,您就可以启动定期存款计划,多余的金额将转移给收款人。

“有担保的”部分

想知道哪个要素为合同提供担保?查看这部分代码:

constructor(address payable _beneficiary, uint256 _releaseTime) {

require(_releaseTime > block.timestamp, “Release time must be in the future”);

depositor = msg.sender;

beneficiary = _beneficiary;

releaseTime = _releaseTime;

}

请注意,releaseTime 函数相对于时间戳是如何设置优先级的。没有什么是随机的,必须满足条件。

“可验证”合约部分

与智能合约相关的每笔交易都记录在链中,由单独的日志活动元素提供。

event Deposited(address indexed _from, uint256 _value);

event Released(address indexed _to, uint256 _value);

emit Deposited(msg.sender, msg.value);

emit Released(beneficiary, amount);

解读智能合约的其他部分

现在我们已经确定了定义智能合约特征的元素,以下是其他合约的元素,可以帮助您更好地练习理解智能合约。

Pragma solidity ^0.8.0; ——写入此智能合约所需的 Solidity 编程语言版本。

// SPDX-License-Identifier:MIT ——术语“软件包数据交换”,该标识符表示代码发布的许可证。合约应包含此内容,以便让人们知道它是否是开源的并且是否是可解决的。

Contract TimeLock { ——为智能合约分配名称,就像是一个标签。

Address public depositor;——由于合同涉及存款人和收款人,因此这里提到了存款人的公共地址。该变量是以太坊钱包地址,并且是公开可见的。

Address payable public beneficiary; ——这是收款人的公共地址,托管机构将资金转移到该地址。它也是可读取的,并为区块链驱动的智能合约带来了透明度。

Uint256 public releaseTime; ——由于这是一个有时限的合约,因此 uint256 将基于时间的变量分配给合约。这将是资金释放的时间表。

在 Solidity 编程语言中,uint(无符号整数)是分配基于整数的值的方式。后缀256代表存储的大量数字。

经过5年的智能合约写入经历后,我直到今天才意识到 Solidity 徽标是展开的以太坊徽标 pic.twitter.com/wlM369Eff9

——kaden.eth (@0xKaden) 发布于2023年7月8日

您可参阅 Solidity 文档来深入了解语法、表达式和其他代码元素。

其他代码元素

constructor(address payable _beneficiary, uint256 _releaseTime) { ——“Constructor”是一个一次性特殊函数,在部署智能合约时被调用。它启动了合约。请注意,在此时,我们之前声明的所有地址变量都被调用并进行初始化。

Receive() external payable { ——这是资金从外部转移到合约地址时调用的特殊函数。External暗示来自外部,“Payable”定义了此举的性质,即接收ERC-20代币。

Function release() public { ——这是一个公共函数,用于说明 ERC-20 代币从合约地址转移到收款人。该功能受到releaseTime的影响。

所有这些要素都是我们讨论假设作为托管合约的一部分。因此,您能阅读到完整的 Solidity 文档,以便更好地了解该语言。

在计划写入智能合约之前了解的要素(来源:BeInCrypto)

DApp 和智能合约的关系

到目前为止,您应已在读取和理解已写入的智能合约方面有了些知识。许多智能合约(例如我们讨论的智能合约)构成了去中心化应用程序的后端——标准移动应用程序的区块链版本。

智能合约的每一个特性,包括合约安全性、自主性和可编程执行、交易的去信任性等等,在开发去中心化应用程序时都很容易实现。因此,下次您无意遇到 DApps 时,请注意,它是托管在区块链上的智能合约驱动的后端,可帮助您在无需人工干预的情况下启动多个任务。智能合约构成了 DApps 的逻辑。

智能合约的区块链

我们知道,以太坊可让您开发智能合约,就像大型软件解决方案一样。然而,它并不是唯一的区块链协议。如果您想深入了解智能合约开发领域,那么您可能想看看其他区块链。不同的区块链在制定合约时有不同的用语。

但首先,让我们讨论一下以太坊——这是大多数智能合约开发人员的首选平台。

以太坊

以太坊上的智能合约是用 Solidity 编程语言写入的。该智能合约开发平台的代币接口是ERC-20。

您可回到我们之前讨论的基于托管的智能合约,看看标准的基于以太坊的智能合约是如何写入的。

即使在以太坊区块链上启动 ERC-20 代币也是一项严重依赖智能合约的功能,我们将在写入智能合约时深入讨论这一点。

如果我们计划推出新的加密货币 BIC,则基本代码结构如下所示。

(此处并不是真的推出 BIC 加密货币,只是一个假设场景。)

pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract BICToken is ERC20 {
    constructor(uint256 initialSupply) ERC20("BIC Token", "BIC") {
        _mint(msg.sender, initialSupply);
    }
}

稍后在写入智能合约时,我们将讨论该代码的每个元素。

其他区块链

与以太坊一样,您甚至可以在 Solana 等平台上使用 Rust 和 Cardano、Plutus(函数式编程语言 Haskell 的子集)创建智能合约。

“Cordona 也有智能合约吗?”
跟你开玩笑的,朋友。 #CardanoADA pic.twitter.com/j8SXCu72Sd ——Willybot 🇦🇺 (@wilbot28) 发布于2023年7月9日

Rust (Solana) 中的代码结构如下所示:

(注意:这是一个简单的合约,其中计数器会递增。)

use anchor_lang::prelude::*;

declare_id!(“Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS”);

#[program]

pub mod hello_world {

use super::*;

pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {

    let greeting_account = &mut ctx.accounts.greeting_account;

    greeting_account.counter = 0;

    Ok(())

}

pub fn increment(ctx: Context<Increment>) -> ProgramResult {

    let greeting_account = &mut ctx.accounts.greeting_account;

    greeting_account.counter += 1;

    Ok(())

}

}

你可知道?Rust 是用于创建基于 Solana 的智能合约的编程语言,而 Anchor 是所使用的智能合约开发框架。为了使用 Rust 创建智能合约,开发人员需要从 Anchor 框架中提取模块——以上示例代码的第一行 (useanchor_lang::prelude::*;) 所代表的内容。

阅读此 Solana 文档,它将帮助您了解 Rust 特定的智能合约语言。

同样地,紧随 Plutus 之后,是作为语言选择的Cardano ,其次是 Polkadot 的语言 Ink!、Algorand 的语言 TEAL、NEO 的 C# 等等。在继续写入兼容的智能合约之前,建议先详细学习区块链知识文档。

为什么要学会读取智能合约?

具有能写入智能合约的能力会得到了高度赞赏,但即便只能读取智能合约也有其好处,部分如下:

  1. 能够了解与 DeFi 应用相关的自动化复杂性。
  2. 可分析与资产代币化相关的所有权标准。
  3. 可了解去中心化自治组织 (DAO) 的运作方式。
  4. 可了解并实施与担保、内容盈利、投票系统、版税和其他垂直领域相关的用例驱动的逻辑。

如何写入智能合约

在现已能读取智能合约的基础上,让我们学习如何写入智能合约。在开始深入研究之前,有必要重申不同的区块链可能有不同的与智能合约开发相关的标准和语言。请务必在写入和合约部署之始,关注任何给定区块链定义的标准。

在我们的大部分讨论中,我们将重点以以太坊区块链为例,并使用Solidity语言。

编程的作用

智能合约编程无疑是开发周期中最重要的部分。要进入以太坊或任何其他区块链上实施智能合约开发,您应该对非区块链编程语言(如 Javascript)有一定的经验。

不同的区块链和写入智能合约的语言(来源:BeInCrypto)

有了写入智能合约的能力,您就能够实施逻辑、处理相同的安全元素、优化Gas费代码、自定义相同的代码,甚至在需要时使相同的代码具有互操作性。

写入合约的基础知识:EVM 和智能合约

任何计划在以太坊上写入智能合约的人都需要了解以太坊虚拟机(EVM)是什么以及它如何与智能合约配合使用。首先,EVM 是一个以太坊组件,为程序提供了一个隔离且受控的工作环境。可将其视为托管以太坊上每段合约代码的全球计算机。以太坊网络上的每个节点都运行 EVM。

如果您有志成为一名智能合约开发人员,您需要了解以下有关智能合约和 EVM 的知识。

在使用 Solidity(一种高级语言)写入了程序后,您就需要将其编译成字节码——一种机器可理解的低级格式。该字节码进入以太坊区块链并驻留在其中。任何与智能合约交互的人都需要将交易发送到合约地址。

每个安装了 EVM 的节点都可以看到该交易,验证者批准该交易后,智能合约代码就会被执行。由于每个节点都具有事务可见性,因此任何内容都无法篡改,并且代码按写入时执行。代码被执行后,区块链的状态就会发生变化,使整个过程实现端到端且完全具有透明性。

任何人都可写入智能合约吗?

写入智能合约需要技术知识。但事实并非如此。您还需要彻底了解区块链技术的工作原理、哪些特定于语言的需求与您所针对的区块链相关、互操作性等等。除此之外,您还应了解与智能合约漏洞相关的大量信息——这写入代码时要避免的事情。最后,合约测试和合约部署知识也是必须要知晓的。

所有这些都看起来让人不知所措。因此,以下准备一份快速入门的备忘清单:

  1. 首先,选择您想要合作的平台或区块链。
  2. 学习与该区块链相关的编程语言,例如以太坊的 Solidity 语言等。
  3. 了解如何使用 Remix 等集成开发环境等开发工具。
  4. 开始写入您的第一个合约,然后使用测试网进行测试。
  5. 对自写的代码元素感到满意后,您就可以将其部署到链上。请记住,在链上部署合约将产生Gas费。

以下提供了一份快捷思路,其中包含一些将智能合约写入得更完善的技巧:

🥧 FREI-PI
‼️ 为什么智能合约开发人员需要知道这些内容!
功能:
– 要求
– 影响
– 交互

协议
不变性
这是您在创建智能合约时应思考的模式。

这就是原因👇
— Patrick Collins (@PatrickAlphaC) 发表于2023年7月6日

探讨编程

现在是时候讨论智能合约开发技术方面的内容了。尽管Solana 和 Cardano 这样的区块链也允许您开发智能合约,但以太坊仍然是最受欢迎的智能合约开发平台。

你可知道?仅在2022年,就有超过100,000个去中心化应用程序进入以太坊网络。

为什么是以太坊?

以太坊拥有庞大的开发者社区。您开发的任何东西都会立刻获得关注。另外,它的母语 Solidity 对于了解 Python 或 JavaScript 的人来说相对容易。最后,以太坊全球软件 EVM 有助于无缝执行合约。

如果您是也是青睐以太坊的大多数人之一,并且更喜欢使用以太坊和 Solidity,那么在开始智能合约开发之前,您需要了解以下快速入门事项:

  1. 编译指示或编译器版本
  2. 标签合约定义
  3. 用于存储数据的状态变量
  4. EVM 日志记录事件
  5. 赋予特定机构特定权利的修改者
  6. 正在发挥作用的功能或智能合约活动
  7. 互操作性的继承
  8. 了解 if、else、for loops 等控制结构,以及字符串、整数等数据类型。

写入并部署第一个智能合约

在知晓了事情在区块链上是如何进行的情况下,让我们开始写入和部署第一个智能合约。尽管“Hello World”仍然是第一步,但我们将首先创建一个智能合约,推出一个假设的 BIC 代币,其供应量为100万个,100%释放。

开始写入的基础事项

第一步,安装最新版本的 Node.js 和 NPM 或 Node Package Manager(节点包管理器)。这会考虑到开发工具和本地开发环境。此外,Node.js 和 NPM 允许您为智能合约设置 Web 前端。

现在,您需要设置一个IDE来写入合约代码。为此,您可快速安装 Visual Studio Code。或者您可避免混乱并跳到 Alchemy——一个区块链开发平台。通过 Alchemy,您可以获得一些测试网 ETH。当您将智能合约部署到 Goerli 测试网甚至 Sepolia 测试网时,将产生 Gas 费用。

请注意,Sepolia 是一个较新的测试网,因此它在节点部署方面占用较少的磁盘空间。

目前,我们将继续使用 Goerli 测试网,因为它已有大量已部署的应用程序。

测试网和假 ETH 准备就绪后,让我们开始具体写入智能合约。以下是创建固定供应量100万个 BIC 代币的代码片段。

注意:我们将在 MacOS 本地而不是测试网上部署智能合约。对于智能合约的测试网和主网部署,我们将有一个单独的部分,这在本文不予讨论。

写入和部署智能合约的步骤

以下是假设代币的简单代码片段:

pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract BICToken is ERC20 {
    constructor() ERC20("BIC Token", "BIC") {
        _mint(msg.sender, 1000000 * 10 ** decimals());
    }
}

若您了解语法,您就会知道每个代码组件的含义。至于Openzepplin部分,它是导入ERC-20智能合约的首选库。该库提供了 ERC-20 代币的基本操作标准。

mint 函数讨论初始供应,该供应被部署到智能合约地址或 msg.sender。

要在本地设置此代码并进行测试,我们需要三个组件:

  1. Node.js 和 NPM(已讨论过):如引擎一样为您的智能合约提供动力
  2. Truffle:像工具箱一样工作,帮助您组织代码、脚本和合约的其他部分
  3. Ganache:就像设备上的虚拟游乐场一样。可将其视为个人区块链。

什么是合约执行?

如果您已完成写入智能合约的详细过程,那么有必要了解一些有关合约执行的知识。它是通过节点在链上执行智能合约代码的过程。

正是与合约执行相关的一致性使得智能合约透明且不可变。现在让我们了解与合约执行相关的详细步骤:

第一步

我们写入的代码片段需要在某个地方执行。就智能合约而言,执行地点就是区块链。节点或链上的参与成员帮助执行合约。

第二步

节点负责执行合约代码块,以换取与链相关的激励。链内发生的每一个命令或动作都由智能合约主导。

第三步

每个智能合约都有一个特定的地址。为了执行合约,交易被发送到该合约地址。请注意,每个节点都运行 EVM,然后 EVM 拥有智能合约代码的副本,从而能更容易地检查交易的真实性。

第四步

针对智能合约的交易由验证者选出,然后将其包含到特定的区块中。

第五步

交易被推送并成功得到验证后,它就成为区块链的一部分。然后,与交易相关的智能合约函数在区块链节点上被调用并执行。

第六步

执行智能合约的每个节点都应得出确定性结论——同一组输入具有相同的输出——从而使合约具有完全去信任和透明的性质。

注意:任何与代码执行有关的错误或与Gas费相关的问题都会导致交易被撤销。这意味着基于特定智能合约代码的交易将不复存在。这正是闪电贷发生的情况,因为无法遵守特定规范而导致整个交易发生逆转,似乎让人觉得一资金从一开始就没有流动。

与智能合约相关的每个状态变化都会记录在区块链中,并成为区块链的不可变部分。

智能合约开发和最佳实践

现在您已经对智能合约有了一定的了解,下面是一些开启合约开发的建议:

  1. 在写入合约时,建议依赖 OpenZeppelin 等受信任的库来遵守所需的代码优化和安全标准。
  2. 要保持合同模块化和简单化——使其更容易测试和审查。
  3. 实施特定于合约的访问控制是个不错的想法。这意味着,宣布只有特定个人或实体才能更改合约关键特征的代码位。访问控制能更轻松地保证智能合约的安全。
  4. 在写入合约时,始终要制定针对边缘和异常情况处理的规定——同时写入多个测试。

关注代码的可持续性

上面提到的每个实践都能帮助优化代码并有利于特定于安全性的实现。但是,您必须遵循和实施一些特定于合约的实践,以保证代码的可持续性。这样做的目的是,保持合约代码为轻量级且是可用的,以便每个运行和执行相同合约的节点无需投入大量计算能力。

  1. 使用较小的数据集来有效地处理存储。例如,在写入合约时,使用 uint8 而不是 uint256 作为操作值。
  2. 在写入合约时,建议将多个操作合并为一个操作来优化代码。我们将在“写入智能合约”的详细文章中更深入地探讨这一点。
  3. 在智能合约执行方面使用惰性评估,这是一个不错的想法。这样,您只需在需要时执行一个函数,而不是每次将某些内容推送到智能合约地址时执行。
  4. 最后,依靠链下计算也是关注可持续性的好方法。这有助于降低Gas费要求,甚至还能加快合约执行的速度。

即便在写入和开发智能合约时遵循了以上最佳实践,但在将其推送到主网时仍需要关注合约安全漏洞事宜。

如何审计智能合约?

主网中存在的每个智能合约都需要在代码性能、安全性和其他特征方面受到评估。这就是审计(严格的合约测试流程)占据重要地位的原因,它让您能够发现潜在的合约漏洞和弱点。

以下是快速入门审计的要点:

绝佳的智能合约审计要点😈
请务必在下次审计时检查这些内容✅
感恩转发,传播知识🫡https://t.co/ILx0C67kf8
——cholakov (@cholakovv) 发布于2023年7月7日

读取、写入和审计之间的关系:为什么还要审计智能合约?

虽然在开发智能代码时,读取和写入智能合约是相辅相成的,但审计的地位不一般,并且首先涉及检查合约的逻辑。在谈到基于区块链的代码执行时,我们都认为它的一切都是不可变的,任何灾难性的事情都可能对合约执行产生不可逆转的后果。这正是为什么需要通过审计对合约代码和其他方面进行全面检查。

合约漏洞及修复措施

详细的智能合约审计可识别出许多合约漏洞。其中包括检查重入攻击、溢出或下溢、与访问控制相关的问题等等。确定了问题的确切性质后,审计员甚至可以提供解决该问题的最佳实践。

漏洞案例研究和教训

还是不明白智能合约审计有何好处?那么,让我们回顾一下2016年臭名昭著的 DAO 黑客事件,该事件利用了重入问题,造成了近360万 ETH 的损失。同样,2017年 Parity 钱包合约被黑客攻击,导致近50万 ETH 损失。通过正确的审计,这些问题本来可以避免。


DAO 黑客的流程图(来源:BeInCrypto)

审计智能合约的策略

审计智能合约的策略有很多。以下讨论了一些较受欢迎的策略:

审计工具

审计工具充当第一套防御措施,最适用于定位常见漏洞。一些更常见工具有 Securify、Mythril 等,能够对代码执行静态分析、检测漏洞模式并帮助获得特定于安全性的领先优势。

审计智能合约的工具(来源:BeInCrypto)

代码审查

代码审查由手动代码审查人员负责,他们检查代码库并识别复杂的漏洞(若有)。手动审查可帮助处理业务逻辑、上下文和使用模式。

以下介绍了手动代码审查如何帮助您定位威胁:

给初级审查员的一个小知识!

如果您发现该漏洞,请转发! pic.twitter.com/i14YtweXcz

——CharlesPaladin (@PaladinCharles) 发布于2023 年7月8日

自动扫描

Snyk 和 GuardRails 等工具能帮助自动合约扫描——每次更新代码时都会调用的安全实现。这种形式的审计可确保对代码所做的新更改在本质上是安全且非侵入性的。

形式验证

形式验证是一个复杂的过程,仅依赖于检查代码的业务逻辑。请注意,形式验证实际上并不是为了验证语法,而是为了验证代码是否按预期执行的逻辑。

除了上述策略之外,还可使用同行评审、漏洞赏金计划和通过 Solidity Coverage 等工具测试覆盖率来启动智能合约审计,以最大限度地提高效率。

审计智能合约的简单方法(来源:BeInCrypto)

如何审查评判代码是否是正确的?

如果您是一位新手智能合约审计员,请务必注意,有两种方法可广泛分析代码并识别问题。具体如下:

静态分析

这种类型的代码分析能帮助根据给定的编码标准和约定识别基本的安全漏洞、编码错误和其他问题。可以使用静态分析来突出显示未经检查的对外部源的调用、整数溢出等威胁。静态分析的最大好处是,无需执行代码即可对其开展检查。

动态分析

这种审计方法用于测试代码与 EVM 的一致性。动态分析不是仅检查代码,而是交叉检查智能合约对各种输入的响应。动态分析可识别诸如不连贯的 Gas 消耗甚至错误的合约逻辑等问题。像 Ganache 这样的个人区块链环境可以用作动态分析平台,可让开发人员进行交易、执行命令以及使用合约执行更多操作。

测试一段实际的代码

这是一个智能合约片段,用作存储资金,具有提款功能:

pragma solidity ^0.6.1;
contract VulnerableContract {
    mapping(address => uint256) public balances;
    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }
    function withdraw(uint256 _amount) public {
        require(balances[msg.sender] >= _amount, "Insufficient balance.");
        (bool success, ) = msg.sender.call{value: _amount}("");
        require(success, "Transfer failed.");
        balances[msg.sender] -= _amount;
    }
}

如果仔细观察此代码片段,您会发现一个关键漏洞:

在上个代码片段中,如果接收资金的用户也使用智能合约,则可再次调用“取款”函数,尽管这是恶意的行为。因此,在最后一个函数或余额更新发生之前,可以发起重入攻击以转移额外的资金。经验丰富的审计员可识别这种漏洞。

以下是相同的固定代码:

function withdraw(uint256 _amount) public {
    require(balances[msg.sender] >= _amount, "Insufficient balance.");
    balances[msg.sender] -= _amount;
    (bool success, ) = msg.sender.call{value: _amount}("");


     require(success, “Transfer failed.”);

    }

检查如何首先调用余额更新函数,然后首先调用用户。操作顺序的改变就是修复合约的东西。

非以太坊区块链和代码审查

去中心化应用程序和智能合约领域已超越了以太坊。尽管大部分操作仍发生在以太坊生态系统内,但还有其他区块链(例如 Cardano、Solana 等)支持智能合约并需要不同的审计标准。

为何每个平台都是独一无二的?

不同的区块链使用不同的编程语言。代码的语义、语法和属性不同,因此智能合约能够响应不同的写入和审计实践。例如,以太坊使用 Solidity 语言,而 Polkadot 使用 Ink 和 Rust——因此它能对特定的审计标准做出反应。

适用于非以太坊区块链的工具

如果您想利用以太坊以外的平台,也有有一些入门的专门审计工具。例如,Cardano有用于形式验证和审计的Marlowe套件。若使用 Solana 平台,Rust 特定的 libfuzzer 和 Cargo-fuzz 可用于审计和合约测试。多链审计员必须熟悉这些概念,以防止合约漏洞。

智能合约审计有哪些不同类型?

需要重申的是,您可将智能合约审计分为三种类型,即手动、自动和混合。请注意,人们更喜欢针对具有深层业务逻辑的复杂合约的混合审计策略,因为它们是最全面的。

外包审计

具有极少编码知识的组织和个人通常将智能合约的写入和审计要求外包给知名公司。选择合适的审计公司变得更加重要,因为尽管 ChatGPT人工智能工具可以帮助写入智能合约代码,但同样需要手动检查来发现问题。

另外,外包审计任务时需注意以下因素:

选择合适的公司

在您选择合适的外包公司之前,要检查历史审计情况、评估经验,甚至关注其重要审计团队成员,这一点至关重要。

知晓责任、成本和管理费用

在雇用审计公司之前,请了解与审计相关的成本和服务。必须首先了解所提供服务的性质,例如问题识别、问题解决等。您还必须检查实施第一行修复后是否还需重新审计。智能合约审计的成本可能因服务而异,因此,有必要在使用服务之前了解每项要求和服务。

最佳的智能合约审计实践

如果您不想将审计工作外包给审计公司,而是想亲自审核智能合约,那么请记住以下最佳策略和实践:

  1. 要始终全面审查代码,包括语法和逻辑
  2. 首先使用 Slither、MythX 等工具找出常见漏洞
  3. 浏览智能合约漏洞分类注册表或 SWC,找到已知漏洞并提前检查。
  4. 对智能合约进行严格的测试,包括集成测试、单元测试等,以在各种场景下对代码进行压力测试。
  5. 特别检查重入攻击的可能性,这一点非常重要。解决这个问题的最佳方法是,检查黑客在第一个智能合约函数之前可调用的递归调用。
  6. 重点关注导致外部调用的函数。这方面的错误可能会改变状态和控制流,这是最不想看到的。
  7. 始终关注指向 Gas 使用情况的代码位,避免合约发起带来过高成本的交互。

智能合约开发和人工智能:未来

人工智能确实让智能合约写入变得更加容易。然而,无论人工智能如何创新,要想做到最好的智能合约审计,仍需人工干预。因此,如果您计划构建下一个强调智能合约和去中心化应用程序的 web3 产品,那么请专注智能合约的最优审计资源,这一点至关重要。随着加密货币黑客攻击和漏洞利用行为日益增多,黑客们也在计划新的突破策略,能准确地审计合约无疑是当今更重要的技能之一。

声明:

  1. 本文转载自[Beincrypto],著作权归属原作者[Ananda Banerjee],如对转载有异议,请联系Gate Learn团队([email protected]),团队会根据相关流程尽速处理。
  2. 免责声明:本文所表达的观点和意见仅代表作者个人观点,不构成任何投资建议。
  3. 文章其他语言版本由Gate Learn团队翻译, 在未提及Gate.io的情况下不得覆制、传播或抄袭经翻译文章。

了解智能合约:读取、写入和审计了解智能合约:读取、写入和审计

进阶Nov 26, 2023
本文是一则阐释智能合约编程技术(包括其读取、写入和审计)的指南。要使用 Solidity 或其他语言写入智能合约,第一步需要了解智能合约的结构和代码块。考虑到智能合约是去中心化金融(DeFi)和去中心化应用程序(DApp)的核心部分,确保其安全性和完美性至关重要,而智能合约审计在这一方面发挥着重要作用。
了解智能合约:读取、写入和审计了解智能合约:读取、写入和审计

智能合约的读取

智能合约是可编程的代码,仅在满足一组条件时才执行。在现实世界中,与具有法律约束力的合同具有相同含义;只有在这种情况下,代码才是法律。由于智能合约驻留在区块链上,因此它们是不可变的,即无法被篡改。正是这种不变性商数赋予智能合约特殊性。

了解智能合约:基础知识和重要意义

智能合约用于自动化区块链特定的交易。由于它们是特定条件的合约,因此不需要中介机构。智能合约之所以有效,是因为它们在广泛的用例(包括金融服务、供应链管理等)中具有兼容性。与一次性编程的传统代码块不同,智能合约需要高度安全且耗时的策略。

智能合约如何与区块链技术相结合(来源:BeInCrypto)

“流行语“web3”暗含了网络松散、安全性差的编程习惯。当加密货币或智能合约像网页一样编程时,它们就注定会失败。可持续成功的区块链及其应用程序基于更加安全、周密和缓慢的编程方法。”——Nick Szabo,密码学家和计算机科学家发布于Twitter

智能合约可与区块链特定的代币(例如以太坊区块链的 ERC-20)配合使用,从而激励行动并促进交易各处转移。由于涉及代码、条件和成本,您应谨慎读取、写入和审计它们。

智能合约及其意义

智能合约的真正意义在于其本质和定位。对于给定的场景,比如当 A 完成一项服务时,A 将资金转移给 B,区块链节点会保存并执行智能合约的副本。智能合约在链内保存为合约代码。这种多路径验证是一种以区块链为中心的特征,可确保事物的安全。

此外,还存在以次序而发生的智能合约或同步智能合约和异步智能合约,其中任务并行执行。因此,智能合约的类型和用途决定了它的写入、读取甚至审计方式。要明白以下特征:

传统的合同、财产契约、遗嘱等都是私法,即“由私人而不是政客或政府官僚起草”。智能合约就是这种去中心化规则制定的一种新形式。参阅:https://t.co/EU2Y28FznK

— Nick Szabo (@NickSzabo4) 于2018年3月15日发布

让我们考虑一个标准的智能合约管理的流动性池。

想象一下,代币池可用于交易,每次成功进行交易时,总交易价值的0.3%都会发送给流动性提供者,流动性提供者实施交易或为给定的可交易资产增加流动性。所有强调交易场景、交易费用、违规和交易失败的条件都被编码为智能合约,以合约代码的形式存储在链内。

智能合约的特点

如果我们不了解合约的特征,我们就无法深入读取、写入和审计合约。以下是需要明白的标准智能合约特征:

标准智能合约的一些特征(来源:BeInCrypto)

可编程合约

智能合约只是一些代码。您可写入智能合约来根据特定条件执行命令和场景。这就是为什么智能合约开发人员和程序员目前很受大家的青睐,因为大多数 DeFi 领域已经依赖智能合约来处理复杂的实例,例如处理跨流动性池的交易费用、维护 APY 比率等。

去信任的

驻留在区块链上的智能合约无需人为干预。因此,他们是完全去信任的。例如,如果由智能合约管理的特定 DeFi 协议同意在价值低于阈值时清算您的资产,则任何人为干预都不能或不应阻止它。该代码处理支付、性能、管理和规则执行,使整个空间完全去信任化。

自主性

如前所述,智能合约加载了自动执行的指令集。就编码而言,这意味着在样板内构建迭代和循环。这确保了诸如支付、提款、存款、通过削减惩罚验证者等任务以及其他一些任务都是自主处理的。

有担保

最后,由于智能合约是使用密码学来保护的,因此破解它们非常困难。如果没有内置漏洞,绕过智能合约就意味着试图在整个区块链面前公开破坏它。

可验证的

通过智能合约处理的交易是可自我验证的。这意味着执行足以证明交易是首先发生的,因为不涉及人为因素。自我验证机制使智能合约比管理遗留银行设置的传统合约更具优势。

因此,下次您计划读取智能合约时,请确保样板或文档包含所涉及的所有上述特征。


简版智能合约(来源:Reddit

根据特征解读智能合约

这是一个代表托管账户的简单智能合约。用户将资金存入托管机构,然后在特定时间范围过后将资金转移到接收方。

/ SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// Basic Smart Contract Boilerplate

contract SimpleTrustlessEscrow {

// State variables

address public depositor; // Account depositing ether

address payable public beneficiary; // Account receiving ether

uint256 public releaseTime; // Timestamp to release ether

// Events for verifying contract activity

event Deposited(address indexed _from, uint256 _value);

event Released(address indexed _to, uint256 _value);

// The contract constructor initializes the smart contract

constructor(address payable _beneficiary, uint256 _releaseTime) {

    require(_releaseTime > block.timestamp, “Release time must be in the future”);

        // Secure and Trustless: Contract binds depositor and beneficiary

    depositor = msg.sender;

    beneficiary = _beneficiary;

    releaseTime = _releaseTime;

}

// Deposit function – autonomous execution (fallback function)

receive() external payable {

    emit Deposited(msg.sender, msg.value);

}

// Release the ether to the beneficiary

function release() public {

    // Programmable: Can only be executed after releaseTime

    require(block.timestamp >= releaseTime, “Too early to release”);

    // Autonomous: Automatically executes based on condition

    uint256 amount = address(this).balance;

    beneficiary.transfer(amount);

    emit Released(beneficiary, amount);

}

}

虽然我们将详细解读并读取此智能合约,但让我们首先检查它是否具备上述合约特征。

The “programmable” part

Look at the contract closely for this piece of code:

require(block.timestamp >= releaseTime, “Too early to release”);

uint256 amount = address(this).balance;

beneficiary.transfer(amount);

The funds are to be released only when a specific releaseTime condition is met, making these programmable contracts.

“可编程”合约部分

仔细阅读合约中的这段代码:

require(block.timestamp >= releaseTime, “Too early to release”);

uint256 amount = address(this).balance;

beneficiary.transfer(amount);

仅当满足特定的释放时间条件时才会释放资金,从而形成这些可编程合约。

“去信任”部分

让我们快速浏览上面的这个代码片段:

depositor = msg.sender;

beneficiary = _beneficiary;

releaseTime = _releaseTime;

在合约中,从存款人到接收资金的人,每个人都受代码的约束。没有人需要与对方交互或信任对方,因为转移资金的功能受到releaseTime(一种基于代码的参数)的约束。

“自主性”部分

阅读以下代码的“资金释放”部分:

function release() public {

require(block.timestamp >= releaseTime, “Too early to release”);

uint256 amount = address(this).balance;

beneficiary.transfer(amount);

emit Released(beneficiary, amount);

 }

整个过程是自主执行的,因为只有当释放时间满足一定标准时才会释放资金。请注意,代码不是部分可编程的,而是完全自主的。

智能合约代码的其他元素(包括存款功能)也可以完全是自主的,具体取决于您想要包含的功能。例如,每当用户的钱包有超过100美元时,您就可以启动定期存款计划,多余的金额将转移给收款人。

“有担保的”部分

想知道哪个要素为合同提供担保?查看这部分代码:

constructor(address payable _beneficiary, uint256 _releaseTime) {

require(_releaseTime > block.timestamp, “Release time must be in the future”);

depositor = msg.sender;

beneficiary = _beneficiary;

releaseTime = _releaseTime;

}

请注意,releaseTime 函数相对于时间戳是如何设置优先级的。没有什么是随机的,必须满足条件。

“可验证”合约部分

与智能合约相关的每笔交易都记录在链中,由单独的日志活动元素提供。

event Deposited(address indexed _from, uint256 _value);

event Released(address indexed _to, uint256 _value);

emit Deposited(msg.sender, msg.value);

emit Released(beneficiary, amount);

解读智能合约的其他部分

现在我们已经确定了定义智能合约特征的元素,以下是其他合约的元素,可以帮助您更好地练习理解智能合约。

Pragma solidity ^0.8.0; ——写入此智能合约所需的 Solidity 编程语言版本。

// SPDX-License-Identifier:MIT ——术语“软件包数据交换”,该标识符表示代码发布的许可证。合约应包含此内容,以便让人们知道它是否是开源的并且是否是可解决的。

Contract TimeLock { ——为智能合约分配名称,就像是一个标签。

Address public depositor;——由于合同涉及存款人和收款人,因此这里提到了存款人的公共地址。该变量是以太坊钱包地址,并且是公开可见的。

Address payable public beneficiary; ——这是收款人的公共地址,托管机构将资金转移到该地址。它也是可读取的,并为区块链驱动的智能合约带来了透明度。

Uint256 public releaseTime; ——由于这是一个有时限的合约,因此 uint256 将基于时间的变量分配给合约。这将是资金释放的时间表。

在 Solidity 编程语言中,uint(无符号整数)是分配基于整数的值的方式。后缀256代表存储的大量数字。

经过5年的智能合约写入经历后,我直到今天才意识到 Solidity 徽标是展开的以太坊徽标 pic.twitter.com/wlM369Eff9

——kaden.eth (@0xKaden) 发布于2023年7月8日

您可参阅 Solidity 文档来深入了解语法、表达式和其他代码元素。

其他代码元素

constructor(address payable _beneficiary, uint256 _releaseTime) { ——“Constructor”是一个一次性特殊函数,在部署智能合约时被调用。它启动了合约。请注意,在此时,我们之前声明的所有地址变量都被调用并进行初始化。

Receive() external payable { ——这是资金从外部转移到合约地址时调用的特殊函数。External暗示来自外部,“Payable”定义了此举的性质,即接收ERC-20代币。

Function release() public { ——这是一个公共函数,用于说明 ERC-20 代币从合约地址转移到收款人。该功能受到releaseTime的影响。

所有这些要素都是我们讨论假设作为托管合约的一部分。因此,您能阅读到完整的 Solidity 文档,以便更好地了解该语言。

在计划写入智能合约之前了解的要素(来源:BeInCrypto)

DApp 和智能合约的关系

到目前为止,您应已在读取和理解已写入的智能合约方面有了些知识。许多智能合约(例如我们讨论的智能合约)构成了去中心化应用程序的后端——标准移动应用程序的区块链版本。

智能合约的每一个特性,包括合约安全性、自主性和可编程执行、交易的去信任性等等,在开发去中心化应用程序时都很容易实现。因此,下次您无意遇到 DApps 时,请注意,它是托管在区块链上的智能合约驱动的后端,可帮助您在无需人工干预的情况下启动多个任务。智能合约构成了 DApps 的逻辑。

智能合约的区块链

我们知道,以太坊可让您开发智能合约,就像大型软件解决方案一样。然而,它并不是唯一的区块链协议。如果您想深入了解智能合约开发领域,那么您可能想看看其他区块链。不同的区块链在制定合约时有不同的用语。

但首先,让我们讨论一下以太坊——这是大多数智能合约开发人员的首选平台。

以太坊

以太坊上的智能合约是用 Solidity 编程语言写入的。该智能合约开发平台的代币接口是ERC-20。

您可回到我们之前讨论的基于托管的智能合约,看看标准的基于以太坊的智能合约是如何写入的。

即使在以太坊区块链上启动 ERC-20 代币也是一项严重依赖智能合约的功能,我们将在写入智能合约时深入讨论这一点。

如果我们计划推出新的加密货币 BIC,则基本代码结构如下所示。

(此处并不是真的推出 BIC 加密货币,只是一个假设场景。)

pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract BICToken is ERC20 {
    constructor(uint256 initialSupply) ERC20("BIC Token", "BIC") {
        _mint(msg.sender, initialSupply);
    }
}

稍后在写入智能合约时,我们将讨论该代码的每个元素。

其他区块链

与以太坊一样,您甚至可以在 Solana 等平台上使用 Rust 和 Cardano、Plutus(函数式编程语言 Haskell 的子集)创建智能合约。

“Cordona 也有智能合约吗?”
跟你开玩笑的,朋友。 #CardanoADA pic.twitter.com/j8SXCu72Sd ——Willybot 🇦🇺 (@wilbot28) 发布于2023年7月9日

Rust (Solana) 中的代码结构如下所示:

(注意:这是一个简单的合约,其中计数器会递增。)

use anchor_lang::prelude::*;

declare_id!(“Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS”);

#[program]

pub mod hello_world {

use super::*;

pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {

    let greeting_account = &mut ctx.accounts.greeting_account;

    greeting_account.counter = 0;

    Ok(())

}

pub fn increment(ctx: Context<Increment>) -> ProgramResult {

    let greeting_account = &mut ctx.accounts.greeting_account;

    greeting_account.counter += 1;

    Ok(())

}

}

你可知道?Rust 是用于创建基于 Solana 的智能合约的编程语言,而 Anchor 是所使用的智能合约开发框架。为了使用 Rust 创建智能合约,开发人员需要从 Anchor 框架中提取模块——以上示例代码的第一行 (useanchor_lang::prelude::*;) 所代表的内容。

阅读此 Solana 文档,它将帮助您了解 Rust 特定的智能合约语言。

同样地,紧随 Plutus 之后,是作为语言选择的Cardano ,其次是 Polkadot 的语言 Ink!、Algorand 的语言 TEAL、NEO 的 C# 等等。在继续写入兼容的智能合约之前,建议先详细学习区块链知识文档。

为什么要学会读取智能合约?

具有能写入智能合约的能力会得到了高度赞赏,但即便只能读取智能合约也有其好处,部分如下:

  1. 能够了解与 DeFi 应用相关的自动化复杂性。
  2. 可分析与资产代币化相关的所有权标准。
  3. 可了解去中心化自治组织 (DAO) 的运作方式。
  4. 可了解并实施与担保、内容盈利、投票系统、版税和其他垂直领域相关的用例驱动的逻辑。

如何写入智能合约

在现已能读取智能合约的基础上,让我们学习如何写入智能合约。在开始深入研究之前,有必要重申不同的区块链可能有不同的与智能合约开发相关的标准和语言。请务必在写入和合约部署之始,关注任何给定区块链定义的标准。

在我们的大部分讨论中,我们将重点以以太坊区块链为例,并使用Solidity语言。

编程的作用

智能合约编程无疑是开发周期中最重要的部分。要进入以太坊或任何其他区块链上实施智能合约开发,您应该对非区块链编程语言(如 Javascript)有一定的经验。

不同的区块链和写入智能合约的语言(来源:BeInCrypto)

有了写入智能合约的能力,您就能够实施逻辑、处理相同的安全元素、优化Gas费代码、自定义相同的代码,甚至在需要时使相同的代码具有互操作性。

写入合约的基础知识:EVM 和智能合约

任何计划在以太坊上写入智能合约的人都需要了解以太坊虚拟机(EVM)是什么以及它如何与智能合约配合使用。首先,EVM 是一个以太坊组件,为程序提供了一个隔离且受控的工作环境。可将其视为托管以太坊上每段合约代码的全球计算机。以太坊网络上的每个节点都运行 EVM。

如果您有志成为一名智能合约开发人员,您需要了解以下有关智能合约和 EVM 的知识。

在使用 Solidity(一种高级语言)写入了程序后,您就需要将其编译成字节码——一种机器可理解的低级格式。该字节码进入以太坊区块链并驻留在其中。任何与智能合约交互的人都需要将交易发送到合约地址。

每个安装了 EVM 的节点都可以看到该交易,验证者批准该交易后,智能合约代码就会被执行。由于每个节点都具有事务可见性,因此任何内容都无法篡改,并且代码按写入时执行。代码被执行后,区块链的状态就会发生变化,使整个过程实现端到端且完全具有透明性。

任何人都可写入智能合约吗?

写入智能合约需要技术知识。但事实并非如此。您还需要彻底了解区块链技术的工作原理、哪些特定于语言的需求与您所针对的区块链相关、互操作性等等。除此之外,您还应了解与智能合约漏洞相关的大量信息——这写入代码时要避免的事情。最后,合约测试和合约部署知识也是必须要知晓的。

所有这些都看起来让人不知所措。因此,以下准备一份快速入门的备忘清单:

  1. 首先,选择您想要合作的平台或区块链。
  2. 学习与该区块链相关的编程语言,例如以太坊的 Solidity 语言等。
  3. 了解如何使用 Remix 等集成开发环境等开发工具。
  4. 开始写入您的第一个合约,然后使用测试网进行测试。
  5. 对自写的代码元素感到满意后,您就可以将其部署到链上。请记住,在链上部署合约将产生Gas费。

以下提供了一份快捷思路,其中包含一些将智能合约写入得更完善的技巧:

🥧 FREI-PI
‼️ 为什么智能合约开发人员需要知道这些内容!
功能:
– 要求
– 影响
– 交互

协议
不变性
这是您在创建智能合约时应思考的模式。

这就是原因👇
— Patrick Collins (@PatrickAlphaC) 发表于2023年7月6日

探讨编程

现在是时候讨论智能合约开发技术方面的内容了。尽管Solana 和 Cardano 这样的区块链也允许您开发智能合约,但以太坊仍然是最受欢迎的智能合约开发平台。

你可知道?仅在2022年,就有超过100,000个去中心化应用程序进入以太坊网络。

为什么是以太坊?

以太坊拥有庞大的开发者社区。您开发的任何东西都会立刻获得关注。另外,它的母语 Solidity 对于了解 Python 或 JavaScript 的人来说相对容易。最后,以太坊全球软件 EVM 有助于无缝执行合约。

如果您是也是青睐以太坊的大多数人之一,并且更喜欢使用以太坊和 Solidity,那么在开始智能合约开发之前,您需要了解以下快速入门事项:

  1. 编译指示或编译器版本
  2. 标签合约定义
  3. 用于存储数据的状态变量
  4. EVM 日志记录事件
  5. 赋予特定机构特定权利的修改者
  6. 正在发挥作用的功能或智能合约活动
  7. 互操作性的继承
  8. 了解 if、else、for loops 等控制结构,以及字符串、整数等数据类型。

写入并部署第一个智能合约

在知晓了事情在区块链上是如何进行的情况下,让我们开始写入和部署第一个智能合约。尽管“Hello World”仍然是第一步,但我们将首先创建一个智能合约,推出一个假设的 BIC 代币,其供应量为100万个,100%释放。

开始写入的基础事项

第一步,安装最新版本的 Node.js 和 NPM 或 Node Package Manager(节点包管理器)。这会考虑到开发工具和本地开发环境。此外,Node.js 和 NPM 允许您为智能合约设置 Web 前端。

现在,您需要设置一个IDE来写入合约代码。为此,您可快速安装 Visual Studio Code。或者您可避免混乱并跳到 Alchemy——一个区块链开发平台。通过 Alchemy,您可以获得一些测试网 ETH。当您将智能合约部署到 Goerli 测试网甚至 Sepolia 测试网时,将产生 Gas 费用。

请注意,Sepolia 是一个较新的测试网,因此它在节点部署方面占用较少的磁盘空间。

目前,我们将继续使用 Goerli 测试网,因为它已有大量已部署的应用程序。

测试网和假 ETH 准备就绪后,让我们开始具体写入智能合约。以下是创建固定供应量100万个 BIC 代币的代码片段。

注意:我们将在 MacOS 本地而不是测试网上部署智能合约。对于智能合约的测试网和主网部署,我们将有一个单独的部分,这在本文不予讨论。

写入和部署智能合约的步骤

以下是假设代币的简单代码片段:

pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract BICToken is ERC20 {
    constructor() ERC20("BIC Token", "BIC") {
        _mint(msg.sender, 1000000 * 10 ** decimals());
    }
}

若您了解语法,您就会知道每个代码组件的含义。至于Openzepplin部分,它是导入ERC-20智能合约的首选库。该库提供了 ERC-20 代币的基本操作标准。

mint 函数讨论初始供应,该供应被部署到智能合约地址或 msg.sender。

要在本地设置此代码并进行测试,我们需要三个组件:

  1. Node.js 和 NPM(已讨论过):如引擎一样为您的智能合约提供动力
  2. Truffle:像工具箱一样工作,帮助您组织代码、脚本和合约的其他部分
  3. Ganache:就像设备上的虚拟游乐场一样。可将其视为个人区块链。

什么是合约执行?

如果您已完成写入智能合约的详细过程,那么有必要了解一些有关合约执行的知识。它是通过节点在链上执行智能合约代码的过程。

正是与合约执行相关的一致性使得智能合约透明且不可变。现在让我们了解与合约执行相关的详细步骤:

第一步

我们写入的代码片段需要在某个地方执行。就智能合约而言,执行地点就是区块链。节点或链上的参与成员帮助执行合约。

第二步

节点负责执行合约代码块,以换取与链相关的激励。链内发生的每一个命令或动作都由智能合约主导。

第三步

每个智能合约都有一个特定的地址。为了执行合约,交易被发送到该合约地址。请注意,每个节点都运行 EVM,然后 EVM 拥有智能合约代码的副本,从而能更容易地检查交易的真实性。

第四步

针对智能合约的交易由验证者选出,然后将其包含到特定的区块中。

第五步

交易被推送并成功得到验证后,它就成为区块链的一部分。然后,与交易相关的智能合约函数在区块链节点上被调用并执行。

第六步

执行智能合约的每个节点都应得出确定性结论——同一组输入具有相同的输出——从而使合约具有完全去信任和透明的性质。

注意:任何与代码执行有关的错误或与Gas费相关的问题都会导致交易被撤销。这意味着基于特定智能合约代码的交易将不复存在。这正是闪电贷发生的情况,因为无法遵守特定规范而导致整个交易发生逆转,似乎让人觉得一资金从一开始就没有流动。

与智能合约相关的每个状态变化都会记录在区块链中,并成为区块链的不可变部分。

智能合约开发和最佳实践

现在您已经对智能合约有了一定的了解,下面是一些开启合约开发的建议:

  1. 在写入合约时,建议依赖 OpenZeppelin 等受信任的库来遵守所需的代码优化和安全标准。
  2. 要保持合同模块化和简单化——使其更容易测试和审查。
  3. 实施特定于合约的访问控制是个不错的想法。这意味着,宣布只有特定个人或实体才能更改合约关键特征的代码位。访问控制能更轻松地保证智能合约的安全。
  4. 在写入合约时,始终要制定针对边缘和异常情况处理的规定——同时写入多个测试。

关注代码的可持续性

上面提到的每个实践都能帮助优化代码并有利于特定于安全性的实现。但是,您必须遵循和实施一些特定于合约的实践,以保证代码的可持续性。这样做的目的是,保持合约代码为轻量级且是可用的,以便每个运行和执行相同合约的节点无需投入大量计算能力。

  1. 使用较小的数据集来有效地处理存储。例如,在写入合约时,使用 uint8 而不是 uint256 作为操作值。
  2. 在写入合约时,建议将多个操作合并为一个操作来优化代码。我们将在“写入智能合约”的详细文章中更深入地探讨这一点。
  3. 在智能合约执行方面使用惰性评估,这是一个不错的想法。这样,您只需在需要时执行一个函数,而不是每次将某些内容推送到智能合约地址时执行。
  4. 最后,依靠链下计算也是关注可持续性的好方法。这有助于降低Gas费要求,甚至还能加快合约执行的速度。

即便在写入和开发智能合约时遵循了以上最佳实践,但在将其推送到主网时仍需要关注合约安全漏洞事宜。

如何审计智能合约?

主网中存在的每个智能合约都需要在代码性能、安全性和其他特征方面受到评估。这就是审计(严格的合约测试流程)占据重要地位的原因,它让您能够发现潜在的合约漏洞和弱点。

以下是快速入门审计的要点:

绝佳的智能合约审计要点😈
请务必在下次审计时检查这些内容✅
感恩转发,传播知识🫡https://t.co/ILx0C67kf8
——cholakov (@cholakovv) 发布于2023年7月7日

读取、写入和审计之间的关系:为什么还要审计智能合约?

虽然在开发智能代码时,读取和写入智能合约是相辅相成的,但审计的地位不一般,并且首先涉及检查合约的逻辑。在谈到基于区块链的代码执行时,我们都认为它的一切都是不可变的,任何灾难性的事情都可能对合约执行产生不可逆转的后果。这正是为什么需要通过审计对合约代码和其他方面进行全面检查。

合约漏洞及修复措施

详细的智能合约审计可识别出许多合约漏洞。其中包括检查重入攻击、溢出或下溢、与访问控制相关的问题等等。确定了问题的确切性质后,审计员甚至可以提供解决该问题的最佳实践。

漏洞案例研究和教训

还是不明白智能合约审计有何好处?那么,让我们回顾一下2016年臭名昭著的 DAO 黑客事件,该事件利用了重入问题,造成了近360万 ETH 的损失。同样,2017年 Parity 钱包合约被黑客攻击,导致近50万 ETH 损失。通过正确的审计,这些问题本来可以避免。


DAO 黑客的流程图(来源:BeInCrypto)

审计智能合约的策略

审计智能合约的策略有很多。以下讨论了一些较受欢迎的策略:

审计工具

审计工具充当第一套防御措施,最适用于定位常见漏洞。一些更常见工具有 Securify、Mythril 等,能够对代码执行静态分析、检测漏洞模式并帮助获得特定于安全性的领先优势。

审计智能合约的工具(来源:BeInCrypto)

代码审查

代码审查由手动代码审查人员负责,他们检查代码库并识别复杂的漏洞(若有)。手动审查可帮助处理业务逻辑、上下文和使用模式。

以下介绍了手动代码审查如何帮助您定位威胁:

给初级审查员的一个小知识!

如果您发现该漏洞,请转发! pic.twitter.com/i14YtweXcz

——CharlesPaladin (@PaladinCharles) 发布于2023 年7月8日

自动扫描

Snyk 和 GuardRails 等工具能帮助自动合约扫描——每次更新代码时都会调用的安全实现。这种形式的审计可确保对代码所做的新更改在本质上是安全且非侵入性的。

形式验证

形式验证是一个复杂的过程,仅依赖于检查代码的业务逻辑。请注意,形式验证实际上并不是为了验证语法,而是为了验证代码是否按预期执行的逻辑。

除了上述策略之外,还可使用同行评审、漏洞赏金计划和通过 Solidity Coverage 等工具测试覆盖率来启动智能合约审计,以最大限度地提高效率。

审计智能合约的简单方法(来源:BeInCrypto)

如何审查评判代码是否是正确的?

如果您是一位新手智能合约审计员,请务必注意,有两种方法可广泛分析代码并识别问题。具体如下:

静态分析

这种类型的代码分析能帮助根据给定的编码标准和约定识别基本的安全漏洞、编码错误和其他问题。可以使用静态分析来突出显示未经检查的对外部源的调用、整数溢出等威胁。静态分析的最大好处是,无需执行代码即可对其开展检查。

动态分析

这种审计方法用于测试代码与 EVM 的一致性。动态分析不是仅检查代码,而是交叉检查智能合约对各种输入的响应。动态分析可识别诸如不连贯的 Gas 消耗甚至错误的合约逻辑等问题。像 Ganache 这样的个人区块链环境可以用作动态分析平台,可让开发人员进行交易、执行命令以及使用合约执行更多操作。

测试一段实际的代码

这是一个智能合约片段,用作存储资金,具有提款功能:

pragma solidity ^0.6.1;
contract VulnerableContract {
    mapping(address => uint256) public balances;
    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }
    function withdraw(uint256 _amount) public {
        require(balances[msg.sender] >= _amount, "Insufficient balance.");
        (bool success, ) = msg.sender.call{value: _amount}("");
        require(success, "Transfer failed.");
        balances[msg.sender] -= _amount;
    }
}

如果仔细观察此代码片段,您会发现一个关键漏洞:

在上个代码片段中,如果接收资金的用户也使用智能合约,则可再次调用“取款”函数,尽管这是恶意的行为。因此,在最后一个函数或余额更新发生之前,可以发起重入攻击以转移额外的资金。经验丰富的审计员可识别这种漏洞。

以下是相同的固定代码:

function withdraw(uint256 _amount) public {
    require(balances[msg.sender] >= _amount, "Insufficient balance.");
    balances[msg.sender] -= _amount;
    (bool success, ) = msg.sender.call{value: _amount}("");


     require(success, “Transfer failed.”);

    }

检查如何首先调用余额更新函数,然后首先调用用户。操作顺序的改变就是修复合约的东西。

非以太坊区块链和代码审查

去中心化应用程序和智能合约领域已超越了以太坊。尽管大部分操作仍发生在以太坊生态系统内,但还有其他区块链(例如 Cardano、Solana 等)支持智能合约并需要不同的审计标准。

为何每个平台都是独一无二的?

不同的区块链使用不同的编程语言。代码的语义、语法和属性不同,因此智能合约能够响应不同的写入和审计实践。例如,以太坊使用 Solidity 语言,而 Polkadot 使用 Ink 和 Rust——因此它能对特定的审计标准做出反应。

适用于非以太坊区块链的工具

如果您想利用以太坊以外的平台,也有有一些入门的专门审计工具。例如,Cardano有用于形式验证和审计的Marlowe套件。若使用 Solana 平台,Rust 特定的 libfuzzer 和 Cargo-fuzz 可用于审计和合约测试。多链审计员必须熟悉这些概念,以防止合约漏洞。

智能合约审计有哪些不同类型?

需要重申的是,您可将智能合约审计分为三种类型,即手动、自动和混合。请注意,人们更喜欢针对具有深层业务逻辑的复杂合约的混合审计策略,因为它们是最全面的。

外包审计

具有极少编码知识的组织和个人通常将智能合约的写入和审计要求外包给知名公司。选择合适的审计公司变得更加重要,因为尽管 ChatGPT人工智能工具可以帮助写入智能合约代码,但同样需要手动检查来发现问题。

另外,外包审计任务时需注意以下因素:

选择合适的公司

在您选择合适的外包公司之前,要检查历史审计情况、评估经验,甚至关注其重要审计团队成员,这一点至关重要。

知晓责任、成本和管理费用

在雇用审计公司之前,请了解与审计相关的成本和服务。必须首先了解所提供服务的性质,例如问题识别、问题解决等。您还必须检查实施第一行修复后是否还需重新审计。智能合约审计的成本可能因服务而异,因此,有必要在使用服务之前了解每项要求和服务。

最佳的智能合约审计实践

如果您不想将审计工作外包给审计公司,而是想亲自审核智能合约,那么请记住以下最佳策略和实践:

  1. 要始终全面审查代码,包括语法和逻辑
  2. 首先使用 Slither、MythX 等工具找出常见漏洞
  3. 浏览智能合约漏洞分类注册表或 SWC,找到已知漏洞并提前检查。
  4. 对智能合约进行严格的测试,包括集成测试、单元测试等,以在各种场景下对代码进行压力测试。
  5. 特别检查重入攻击的可能性,这一点非常重要。解决这个问题的最佳方法是,检查黑客在第一个智能合约函数之前可调用的递归调用。
  6. 重点关注导致外部调用的函数。这方面的错误可能会改变状态和控制流,这是最不想看到的。
  7. 始终关注指向 Gas 使用情况的代码位,避免合约发起带来过高成本的交互。

智能合约开发和人工智能:未来

人工智能确实让智能合约写入变得更加容易。然而,无论人工智能如何创新,要想做到最好的智能合约审计,仍需人工干预。因此,如果您计划构建下一个强调智能合约和去中心化应用程序的 web3 产品,那么请专注智能合约的最优审计资源,这一点至关重要。随着加密货币黑客攻击和漏洞利用行为日益增多,黑客们也在计划新的突破策略,能准确地审计合约无疑是当今更重要的技能之一。

声明:

  1. 本文转载自[Beincrypto],著作权归属原作者[Ananda Banerjee],如对转载有异议,请联系Gate Learn团队([email protected]),团队会根据相关流程尽速处理。
  2. 免责声明:本文所表达的观点和意见仅代表作者个人观点,不构成任何投资建议。
  3. 文章其他语言版本由Gate Learn团队翻译, 在未提及Gate.io的情况下不得覆制、传播或抄袭经翻译文章。
即刻开始交易
注册并交易即可获得
$100
和价值
$5500
理财体验金奖励!
立即注册