先打个强心针,我目前涉及的行业只能说和之前所学的大不相同——区块链。

今天接到一个任务:将 Leo 语言学会,然后短时间内创建一个简单的区块链框架。以下文章作为今天的学习心得。项目已经开源到 hubei-xhjy 的仓库中,需要的同学自取。

安装 Leo

这个过程主要看网络环境,我下了半小时左右,期间利用时间来查询一些相关资料及文档,我的环境是 MacOS,需要安装 git 和 rust。git 的安装很简单(Mac OS 自带),而 rust 则需要执行以下命令

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

通过以下指令来查看环境是否安装成功

git --version
cargo --version

然后在你习惯的 working directory (比如说我 cd ~/src/) 克隆 Leo 项目,并安装 Leo

git clone https://github.com/AleoHQ/leo
cd leo

cargo install --path .

执行完这一步之后,将会在 ~/.cargo/bin/leo 创建一个可执行文件。

可以通过在终端运行以下指令来验证安装是否成功

leo

代码高亮

我使用的开发环境是 VSCode,直接在应用商店搜寻 Leo 然后安装第一个插件(作者:aleohq,识别号:aleohq.leo-extension

创建第一个 Leo 项目

回到你的 working directory(这一步很重要!),通俗点就是 terminal 的位置要在你平时放代码的目录。leo 创建的项目和其他编程环境一样(如 Node JS),会创建一个项目文件夹。

然后执行以下指令

leo new hello
cd hello

这时候会创建一个 leo 项目目录,并将其命名为 hello,然后我们进入 hello 文件夹中。里边的文件列表是这样的:

hello/
├── .env # 程序的环境配置
├── program.json # 程序的 Manifest 文件
├── README.md # 文件文档
├── build/ # 构建出的可执行文件
├── inputs/ # 文件的输入
│ ├── hello.in # 程序的输入参数在这里设置
└── src/ # 源程序
└── main.leo # 程序源代码

执行项目

因为创建的项目中已经有一个写好的 example 文件,所以我们可以通过以下指令编译并运行程序

leo run main

一些细节上的内容可以直接查看官方文档,由于篇幅限制就不再赘述

代码解释

源程序给出了这么一段代码

// The 'hello' program.
program hello.aleo {
transition main(public a: u32, b: u32) -> u32 {
let c: u32 = a + b;
return c;
}
}
  • hello.aleo 是我们的程序名称,他必须和我们的 Manifest 文件中的 program 字段相对应。
  • transition 的意思是构建了一个 transition 函数,目前尚未对 transition 函数有了解,但是本文后面有对该函数的猜想
    • 然后 main 函数中携带了两个参数:
    • public a: u32:
      • u32 初步判断为其他编程语言中 unsigned int32 类型
      • public 指的是这个函数的可见性是公共的。
    • b: u32:
      • 这个是私有变量,默认变量作用域就是私有变量
    • -> u32:
      • 这个写法说明 main 函数返回一个 u32 的值
  • 理论上 main 可以是任何一个英文单词(在本文后面会讲解关于:关键字、输入文件等相关概念)
  • 函数中使用 let 语法定义了一个 c 变量,类型也为 u32(和我们的返回值相同)
    • 它的值就是 a + b。由此可见我们的 main 函数执行的功能就是两数相加
  • 最后再通过 return 语法返回 c 变量。

官方提到,由于开发者也是人类,也会犯错,所以他们将该编程语言设计成强类型编程语言。

但是我在这里吐槽一下,这种类型的语法未免也太魔鬼了吧。第一眼看到这个写法我的直觉是好复杂。

文件输入

我们来观察 hello.in 文件,这将是我们 hello.aleo 程序的输入。

暂时不知道作者这么操作的意图(或者说输入文件存在的意义)是什么,正如我一开始所说,区块链是我最近才深入接触的领域。

[main]
public a: u32 = 1u32;
b: u32 = 2u32;

可以看到,[main] 代指以下的信息是会传递给 main 函数的,其中传递:public a: u32 (这个值和上面函数定义的值相同),而它的值为:1u32。如果将其置换为其他编程语言表示,应该是这样:

public UInt32 a = 32; 

换言之,它的数据表达应该是 【值 类型】。

验证猜想

有了上面的实操经验,接下来我来验证一些我在学习中的猜想

猜想:一个 program 中可以有多个函数

因为我注意到我们是通过 leo run main 指令来执行程序,而非 leo run 或者 leo run hello.aleo。这样我猜测 leo run main 其实是执行 main 函数。这就是说,一个 Leo 程序可以拥有多个 transition 函数。于是我增加了这么一句:

transition substract(public a: i32, b: i32) -> i32 {
let c: i32 = a - b;
return c;
}

可以注意到:我增加了一个 substract 函数,参数需求和 main 函数几乎相同,不同的是数据类型由 u32 变为 i32。也就是一般编程语言中的 int。返回值也同样变成了整型。而函数执行的是 a - b 并将其返回。

我们先不急着执行这个函数,别忘了我们还需要去定义函数的输入,现在渠道 hello.in 文件。

猜想:hello 文件中可以对不同的函数定义不同的输入

上面我们定义了一个 [main] 函数的输入,那么在这里,函数中我们创建了

[substract]
public a: i32 = 4i32;
b: i32 = 2i32;

因为我们创建的是 substrate 函数,所以这里也需要写上 [substract],让程序知道这个输入是给 substract 函数使用的。

同样的,我们要给对应的变量定义正确的数据类型,在这里是 i32

猜想:除了 main 函数,我们也可以执行别的函数

上面学的是 leo run main,然后它执行的是 main 函数嘛。那我们可以通过修改 run 之后的值,来执行别的函数,如:

leo run substract

执行这段指令之后,会执行我们自定义的 substract 函数。并执行减法输出。

猜想:leo 程序的执行顺序

当我们执行 leo run xxx 时,它会运行 xxx 函数,然后再去 input 文件夹找到对应 [xxx] 的输入,并执行计算然后输出结果。

验证过程中的意外收获

关键字

为什么我们创建的是 substract 函数而不是 sub 函数。我已经尝试过了,最后得出的结论:

在执行 leo run xxx 之后 leo 将会把我们的源码打包成 aleo。一种类似汇编语言的代码,位于 build/ 文件夹中。而 sub 正是 “汇编” 语言中的其中一个关键词。所以我们不能通过 sub 作为函数。

如果在定义用户标识符使用关键字,那么 leo 会报出:Failed to parse string 报错。

总结

对于 Leo 语言,可能是新兴编程语言的缘故,想要做出差异化。反而使得代码更加的晦涩难懂。何况这种直接转义成“汇编语言”的骚操作,导致一些代码会变得更加冗余。后续的文章中将会对区块链的各种开发语言进行学习与比较。