Skip to content

Commit

Permalink
what is anchor
Browse files Browse the repository at this point in the history
  • Loading branch information
DaviRain-Su committed Sep 6, 2023
1 parent 814ceaa commit 80d1c34
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 0 deletions.
233 changes: 233 additions & 0 deletions blog/2023-09-26/2023-09-06.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
---
slug: what-is-anchor
title: 什么是Anchor?
authors: [davirain]
tags: [blog, blockchain, solana, anchor]
---

# 什么是Anchor?

今天,开始我们学习从Solana上开发智能合约,这里我打算先从Anchor开始。因为Anchor也是Solana上现在如今用的最多的开发框架,哦,这里主要用的也是Rust语言,对于Anchor还支持的Solidity语法来写合约,暂时我先不考虑。也希望有🧍‍♂️能一起完善。

那今天就简单的介绍下Anchor上如何从项目的初始化,到后面如何部署合约以及前端如何来调用这个简单的Example合约。

## 先来介绍下什么是Anchor吧

这里我先引用下官方的介绍

> Anchor是一个快速构建安全Solana程序的框架。
>
> 使用Anchor,您可以快速构建程序,因为它会为您编写各种样板代码,例如账户和指令数据的(反)序列化。
>
> 由于Anchor为您处理了某些安全检查,因此您可以更轻松地构建安全的程序。除此之外,它还允许您简洁地定义额外的检查,并将其与业务逻辑分开。
>
> 这两个方面意味着,你不必再花费时间在繁琐的Solana原始程序上,而是可以更多地投入到最重要的事情上,即你的产品。
>
简单的点来说,就是Anchor做为一个Solana上的合约开发框架,对于原生使用Rust开发来说的话,anchor 提供了对于一些模版代码,或者说公共代码操作的抽象,使得开发者更加具体的专注与自己的业务逻辑。

简单的Anchor介绍完了,我们看看如何来初始化一个合约以及部署合约到本地测试网。本地测试网的部署查看[这个教程](https://creatorsdao.github.io/Solana-Co-Learn/module1/local_program_development/)完成✅。

## 一个简单的Anchor合约的部署测试

对于要使用Anchor来开发他需要一些前置的环境配置,例如你需要先安装Rust环境,第二个是安装Solana-cli工具。因为这里Anchor要使用solana cli的 `solana-keygen new` 命令来生成一个本地册测试账户。最后一个是Yarn。这里是Anchor官方给出的[安装教程](https://www.anchor-lang.com/docs/installation),按照这个安装即可。

### 下面是具体的anchor如何安装

官方推荐的是avm,一个Anchor的多版本管理器。前面我们已经安装了Rust语言,我们就可以使用cargo来安装这个工具。

通过执行这个命令,我们就可以安装avm了。

```bash
cargo install --git https://github.com/coral-xyz/anchor avm --locked --force
```

按照完之后我们就可以使用avm选择一个具体的版本安装,下面者一个命令我们安装的Anchor版本是最新的Anchor。

```bash
avm install latest
avm use latest
```

验证安装成功的我们可以执行`anchor --version`命令,我们可以看到有版本号输出,说明我们安装成功了。

### 一个anchor项目的结构

通过执行`anchor init new-workspace-name` 我们就可以初始化一个solana program。

下面是通过执行`anchor init hello-world`的输出。

```bash
ls --tree . --depth 1
.
├──  .git
├──  .gitignore
├──  .prettierignore
├──  Anchor.toml
├──  app
├──  Cargo.toml
├──  migrations
├──  node_modules
├──  package-lock.json
├──  package.json
├──  programs
├──  target
├──  tests
├──  tsconfig.json
└──  yarn-error.log
```

- `app` 文件夹:初始化之后是一个空文件夹,这里可以用来存放自己的前端代码。
- `programs` 文件夹:此文件夹包含程序代码。它可以包含多个文件,但最初只包含与 `<new-workspace-name>` 相同名称的程序。并且这个program中已经包含了一些示例代码,在`lib.rs`中可以看到。
- `tests` 文件夹:包含您的端到端测试的文件夹。它已经包含一个测试 `programs/<new-workspace-name>` 中示例代码的文件,这里面的测试都是使用typescript写✍️的代码。当执行`anchor test`的时候会在本地启动一个solana的测试节点,执行里面的测试代码。
- `migrations` 文件夹:在这个文件夹中,保存程序的部署和迁移脚本。
- `Anchor.toml` 文件:此文件配置了程序的工作区范围设置。
- 程序在本地网络上的地址( `[programs.localnet]`
- 程序可以推送到的注册表 ( `[registry]` )
- 一个可以在你的测试中使用的也就是通过`solana-keygen new` 生成的私钥文件路径 ( `[provider]` )
- `.anchor` 这个文件是只有在执行`anchor test`之后才生成的文件夹,里面包含了最新的程序日志和用于测试的本地账本。

这个是在执行`anchor test`之后的文件内容。
```bash
ls --tree . --depth 1
.
├──  .anchor
├──  .git
├──  .gitignore
├──  .prettierignore
├──  Anchor.toml
├──  app
├──  Cargo.lock
├──  Cargo.toml
├──  migrations
├──  node_modules
├──  package-lock.json
├──  package.json
├──  programs
├──  target
├──  tests
├──  tsconfig.json
└──  yarn-error.log
```

下面这个是执行`anchor test`之后`.anchor`里面生成的日志内容。

![](./anchor-test-log.png)

好说了这么多,我们看下如何使用anchor打印一个hello world, 目前先只通过anchor test 来观察打印,后面在做介绍如何通过前端调用打印。

## 初始化一个 hello world program

通过执行`anchor init hello-world`, 会为我们创建一个solana program的样板代码。

```rust
use anchor_lang::prelude::*;

declare_id!("2HvxNpAdkkWitSQyDy9vMvJDpRsvtrhZ6JNqsXzGRi3i");

#[program]
pub mod counter {
use super::*;

pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
Ok(())
}
}

#[derive(Accounts)]
pub struct Initialize {}
```

上面这段代码就是通过`anchor init hello-world` 创建出来的代码,文件存放在`hello-world/programs/hello-world/src/lib.rs`中。

下面我们就通过简单的修改下这个简单的代码,在里面添加一个打印hello, world!的消息。


```rust
use anchor_lang::prelude::*;

declare_id!("2HvxNpAdkkWitSQyDy9vMvJDpRsvtrhZ6JNqsXzGRi3i");

#[program]
pub mod counter {
use super::*;

pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
msg!("hello, world!");
Ok(())
}
}

#[derive(Accounts)]
pub struct Initialize {}
```

这个是添加了`msg!`这段代码,`msg!`主要做的事情,类似于在rust中打印内容到标准输出的`println!`
因为是solana program,他是链上代码,我们不可能打印到标准输出的,所以这我们就通过使用`msg!`这个宏记录自己需要打印的东西。

>在Solana中,由于智能合约在执行时是在分布式网络中运行的,无法直接使用传统的标准输出来打印消息。为了在智能合约中输出调试信息或日志,Solana提供了`msg!`宏。
>
>`msg!`宏的使用方式与`println!`宏类似,你可以在智能合约中使用它来打印消息。这些消息将被记录并作为日志输出到Solana节点的日志文件中。
>
>需要注意的是,`msg!`宏只在Solana智能合约中可用,用于在智能合约执行过程中输出消息。它与Rust中的`println!`宏略有不同,因为它将消息记录到Solana节点的日志文件中,而不是直接输出到控制台。
## 观察👀 `hello,world!`消息

想要观察是否打印了`hello, world!`这个消息,我们可以通过运行`anchor test`。这个会记录📝program在测试执行的内容。

![](./anchor-hello-msg.png)

我们可以看到通过执行`anchor test`已经将我们打印的hello,world! 记录下来了。

来看下执行的这个测试脚本吧。这里是执行的程序的`initialize`执行的调用。我们在这个指令中添加了打印hello, world的代码。

```ts
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { Hello } from "../target/types/hello";

describe("hello", () => {
// Configure the client to use the local cluster.
anchor.setProvider(anchor.AnchorProvider.env());

const program = anchor.workspace.Hello as Program<Hello>;

it("Is initialized!", async () => {
// Add your test here.
const tx = await program.methods.initialize().rpc();
console.log("Your transaction signature", tx);
});
});
```

`anchor.setProvider(anchor.AnchorProvider.env());` 这段代码是通过读取的Anchor.toml中的配置初始化了Anchor的provider。

```toml
[features]
seeds = false
skip-lint = false
[programs.localnet]
hello = "2HvxNpAdkkWitSQyDy9vMvJDpRsvtrhZ6JNqsXzGRi3i"

[registry]
url = "https://api.apr.dev"

[provider]
cluster = "Localnet"
wallet = "/Users/davirain/.config/solana/id.json"

[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
```

我们可以看到这里的provider是localnet,wallet是自己本地的私钥路径。

`const program = anchor.workspace.Hello as Program<Hello>;`

这一步是我们初始化了一个solana 的program 实例,通过Hello这个IDL文件。

在测试中,使用`it`函数定义了一个测试用例,名称为"Is initialized!"。在这个测试用例中,调用了`program.methods.initialize().rpc()`方法,该方法是调用合约中的`initialize`方法,并通过RPC方式发送交易。然后,使用`console.log`打印出交易的签名。

这段代码的目的是测试`hello`程序是否能够成功初始化。通过调用`initialize`方法并打印交易签名,可以验证初始化过程是否成功。

这就是一个简单的`Anchor`合约的入门。
Binary file added blog/2023-09-26/anchor-hello-msg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added blog/2023-09-26/anchor-test-log.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 80d1c34

Please sign in to comment.