AELF初体验(从零开始跑通AELF的生活)

本次教程的机器:windows

官方的图文教程:官方的图文教程

大家也可以去看官方的教程。一样的。不过我这里会列出一些我遇到的问题以及如何解决。

教程开始

所需准备工具

(1)开发环境
Visual Studio Code (vscode),需要安装 c#扩展
官方下载地址:https://code.visualstudio.com/docs/setup/setup-overview
(2)工具软件
Google Chrome 官方下载地址:https://www.google.cn/intl/zh-CN/chrome/
git 官方下载地址:https://git-scm.com/book/en/v2/Getting-Started-Installing-Git
dotnet core sdk 2.2 官方下载地址:https://dotnet.microsoft.com/download
nodejs(不低于 8.0 版本) 官方下载地址:http://nodejs.cn/download/
MAC 用户还需安装 Homebrew 官方下载地址:https://brew.sh/

如果你有代理,在下载Homebrew的时候如果不走代理(windows忽略这条)
可以终端设置(每次都要设置)
···
export http_proxy=socks5://127.0.0.1:1080 # 配置http访问的
export https_proxy=socks5://127.0.0.1:1080 # 配置https
export all_proxy=socks5://127.0.0.1:1080 # 配置http和https访
···

nodejs建议装稳定版,目前是10点多

运行demo

1.下载demo源码https://github.com/AElfProject/aelf-boilerplate
喜欢用git下的可以使用git clone进行下载

git clone https://github.com/AElfProject/aelf-boilerplate

如果git下载太慢直接直接github的download走起

下载后打开vscode,点击左上角的File=》Open Folder导入整个项目


file folder

然后 打开AElf.Boilerplate.sln文件(位于根目录下的chain文件夹里)
打开 vscode 后若出现下图中的提示框,请分别选择“yes”和“Restore”


图截取自原教程

2.下载protobuf和unzip
如果是非windows用户,直接按以下命令下载即可

sh chain/scripts/install.sh 命令下载protobuf 脚本

如果下载出错建议手动下载并且配置环境变量(通用)
原教程的手动安装教程:链接

官方教程中给了几个建议,这里建议直接用第三个,如下:

111. 手动下载 protoc

下载地址: [https://github.com/protocolbuffers/protobuf/releases/tag/v3.7.0](https://github.com/protocolbuffers/protobuf/releases/tag/v3.7.0)

1.  下载 protoc-3.7.0-win64/32 根据系统判断下载哪个版本

2.  解压缩到任意目录(路径需要全英文)

3.  设置环境变量(解压缩目录/bin)


222. 手动下载unzip

下载地址: [https://sourceforge.net/projects/gnuwin32/files/unzip/5.51-1/unzip-5.51-1.exe/download?use_mirror=nchc&download=](https://sourceforge.net/projects/gnuwin32/files/unzip/5.51-1/unzip-5.51-1.exe/download?use_mirror=nchc&download=)

1.  安装到任意目录(路径需要全英文)

2.  设置环境变量 安装目录/bin

手动安装完记得退出当前的命令行重新打开(不然环境变量不生效)

demo开始

当上面的环境都配置好之后,就可以开始运行demo了。

首先介绍一下vscode的teminal
点击红框内的地方可以打开界面

image.png

点击terminal就可以打开teminal了


image.png

点击+号可以新开一个teminal,点击垃圾桶可以关掉teminal


image.png

掌握这些基本用法后,我们将会在这个地方多开teminal进行操作

首先启动整个链(hello world智能合约,后面我会简称为这条链)

cd chain/src/AElf.Boilerplate.Launcher/
dotnet build
dotnet run bin/Debug/netcoreapp2.2/AElf.Boilerplate.Launcher

看到这个字样说明链跑起来了


image.png

特别提醒,只要不爆红,就是正常的,爆黄无视即可

如果出现以下报错(这几个字是白色的,不是红色报错),说明没有下载到一个文件,
手动到https://github.com/AElfProject/contract-plugin/releases/download/v1.0.2/contract_csharp_plugin-v1.0.2-win32.zip这个地址下载并放到chain/scripts文件夹下即可

 unzip:  cannot find either aelf-boilerplate/chain/scripts/contract_csharp_plugin-v1.0.2-win32.zip or aelf-boilerplate/chain/scripts/contract_csharp_plugin-v1.0.2-win32.zip.zip.
  Could Not Find aelf-boilerplate\chain\scripts\contract_csharp_plugin-v1.0.2-win32.zip
  --contract_out: protoc-gen-contract: The system cannot find the file specified.

如果正常运行,链会以500ms的速度刷新,如图现在链的高度是96


image.png

当整条链跑起来后,我们就挂着就行,之后的demo项目跑的时候这条链记得不用关。

  • demo1 测试智能合约
    在根目录运行以下代码
cd .\chain\test\HelloWorldContract.Test\
dotnet test

只要测试通过即可


image.png
  • demo2 运行 JS SDK Demo
    根目录运行以下代码
cd .\web\JSSDK\
npm install
npm start

全部运行后会弹出网页,alert一个hello world,页面上会显示hello aelf。

出现这个即为成功

如果运行npm start报错的话,直接去JSSDK项目下直接打开Index.html即可

npm start报错

  • demo3 运行 AElf 浏览器插件 Demo
    根节点运行以下命令
cd .\web\browserExtension\
npm install
npm start

如果npm start失败,直接去文件夹里打开Index.html即可

这个时候应该会弹窗说什么not ready之类的。因为我们还没安装插件


image.png

用谷歌浏览器打开链接https://chrome.google.com/webstore/search/aelf?hl=en
下载安装这个

image.png

安装后刷新一下页面,应该会弹出xxx is ready的字样。这时候页面上的按钮都是点不动的。我们点击浏览器右上角aelf的插件图标。


image.png

输入密码后 ,点击创建钱包。
钱包创建后,如下所示,这时候我们点击密钥对=》创建密钥对
创建成功后,刷新网页,点f12(开发者模式)。

点击getChainStatus,console会输出如下东西


image.png

点击login后,会输出如下


image.png

点击init contract


image.png

点击hello 会alert hello world。会输出如下


image.png

如果是参加活动,录屏记得录下console的东西

完成如上后,demo完成

  • demo4 运行 DAPP Demo——BingoGame

在根目录下运行

cd .\web\browserBingo\
open index.html

如果open index.html运行报错,手动打开Index.html即可

点击register 初始化


image.png

然后点击下注金额,点击play 按照提示进行即可。

那么到了这里,这个4个demo就已经体验完成了。
已经完成任务了。

但是活动还出了一个题目给我们:


image.png

文档链接1:https://docs.aelf.io/main/main/smartcontracthelloworld
文档链接2:https://github.com/AElfProject/aelf-boilerplate/blob/hello-world/docs/%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E7%BC%96%E5%86%99.md

刚开始修改这个demo的时候还没有链接2,链接2是中文的,也清晰一点。以下的教程是我根据链接1的一个摸索历程。

那么我们现在开始学习如何修改hellowrold demo。

修改helloworld

1.项目结构
项目分为两部分,chain部分和web部分。官方教程主要围绕chain部分来讲解


image.png

我们点开chain文件夹,里面有四个文件夹,分别是protobuf,scripts,src和test。scripts是这个demo的构建脚本,不是重点。

  • protobuf 这个文件是定义protobuf的地方
  • src
    1.AElf.Boilerplate.Launcher: 可以理解为区块链代码(node,节点,原文是一个用命令行跑起来的节点),其他项目依靠这个节点跑起来才能正常运行
    2.AElf.Boilerplate.Mainchain: 上面这个节点的library
    3.HelloWorldContract: Hello World contract的实现,也是本文重点
  • test 测试代码

Hello World contract

下面介绍如何写一个智能合约。我们将在这个已有的项目上进行。
在AELF中,合约(contract)使用protobuf来实现/执行,并且被定义为一个服务(in AElf, contracts are defined as services and are implemented using Protobuf),这句话看不懂没关系。继续。

我们点开chain/protobuf/hello_world.proto.

syntax = "proto3";
​
import "aelf_options.proto";
import "google/protobuf/empty.proto";
​
option csharp_namespace = "HelloWorldContract";
​
service HelloWorldContract {
​
    option (aelf.csharp_state) = "HelloWorldContractState";
​
    rpc Hello (google.protobuf.Empty) returns (HelloReturn) { }
}
​
message HelloReturn {
    string Value = 1;
}

可以看到定义了一个方法(rpc)Hello和一个类型(message)HelloReturn。

这里的语法是protobuf的语法,可以百度搜索以下具体的语法。
怎么理解这里的rpc和message呢。我们可以把rpc看成是抽象类,这里只定义名字(Hello),入参(google.protobuf.Empty),出参(HelloReturn)。我们可以把message看成是一个类。这个类可以用在入参和出参上,如果你没有参数,那么使用google.protobuf.Empty即刻。到了这里,你可以看出,其实这个google.protobuf.Empty也是一个定义的类,所以你就知道了,rpc方法的入参出参,你就直接扔一个自定义类(message)即可。

好了,既然定义了抽象方法(rpc),那么总得有一个实现类。

打开chain/src/helloworldcontract,点开HelloWorldContract.cs 和 HelloWorldContractState.cs这两个文件。

提示:如果你连续点开得话,会发现只会打开一个页面,我们会觉得很不方便,这时候我们可以右键文件,open in side,就可以对比得看

image.png

HelloWorldContract.cs
如下,可以看到这里实现了Hello方法,入参是一个empty。返回了一个HelloReturn。这里可以看到,返回是new了一个返回message,并且是key value得形式,key是我们在protobuf中定义得名字得,value就是我们想要返回得东西

using Google.Protobuf.WellKnownTypes;
​
namespace HelloWorldContract
{
    public partial class HelloWorldContract : HelloWorldContractContainer.HelloWorldContractBase
    {
        public override HelloReturn Hello(Empty input)
        {
            return new HelloReturn {Value = "Hello world!"};
        }
    }
}

HelloWorldContractState.cs
这个State是我们这个helloContract得一个状态容器(我是这么理解得),目前是一个空实现(This class represents the state of the contract. It is empty now)

using AElf.Sdk.CSharp.State;
namespace HelloWorldContract
{
    public class HelloWorldContractState : ContractState
    {
    }
}

点开chain/test/helloworldcontract.test/helloworldcontracttest.cs
可以看到测试代码如下:
使用HelloWorldContractStub.Hello.CallAsync去调用方法
await 去等待结果返回,方法是异步得(await是js得新特性)
使用result.Value.ShouldBe去进行测试

public class HelloWorldContractTest : HelloWorldContractTestBase
{
    [Fact]
    public async Task HelloCall_ReturnsHelloWorldMessage()
    {
        var result = await HelloWorldContractStub.Hello.CallAsync(new Empty());
        result.Value.ShouldBe("Hello world!");
    }
}

知道了大概得流程走向后,现在我们要开始修改项目了。

首先,回到protobuf得定义处,chain/protobuf/hello_world.proto.,添加两个rpc方法

rpc Visit (Visitor) returns (google.protobuf.Empty) { }
rpc GetVisitors (google.protobuf.Empty) returns (VisitorList) { }

添加两个message(repeated是protobuf中的一种限定修饰符,从字面意思看有“重复”的意思,实际上它就是用来指定某一个字段可以存放同一个类型的多个数据(当然也可以是0个或者1个),相当于C++中的vector或者Java中的List。)

message Visitor {
    string Name = 1;
}
​
message VisitorList {
    repeated string Names = 1;
}

注意,上面的message的序号是从1开始的,不可以从0开始,否则会爆field numbers must be positive integers这样的提示
编写完后,我们来编译(build)

cd chain/src/HelloWorldContract/
dotnet build

题外话1:如果你在之后得操作中,发现一些定义好像没生效之类得话,可以删除HelloworldContract/protobuf目录下得xxx.c.cs和xxx.g.cs文件,然后重新编译即可,在你没有删除得时候,编译会爆黄,而删除后编译,则不会爆黄

题外话2:c#跟java得ide不太一样,java得ide编写的时候会自动帮你编译,然后你可以直接导入,代码就不会爆红。但是使用vscode写c#的时候,如果你定义了还爆红,那么可以尝试build多一次,等待个5s,就可以了

题外话3:vscode中,ctrl+. 可以提示

然后我们接下来去实现
点开src/HelloWorldContract/HelloWorldContractState.cs,在HelloWorldContractState这个类里面添加这句代码(个人猜测是c#的get set,未验证)

public SingletonState<VisitorList> Visitors { get; set; }

点开src/HelloWorldContract/HelloWorldContract.cs
我们去实现那两个方法
可以看到,我们可以使用State.方法名.Value去获取值

public override Empty Visit(Visitor visitor)
{
    if (State.Visitors.Value == null)
        State.Visitors.Value = new VisitorList();
​
    State.Visitors.Value.Names.Add(visitor.Name);
​
    return new Empty();
}
​
public override VisitorList GetVisitors(Empty input)
{
    return State.Visitors.Value;
}

然后运行

dotnet build

如果vscode爆红,并不绝对代表代码有错,放心去编译把

接下来我们测试一下编写的代码

点开chain/test/HelloWorldContract.Test/HelloWorldContractTest.cs
添加测试代码:

public async Task VisitCall_AddsVisitorToVisitorList()
{
    await HelloWorldContractStub.Visit.SendAsync(new Visitor { Name = "Jon Snow"});
​
    var result = await HelloWorldContractStub.GetVisitors.CallAsync(new Empty());
    result.ShouldBe(new VisitorList { Names = { "Jon Snow" }});
}

运行下面命令即可进行测试(如果发现没有结果,可以看看是不是目录cd错了)

dotnet test

整个修改过程就是如此。当然,新增代码后,整个链要重启一下,不然会不更新

那么我们要添加的这个斐波拉契数列函数的思路也很明了了

  1. 首先,我们要在protobuf中添加一个rpc方法
  2. 然后添加两个message(入参,返回值/出参)
  3. 在HelloWorldContract.cs文件中实现具体的逻辑
  4. 根据上面指引,在JSSDK中index.html中
    在第42行后面增加
    helloWorldC.Fibonacci.call(这里是对应的斐波拉契数列函数输入, (err, result) => {
    alert(result);
    });

我们来点开这个index.html,添加,但是可能会发现返回的值是undefind。这时候我们看看别的项目是怎么写的.可以看到,调用时直接传一个{key:value}对象进去的,如果你是直接传一个值进去,是会无法识别的。而取值的话是用的result.名字去取得。

bingoGameContract.Play({Value: value}, (error, result) => {
            if (result) {
                console.log(result);
                play.style.display = 'none';
                loader.style.display = 'inline-block';
                txId = result.TransactionId;
                setTimeout(() => {
                    bingo.style.display = 'inline-block';
                    loader.style.display = 'none';
                }, 20000);
                alert('耐心等待20s,出现Bingo按钮后点击查看开奖结果!');
            }
        });

好的,到这里,整个体验过程就结束了,谢谢大家的观看。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • 应朋友要求试了一下aelf公链,楼主表示自己没看过区块链相关的知识,也不会c#,但是真的在15分钟左右就通关了ae...
    Darkeril阅读 829评论 0 2
  • 2016更新:本文写于2014。其中值得注意的是,建议默认使用python编写脚本,对跨平台有好处。而并非下文即将...
    DonaldW阅读 11,169评论 7 34
  • 1、上午带着儿子一边看电影一边吃刚从每日生鲜上订的好吃的。 2、晚饭第一次试着做了一条清蒸黄花鱼,被猫咪父子俩一扫...
    星空梦旅人Beverly阅读 152评论 0 0
  • 芝麻大的小爬虫,我用纸巾用力搓压两次后,过会儿,它从纸巾下,多瘸多拐的挣扎出来了,我一手啃苹果一手拿起纸巾,压下…...
    就小妞阅读 129评论 0 1
  • 最近感冒,后期伴随着咳嗽,2个星期过去了,也不见好转。 资料说感冒之后的咳嗽可能会持续1到2个月,太漫长的等待时间...
    呱呱鸟阅读 3,132评论 7 43