用 Go 语言写焦虑发生器并发布到 Rum 上·第一篇

初学 Go 语言是在去年 11 月 20 日。到今年 2022 年的 2 月 3 日,我写了一个小 bot 连续运行成功,发布到了 github 上开源。花了两个多月时间。我感觉效率还是不错的。
于是我这就来记录这段学习经历:
目的一是让同样正在跨编程入门这道薛定谔之忽高忽低门槛的小白同学一些参考,更顺利的入门编程;
目的二是回顾并巩固自己过去的学习,为下一步继续学习打好基础;
目的三是让更多的人能够对 Rum 这个新的东西感兴趣。
希望能成功达成目的:

Go 语言基础入门

学 Go 的出发点是因为大佬们都用 Go 语言来写链上应用。看着他们在群里交流的非常欢乐,文字我都认识,但就不懂他们在讲什么。
这种感觉太难受,就像小矮人身在片场却眼巴巴看高等精灵们讲精灵语,脸上还是挂着围笑假装在参与对话。

然后呢,因为自己喜欢游戏,找了本书叫:Pac Go: A Pac Man clone written in Go
就是用 Go 语言写吃豆人游戏。好,从这本书开始入门 Go。
并不是因为作者是美丽的女程序员我才选择的这本书。

并不是

P.S. 这本书的链接是链到 [xue.cn](https://xue.cn) 的,是一个可以一边阅读编程教程一边在当前书页运行代码的学习网站。

一边做实例,一边学编程,也非常符合我自己的学习理念。很快我从 xue.cn 转移到了 github 去学习,上面有 Pac Go 的开源代码。自己 clone 了一份到电脑上,然后通过读 readme 继续学习。

老实说 Pac Go 的前 5 章我认真跟着学了,后面就没有认真学,而是略读之后,感觉基础语法已经掌握差不多了,就开始用 Go 做自己的项目。
因为新的一年快要到了,如何让人即便是年初,也要焦虑起来呢?想到了在 Twitter 上见过的 year progress。把人习以为常的日期,转变成百分比的进度条,会发现,时间怎么这么不经用?这么不经意的流逝掉了?这会让人产生巨大的焦虑感。于是我打算做一个这样的 bot 并到 Rum 上去运行。

Go 语言发送 HTTP request

理性的角度出发我应该规划一下这个程序的各个功能零件,以及工作流程,然后从生成进度条这一步开始,最后再做发布到 Rum 的 HTTP 请求。但我是小白啊,我野路子啊!我有搞着玩的特权啊!
先试着用 Go 写 HTTP 的 Post 请求,发布到 Rum 上看看再说。

导入Go 语言的 HTTP 包:

1
import "net/http"

有了这个包,就可以调用 Go 语言的 HTTP 方法了,这里我是随便 google 了一下,了解到 HTTP 到底是个什么东西,HTTP 请求又是怎么发送的。
在此建议像我一样的新手小白也自己去研究 HTTP,这个并不难。本文不再花篇幅来讲 HTTP。
当然深入研究也会花大量时间,这里用不到那么深入的知识,单独看看 Post 和 Get 两种最常用的 HTTP 请求就好了。

简单理解了 HTTP 请求,回来继续写自己的代码。

建立一个 client 用来发送 request。代码是:

1
2
3
4
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}

上面这一段代码简单的解释是这样的:
变量 client 是一个地址,指向了 http 包内的 struct,名为 Client。而这个 Client 里的一个值,也是一个 struct,名为 Transport。将 Transport 里的一个 TLSClientConfig 写入一个 tls 设置,把 InsecureSkipVerify 设置为 true。
这里的 tls 是把 HTTP 变成 HTTPS 的一层协议。我们这个设置是为了跳过一个 tls 的验证。因为这个 HTTP 请求的地址就在本地,我们可以不用进行验证。

client 建立之后我们需要用 client 来发送请求。这段代码是:

1
2
3
4
5
6
7
8
9
10
11
12
req, err := http.NewRequest("POST", "https://127.0.0.1:[Rum节点的端口号]/api/v1/group/content", body)
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")

resp, err := client.Do(req)
if err != nil {
panic(err)
}

defer resp.Body.Close()

变量 req 就是我们要发送请求的一个实例了。通过 http.NewRequest 来建立,有三个参数,分别是:
“POST”,表示我们的请求是 POST 方法;
第二个参数是 URL,端口号可以在 Rum 客户端的“节点与网络”菜单中的“节点参数”中找到;

第三个 body 变量是要 Post 给 Rum 的具体内容。

接下来设置一个 header,把 header 设置为一个 json 的内容。这是因为 Rum 需要我们发送 json 内容。
最后就通过 client.Do(req) 来执行我们设置好的一切,并将请求到的返回值赋值给 resp 变量。这样就通过 Go 完成了一个完整的 HTTP request。

我把这个完整的 HTTP request 提供如下,整个 request 写成了一个叫 postToRum 的函数,请注意函数里面定义的叫 Payload 的 struct 数据结构是按照 quorum 的格式要求来声明的,内容格式可以自定义的是标题,正文,然后目标种子网络的ID,其他的不用修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
func postToRum(title string, content string, group string, url string) {
type Object struct {
Type string `json:"type"`
Content string `json:"content"`
Name string `json:"name"`
}
type Target struct {
ID string `json:"id"`
Type string `json:"type"`
}
type Payload struct {//按照 quorum 要求的数据结构进行声明
Type string `json:"type"`
Object Object `json:"object"`
Target Target `json:"target"`
}

tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}

data := Payload{
Type: "Add",
Object: Object{
Type: "Note",
Content: content,
Name: title,
},
Target: Target{
ID: group,
Type: "Group",
},
}

payloadBytes, err := json.Marshal(data)
if err != nil {
panic(err) // handle err
}

fmt.Println(string(payloadBytes))

body := bytes.NewReader(payloadBytes)

req, err := http.NewRequest("POST", url, body)
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")

resp, err := client.Do(req)
if err != nil {
panic(err)
}

defer resp.Body.Close()

received, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(received))
}

函数的四个参数分别是 title 表示标题,content 表示内容,group 用于指定要发布内容的种子网络 ID,最后 url 是要发 POST 请求的目标 url,这里的地址是根据 Rum 的 api 要求来的,读者感兴趣可以自己在 Rum 的 github 主页去看看,这里的话可以直接用我提供的地址。

值得注意的是,请求的内容主体:body 变量,经过了两次加工:
最初是一个 struct,这个 struct 要符合 Rum 的格式要求,我们取名叫 Payload。
然后用 Payload 来创建一个叫 data 的实例,给 data 填入了具体的内容。
再接下来,用 json.Marshal(data) 方法,把 data 解析成了 json 格式,并赋值给变量 payloadBytes。
最后再把 payloadBytes 通过 bytes 包的 bytes.NewReader(payloadBytes) 方法,转变成了能够通过 HTTP POST 方法发送给 Rum 的字符。

既然写好了这个函数,我也迫不及待的往 Rum 上发了一个 Hello Rum 的消息。
于是在 mian 函数里写下如下代码:

1
2
3
4
5
func main() {
url := "https://127.0.0.1:[端口号]/api/v1/group/content"
postToRum("Hello Rum", "Hello Rum", "[目标种子网络的ID]", url)

}

目标种子网络的 ID 可以在种子网络的详情处获取到,比如“Go语言学习小组”的 ID 是

fe2842cb-db6b-4e8a-b007-e83e5603131c

我们填入 ID 就可以往“Go语言学习小组”发送 Hello Rum 了。
以上代码的片段忽略掉了一些 Go 语言的一些前置语句,比如包管理的 package 语句,比如引入依赖的包的 import 语句。这里我把代码完整的提供到了 github 仓库里。本系列文章的第一步骤放在了 Step0 文件夹里(因为我们程序员要习惯从零开始):

https://github.com/hawken-im/yearprogress/tree/main/Step0

clone 完整代码或者复制粘贴也行,之后在 Step0 目录下执行:

1
go run main.go

就能看到结果了。

非常欢迎读者们发送 Hello Rum 到“Go语言学习小组”,小组的种子提供于此:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"genesis_block": {
"BlockId": "7016d356-b42f-421c-a086-094e1f35dbeb",
"GroupId": "fe2842cb-db6b-4e8a-b007-e83e5603131c",
"ProducerPubKey": "CAISIQOU1kDjMc3cCZRKV/r2bU/IUPukEcdFkIqkFe3Gbqfy+w==",
"Hash": "v+kfzMMuwNgb2h1PUAktBk1K9DZbN9pEdcfg2rG1Zys=",
"Signature": "MEUCIAZ8A4fgP5TWjXZoAe47qqfktrMrP1/2MMsOM5QsaFiQAiEAn8i8SzpdbGd4wlbbtk6Dws32Ea6aBWtcam+VdUzeHBg=",
"TimeStamp": "1637338394235167000"
},
"group_id": "fe2842cb-db6b-4e8a-b007-e83e5603131c",
"group_name": "GO语言学习小组",
"owner_pubkey": "CAISIQOU1kDjMc3cCZRKV/r2bU/IUPukEcdFkIqkFe3Gbqfy+w==",
"consensus_type": "poa",
"encryption_type": "public",
"cipher_key": "835360cc49a5faf385b906b8fd1fb16f31a73c652c65398513070c27a3920550",
"app_key": "group_post",
"signature": "304502204baef7f83e01af403791a96024413deb59ecec7b92f9ae2c18377917e127e6c1022100a4529dc2542aa3f6dc9afd8d14d8bfbcbb3ac33a3a32ca993805a13a77942efe"
}

学 go 语言的一些小笔记

Thu-Feb-3 2022 终于弄好了包管理 YearProgress 2022 这个项目暂时告一段落

在度假,网不好,因此没法翻墙,断断续续 baidu 了好几天,被弄到 CSDN 里兜兜转转了好几天!鬼打墙一样。
今天好不容易找了个咖啡店,翻出去了,立刻!马上!看到了这句话:

“In the most basic terms, A package is nothing but a directory inside your Go workspace containing one or more Go source files, or other Go packages.”
划重点是”is nothing but”

这个太关键了
中文文章要么就是高深莫测,搞得小白不知道他们是不是在故弄玄虚,要么就觉得包管理是不是太习以为常就干脆跳过。
这篇文章就叫深入浅出。即便是可能会很高深,但是文章也说了, “In the most basic terms”。 对,可以很难,但是本小白要的就是”most basic terms”。 文章链接在此: https://www.callicoder.com/golang-packages/

Mon-Jan-24 2022

继续学了 flag 和 arguement,这样就可以在命令行输入酷酷的命令了。
go 的两个包分别是:

1
2
"flag"
"os"

Sun-Jan-23 2022

昨天跑通了 json 的解析,今天开始系统的学习 struct 以及指针,这样就能在函数中读取 struct 并返回一整个 struct
今天主要看的书是 Head First Go
下一步应该要把包管理学了,不然现在所有的代码都是堆在一个文件里面
学完小半本 Head First Go 之前应该暂时不会更新 Year Progress 2022 代码了

Sat-Jan-22 2022

今天学 go 语言解析 json,这两个教程解答了我很多问题:
https://eager.io/blog/go-and-json/
https://golangbyexample.com/struct-json-golang/

从零开始在 Ubuntu 20.04 上Build Quorum 并用本地 Rum App 进行连接

2022 Feb 13版本更新:

新版 quorum 里 jwt token 是可选项,如果留空的话系统会自动生成一个。


Rum App 发布后我搭建了一个 windows server 运行,但一直感觉不够炫酷,于是折腾了一台 Ubuntu 主机。在主机上自己 Build Quorum,并运行,并在两位大佬轮番指导下才通过本地 Rum App 连接成功。两位大佬一位是 samson 一位是 wanming,这篇文章圈不出来他们本人。但是真的很感谢他们的热心帮助。如果大佬看到希望可以在评论区留言认领我的感谢。

正文开始

1. 从零开始的第一步 - 在服务器上获取 Rum System

这一步我们会通过 git 命令从 github 上直接克隆一个 Rum System 到我们的服务器上。
所以你需要先在服务器上安装 git:

1
sudo apt-get install git

安装完成输入命令:

1
git --version

检查一下是否安装成功。
接下来就是从 github 上通过 git clone 命令来克隆 Rum System。
Rum System 在 github 上的地址是:
https://github.com/rumsystem/quorum

点击“Code”按钮会出现下拉菜单,菜单中选择“SSH”这一栏,就会出现仓库地址了。

将仓库地址放到克隆命令后,回车执行命令行:

1
git clone git@github.com:rumsystem/quorum.git

如果发现系统提示我们无法连接,是因为 git clone 命令是通过 SSH 进行连接的,我们需要在自己的 github 账号里加入我们的 SSH 公钥。

步骤可以参考 github 的官方教程,链接如下:
https://docs.github.com/en/authentication/connecting-to-github-with-ssh

克隆完成后可以“ls”一下看看是不是有了“quorum”这个文件夹。

2. Build

现在可以进入文件夹去 build 我们的 Rum System。

1
cd quorum

在根目录里执行开发人员准备好的脚本文件就好:

1
./scripts/build.sh

这个时候有可能会报错,是说我们还没有安装 go 语言。那我们就安装一下好了。
go 语言的官方下载页面在这里:
https://go.dev/dl/

进去后下载 linux 的版本就好:

你可以通过 scp 命令上传到服务器,也可以在服务器上用 curl 命令把这个文件下载下来。
我这里是在本地用的 scp 命令:

1
scp [本地tar.gz] [用户]@[服务器地址]:[服务器文件路径]

上传成功后,到文件所在位置输入如下命令:

1
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.17.6.linux-amd64.tar.gz

然后把 go/bin 输入到环境变量中,只需要把下面的语句放到 /etc/profile 文件内:

1
export PATH=$PATH:/usr/local/go/bin

确认一下是否安装成功:

1
go version

go 语言的官方安装教程在这里:
https://go.dev/doc/install

再次 Build 成功,进入下一步。

3. 在服务器上运行 Quorum

Build 成功的可执行文件存在 dist 文件夹中。cd 进 dist 去,ls 看到 dist 里面的文件夹里有个 linux 文件夹,再次 cd 进去,就到了 linux 系统的可执行文件的所在地了。

直接 ./quorum 运行是不行的,需要加一些参数,我的带参数的运行命令是这样的:

1
RUM_KSPASSWD=[我的密码] ./quorum -peername [我的节点名] -listen /ip4/0.0.0.0/tcp/7000  -apilisten 0.0.0.0:8002 -peer /ip4/94.23.17.189/tcp/10666/p2p/16Uiu2HAmGTcDnhj3KVQUwVx8SGLyKBXQwfAxNayJdEwfsnUYKK4u -peer /ip4/132.145.109.63/tcp/10666/p2p/16Uiu2HAmTovb8kAJiYK8saskzz7cRQhb45NRK5AsbtdmYsLfD3RM -ips [服务器的公网IP] -ips 127.0.0.1

这样就能运行成功了。
运行成功的界面应该长这样:

会跳出一些 warning 什么的,可以暂时忽略掉。

这个时候可以输入一个 curl 命令检查一下是否连接成功:

1
curl -k https://127.0.0.1:8002/api/v1/groups

成功的话会返回一个当前种子网络的状态的消息。

进入下一步之前再保存一个密钥,它位于 quorum 文件所在的文件夹里,cd 进 cert 文件夹,里面有两个文件分别是 server.key 和 server.crt。输入命令:

1
cat server.crt

把返回的密钥复制保存在本地。

新版本里 jwt token 不是必须的,这里也可以去存一个备用,jwt 位于 quorum 运行根目录所在的 config 文件夹里,里面有个后缀为 .toml 的文件,cat 或 vi 打开就能找到 jwt。

4. 本地 Rum APP 连接服务器

这下万事俱备了,我们在本地打开 Rum APP,从菜单项“节点与网络”中选中“外部节点”。

到了填入节点信息的步骤,把我们在上一步收集到的 jwt 和 server.crt 填进去就好了:

顺利的话,应该可以看到“外部节点模式”亮绿灯了:

不顺利的话,比如我,踩到的坑我在下一个小节总结一下,看看读者能不能顺利回避:

踩到的坑:

  1. 如果是新手小白的话可能会在各种文件夹和目录之间反复横跳找不到方向。这个看仔细一点就好了。
  2. 防火墙可能会阻止本地 APP 连接服务器。解决办法是打开端口 433,7000,8002。
  3. 最坑我的是我的云主机买的内存太小,如果内存溢出 quorum 进程马上就会被杀死。这个问题我一直无法定位,走了好多弯路,最后是求助大佬帮我发现的。解决办法是加了 1G swap。
  4. 最后是一个很好用的工具 tmux,可以帮我们保持住 quorum 的运行的同时开启别的命令行界面进行测试。

Notes Of Learning Go


Sun Nov 21
今天的 Leetcode 练习是:
把罗马数字转化成整数,很有趣的一个小练习(也许是简单容易理解才觉得有趣哈哈)。
然后我对 Go 还不熟悉,还不知道 Go 里面也有类似 Json 的数据结构。
最后看了solution。发现别人的解题思路很棒,很直接。最后采用了她的思路。


Sat Nov 20

今天打算开始每天一个 Leetcode。
试着做了一个递归小函数,这种在以前初学编程的时候感觉好难好难,在 Leetcode 上居然是 easy 级别。程序员真厉害。
https://github.com/hawken-im/GoLeetCode


Sat Nov 19

先是在 xue.cn 上找了书但是发现有bug,然后在github上找到了该repo的地址就干脆在 github 里学习了吧。
https://github.com/danicat/pacgo/

函数中有个叫“defer”的东西,后来去研究了,是一个很方便的语句,可以记录当前的状态但是延迟到函数结束再执行。

然后还学了ansi escape code,一个很奇怪的控制命令行窗口的代码……掌握这个奇怪的知识有啥用吗,还是说这个知识点背后还有点别的有连续性的知识体系,暂时没有继续研究下去。

元宇宙三问

元宇宙三问

我是谁,从哪来,去哪里

1. 元宇宙是什么?

相信本文读者既然能发现我这篇小角落的小文章,肯定已经看了很多别的关于元宇宙的文章了。

我打赌5篇有4篇都会说这几个意思:比如,元宇宙这玩意很复杂我跟你说不清,再比如,大家都对元宇宙有不同的理解, 甚至会直接否定元宇宙,说这是个概念炒作或者噱头什么的。

以上对元宇宙的说法,都是故弄玄虚。

元宇宙这个词的来历无非是一本叫做《雪崩》(Snow Crash)的科幻小说。

《雪崩》描述了一个未来,人类通过科技解决了资金流、信息流的顺畅流动,于是只剩下物流需要传统的运输方式了。留给人类的职业只剩:解决物流的快递员,维护资金流、信息流顺利流通的程序员。其余的人类就好好的玩吧,去哪里玩呢?虚拟世界。这个虚拟世界在小说中,称为“元宇宙”。

所以,去掉了这种神秘感,就也没有故弄玄虚的余地了,再问元宇宙是什么?答案简单明了:

元宇宙是一本科幻小说中描述的一个虚拟世界。

是就是。没有可是但是而是。

这样的解释显然是不够的,因为人们关心的并不是元宇宙这个名词本身,而是元宇宙突然火起来的这个事情,问题二来了:

2. 元宇宙为什么火?

因为时候到了。

一个是全球的疫情把人们锁在家中,带火了一大批网络应用和游戏。

一个是各类影视作品的铺垫,更多人理解了虚拟世界的科幻概念。

还有不能忽略的是虚拟货币的大起大落,消息出圈,让更多的人认识到去中心化的概念。

这些认知的铺垫最后在一个手段特别毒辣的公司手上爆发,从此元宇宙成为了资本追逐的对象。

这个公司叫 Roblox。

他们做的事情,概括的说:

Roblox 做了一个游戏发布平台,这个平台上的游戏全都是通过 Roblox 提供的技术进行开发。而这个技术很高级,以至于大量的小学生都可以开发出可玩性很高的 3D 游戏,而且是网络游戏。于是 Roblox 成为了“寓教于乐”的编程教育公司。大量的青少年在上面开发游戏,并且让TA们的朋友们来玩自己制作的游戏,玩的人多,开发者还可以赚到钱。

我不是给 Roblox 打广告,Roblox 做的事情非常邪恶,以至于我打算以后单独开文章来骂他们,这里仅仅作为背景介绍。

于是 Roblox 就这么火了。趁着学生们没有办法去学校上课,笼络了大量的,抱着免费学编程还可以赚钱的想法的,家长和学生。

Roblox 鸡贼之处又来了,他们一火起来,自然有资本来投入,而且顺理成章的准备上市,上市的时候他们就甩出来了元宇宙的概念,股票也是应声大涨。

是的,元宇宙正式出圈,标志事件就是 Roblox 上市。

接下来各路神仙纷纷出动,如果去一些美股分析网站,我们会经常看到这些公司被点名:

Roblox(刚刚说了)

Facebook(现在干脆连名字都叫 Meta 了)

微软(怎能没有它呢,不提它的实力了,微软都还有 HoloLens,XBox 还有“我的世界”这样的游戏)

亚马逊 (亚马逊前段时间也宣布要搞元宇宙,但是看他们的意思主要就是到虚拟世界选购商品)

Autodesk (一家商业软件公司,著名的工程制图软件 CAD 我相信很多人都不陌生,于是它打算拿出它搞 3D 建模很厉害的看家本领来参与到元宇宙浪潮中)

NVidia (显卡公司,元宇宙怎么能少了显示设备呢)

还有很多别的公司但是都差不多能归类到这几个类别:

社交网络,游戏,基础硬件设施,甚至脑机接口的技术开发。他们受到关注都非常的合情合理。

但是不要忘了还有一个巨大的不怎么被正规资本市场关注的,隐藏游乐场,区块链世界。

不是要说币,烦不烦。

我要说的是区块链世界的强大特性:

  1. 去中心化
  2. 不可篡改
  3. 智能合约

先直接暴力给出我的结论吧:

区块链技术是否能成功发展,直接影响到元宇宙是否能成功创世(成功发展)。

首先元宇宙变成什么样我们才叫成功发展?每个利益体都有不同的意见,比如扎克伯格可能认为大家都来他的 Facebook 注册元宇宙账号,建立自己的朋友圈,他的元宇宙就成功了;比如游戏公司可能觉得,玩家们带上 VR 眼镜开始玩大型的虚拟现实游戏,没日没夜泡在里面,就是成功。这里正常人都会反应过来,那我们不挣钱不工作?拿什么叫外卖?

是的,这些问题归结为,怎么解决人在虚拟世界的产值的认定。游戏账号说删掉就删掉,服务器说关停就关停。Facebook 也面临各种利用用户信息获利的指责。

用户或者玩家在虚拟世界投入了大量的时间和精力,最后产生的数据甚至都不属于TA。这样的虚拟世界恐怕没有人会承认是一个可供人类的虚拟身份和数字资产入住的元宇宙。

怎么解决以上的问题,就是我刚刚引出来的区块链了:

去中心化,保证数字资产不受某一处或几处中心服务器的制约。

不可篡改,保证私有产权的神圣不可侵犯。

智能合约,这个概念对于不常接触区块链的朋友比较陌生,可以简单说,但是它很重要。简单说:保证元宇宙中的信息流动规律像是在遵守宇宙定律般自然而然按照既定的规则运行,无需第三方提供监管或担保。

甚至我在这里大言不惭:区块链简直就是为元宇宙而生,感觉并不过分。

当然当然,我听过很多技术牛人的指导,区块链无非就是几十年前流行的 P2P 技术的应用,是的,朋友们肯定记得电驴啊 BT 下载这些去中心化的文件下载应用。

那看这样的例子:

活字印刷是中国人发明的,但是遇到拼音文字才能被真正的利用,遇到机械工业才能开始量产书籍。

现在元宇宙来了,P2P 技术遇到一个崭新的应用场景,也有了更强大的网络基础设施。

所以,第二个问题一开始我就说了:

时候到了

社交网络公司认为:时候到了。

游戏公司,网购平台,显示设备厂商认为:时候到了。

网络基础设施的建设也让众多从业者发现:时候到了。

作为区块链社区的一员,我的观点也很明确:是时候了。

3. 元宇宙是未来吗?

科幻小说是预言书吗?很少人真的认为科幻小说能够精准预测未来。

但是我们会发现,科幻小说经常会有启发性和警示性。

《1984》告诉我们如果不把怪兽关进笼子会发生什么。

《美丽新世界》警告我们,如果放任消费主义,娱乐至上,人类有可能面临的未来是什么。

银翼杀手更是用电影的视觉冲击把一个可怕的赛博朋克未来深深印在了人类的想象空间。

科幻如此悲观,是有道理的。

《雪崩》提出的元宇宙其实也是很多科幻小说早就有过的设定了,不光是虚拟世界,书中“厉害的不行的快递员”,这种设定在别的科幻作品中都有。

这其实是很多科幻作者基于成书时代的科技水平和社会形态,对人类未来的预判。

比如凡尔纳写的《月球大炮》,当时有了火器的发展进步,富于想象的凡尔纳自然就会想,我们用大炮把人发射到月球上怎样?

而未来会产生虚拟世界,几乎可以说是当今想象家们的一种共识了。

信息技术发展至今,解决了人类很多”必须要移动肉身”的事情了。比如我本人已经在没有办公室的状态下远程办公两年了。

如今能被机器人和人工智能替代的职业也越来越多,甚至建筑也可以在工厂中生产完成,并运输到现场安装。

在大部分基础工作都被 AI 和机器人代替的未来里,能够留给人类做的事情。我认为有三个:

娱乐、创作、探索。

“选择娱乐的人,恐怕是大多数。”不少人会这么认为吧。

于是《雪崩》描述的未来,也许真的会这么自然而然的发生。

不管你喜不喜欢,该来的总会来。

这样的未来里,如果真的有“必须移动肉身”的娱乐,也许就剩下能够满足探索欲的旅行了。

再如果虚拟现实技术继续发展下去,迟早会发生这样的情况之一或更多:

  1. 肉身旅行给人带来的视听享受远远比不过虚拟世界的娱乐。
  2. 肉身旅行的成本过高,人们最终选择虚拟世界的娱乐。
  3. 肉身旅行的风险过高,人们最终选择虚拟世界的娱乐。

上面三种情况,除了第一种是不好不坏的情况,第二种和第三种,仔细想想,恐怕是比较可怕的未来吧。

不要恐慌!

Don’t Panic!

爹味说教开启:

  1. 悲观很有必要,悲观能让我们看到危险,从而回避。
  2. 技术只是工具,工具没有善恶,善恶取决于使用工具的人。
  3. 技术总是要进步的,如果因为预见了可怕的未来就选择回避,只会把这个技术让给你讨厌的人!

掌握这个工具,用你的理想去使用,有什么错呢?

4. 去中心化的元宇宙

人生三问里,我是谁?我从哪里来?我到哪里去?

不谈哲学,只说江湖规矩的话,英雄不问出处,最重要的还是我要到哪里去吧。

那么元宇宙三问呢?未来是什么样,才是最重要的。

所以,有没有一种避免科幻小说中的可怕未来的元宇宙呢?

社会学,人类学,心理学我通通不懂。

只谈自己熟悉的领域,我认为区块链作为底层技术的元宇宙是一个可以避免可怕未来的选项。

区块链的特性以及它们能带来的好处前面已经提过。

这里我想,像是写超短篇科幻小说一样描述这样的可能性供人参考:

设定:2035年,正如科学家已经发现了多元宇宙(Multiverse),开启了新宇宙大探索时代一样,一群吃饱了没事儿干的程序员也有样学样的搞了个多元元宇宙(Multi-metaverse)。

新闻:昨晚一个名为黑洞的黑客组织,在某元宇宙A中制造了一次黑洞攻击,该元宇宙中大量行星被直接吞噬,好在该元宇宙的双星伴随系统及时启动反制机制将黑洞攻击效果隔离在了伴星系统中并做了降维处理。其他的元宇宙及时作出反应,判断出这是一次黑客攻击,接受了这次降维处理,因此元宇宙A中的用户资产得到了多元元宇宙的继续认同和保护。

场景:一个背影,坐在美丽而平静的湖边,似乎在思考着。镜头逐渐拉近,头上的脑机设备闪硕,脖子上有一个黑洞的纹身。镜头转向侧面,嘴唇蠕动,听见轻声的自言自语:“超新星爆炸?也许是个好主意。”

Nginx and Certbot to build a server to support multiple web sites

Install and config nginx first.

I followed these two instructions:

Remember to config “sites-available” seperately, try not to config the global config file, for two reasons:

  1. It’ll be easier to maintain.
  2. Certbot is not that clever, so we want to leave the global config file to Certbot.

Read Certbot manual first then follow quick instructions from Certbot homepage

Follow the official instructions to install Certbot correctly.

Then we need to choose a command to call a plugin to get CA.
After I finished reading, I found out many unofficial instructions online are outdated.

If we install Certbot correctly, we only need to use command:

1
certbot --nginx

Then Certbot can do all for you. Even can create a cron job to renew certificate automatically.